mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 08:23:05 -05:00
dll: FspFileSystem*DirectoryBuffer API's
This commit is contained in:
parent
4fe72ab332
commit
55a7864173
@ -182,6 +182,7 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\tst\memfs\memfs.cpp" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\create-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\dirbuf-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\dirctl-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\eventlog-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\flush-test.c" />
|
||||
|
@ -76,6 +76,9 @@
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\oplock-test.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\dirbuf-test.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">
|
||||
|
@ -31,6 +31,7 @@
|
||||
<ClInclude Include="..\..\src\shared\minimal.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\dll\dirbuf.c" />
|
||||
<ClCompile Include="..\..\src\dll\eventlog.c" />
|
||||
<ClCompile Include="..\..\src\dll\fuse\fuse.c" />
|
||||
<ClCompile Include="..\..\src\dll\fuse\fuse_intf.c" />
|
||||
|
@ -103,6 +103,9 @@
|
||||
<ClCompile Include="..\..\src\dll\fuse\fuse_intf.c">
|
||||
<Filter>Source\fuse</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\dll\dirbuf.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\src\dll\library.def">
|
||||
|
@ -1293,6 +1293,19 @@ FSP_API NTSTATUS FspFileSystemCanReplaceReparsePoint(
|
||||
FSP_API BOOLEAN FspFileSystemAddStreamInfo(FSP_FSCTL_STREAM_INFO *StreamInfo,
|
||||
PVOID Buffer, ULONG Length, PULONG PBytesTransferred);
|
||||
|
||||
/*
|
||||
* Directory buffering
|
||||
*/
|
||||
FSP_API BOOLEAN FspFileSystemAcquireDirectoryBuffer(PVOID *PDirBuffer,
|
||||
BOOLEAN Reset, PNTSTATUS PResult);
|
||||
FSP_API BOOLEAN FspFileSystemFillDirectoryBuffer(PVOID *PDirBuffer,
|
||||
FSP_FSCTL_DIR_INFO *DirInfo, PNTSTATUS PResult);
|
||||
FSP_API VOID FspFileSystemReleaseDirectoryBuffer(PVOID *PDirBuffer);
|
||||
FSP_API VOID FspFileSystemReadDirectoryBuffer(PVOID *PDirBuffer,
|
||||
PWSTR Marker,
|
||||
PVOID Buffer, ULONG Length, PULONG PBytesTransferred);
|
||||
FSP_API VOID FspFileSystemDeleteDirectoryBuffer(PVOID *PDirBuffer);
|
||||
|
||||
/*
|
||||
* Security
|
||||
*/
|
||||
|
392
src/dll/dirbuf.c
Normal file
392
src/dll/dirbuf.c
Normal file
@ -0,0 +1,392 @@
|
||||
/**
|
||||
* @file dll/dirbuf.c
|
||||
*
|
||||
* @copyright 2015-2017 Bill Zissimopoulos
|
||||
*/
|
||||
/*
|
||||
* This file is part of WinFsp.
|
||||
*
|
||||
* You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License version 3 as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Licensees holding a valid commercial license may use this file in
|
||||
* accordance with the commercial license agreement provided with the
|
||||
* software.
|
||||
*/
|
||||
|
||||
#include <dll/library.h>
|
||||
|
||||
#define RETURN(R, B) \
|
||||
do \
|
||||
{ \
|
||||
if (0 != PResult) \
|
||||
*PResult = R; \
|
||||
return B; \
|
||||
} while (0,0)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SRWLOCK Lock;
|
||||
ULONG Capacity, LoMark, HiMark;
|
||||
PUINT8 Buffer;
|
||||
} FSP_FILE_SYSTEM_DIRECTORY_BUFFER;
|
||||
|
||||
static int FspFileSystemDirectoryBufferFileNameCmp(PWSTR a, int alen, PWSTR b, int blen)
|
||||
{
|
||||
int len, res;
|
||||
|
||||
if (-1 == alen)
|
||||
alen = (int)lstrlenW(a);
|
||||
if (-1 == blen)
|
||||
blen = (int)lstrlenW(b);
|
||||
|
||||
len = alen < blen ? alen : blen;
|
||||
|
||||
/* order "." and ".." first */
|
||||
switch (alen)
|
||||
{
|
||||
case 1:
|
||||
if (L'.' == a[0])
|
||||
a = L"\1";
|
||||
break;
|
||||
case 2:
|
||||
if (L'.' == a[0] && L'.' == a[1])
|
||||
a = L"\1\1";
|
||||
break;
|
||||
}
|
||||
|
||||
/* order "." and ".." first */
|
||||
switch (blen)
|
||||
{
|
||||
case 1:
|
||||
if (L'.' == b[0])
|
||||
b = L"\1";
|
||||
break;
|
||||
case 2:
|
||||
if (L'.' == b[0] && L'.' == b[1])
|
||||
b = L"\1\1";
|
||||
break;
|
||||
}
|
||||
|
||||
res = invariant_wcsncmp(a, b, len);
|
||||
|
||||
if (0 == res)
|
||||
res = alen - blen;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Binary search
|
||||
* "I wish I had the standard library!"
|
||||
*/
|
||||
static BOOLEAN FspFileSystemSearchDirectoryBuffer(FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer,
|
||||
PWSTR Marker, int MarkerLen, PULONG PIndexNum)
|
||||
{
|
||||
PULONG Index = (PULONG)(DirBuffer->Buffer + DirBuffer->HiMark);
|
||||
ULONG Count = (DirBuffer->Capacity - DirBuffer->HiMark) / sizeof(ULONG);
|
||||
FSP_FSCTL_DIR_INFO *DirInfo;
|
||||
int Lo = 0, Hi = Count - 1, Mi;
|
||||
int CmpResult;
|
||||
|
||||
while (Lo <= Hi)
|
||||
{
|
||||
Mi = (unsigned)(Lo + Hi) >> 1;
|
||||
|
||||
DirInfo = (PVOID)(DirBuffer->Buffer + Index[Mi]);
|
||||
CmpResult = FspFileSystemDirectoryBufferFileNameCmp(
|
||||
DirInfo->FileNameBuf, (DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR),
|
||||
Marker, MarkerLen);
|
||||
|
||||
if (0 > CmpResult)
|
||||
Lo = Mi + 1;
|
||||
else if (0 < CmpResult)
|
||||
Hi = Mi - 1;
|
||||
else
|
||||
{
|
||||
*PIndexNum = Mi;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
*PIndexNum = Lo;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Quick sort
|
||||
* "I wish I had the standard library!"
|
||||
*
|
||||
* Based on Sedgewick's Algorithms in C++; multiple editions.
|
||||
*
|
||||
* Implements a non-recursive quicksort with tail-end recursion eliminated
|
||||
* and median-of-three partitioning.
|
||||
*/
|
||||
|
||||
#define less(a, b) FspFileSystemDirectoryBufferLess(Buffer, a, b)
|
||||
#define exch(a, b) { ULONG t = a; a = b; b = t; }
|
||||
#define compexch(a, b) if (less(b, a)) exch(a, b)
|
||||
#define push(i) (stack[stackpos++] = (i))
|
||||
#define pop() (stack[--stackpos])
|
||||
|
||||
static __forceinline
|
||||
int FspFileSystemDirectoryBufferLess(PUINT8 Buffer, int a, int b)
|
||||
{
|
||||
FSP_FSCTL_DIR_INFO *DirInfoA = (FSP_FSCTL_DIR_INFO *)(Buffer + a);
|
||||
FSP_FSCTL_DIR_INFO *DirInfoB = (FSP_FSCTL_DIR_INFO *)(Buffer + b);
|
||||
return 0 > FspFileSystemDirectoryBufferFileNameCmp(
|
||||
DirInfoA->FileNameBuf, (DirInfoA->Size - sizeof *DirInfoA) / sizeof(WCHAR),
|
||||
DirInfoB->FileNameBuf, (DirInfoB->Size - sizeof *DirInfoB) / sizeof(WCHAR));
|
||||
}
|
||||
|
||||
static __forceinline
|
||||
int FspFileSystemPartitionDirectoryBuffer(PUINT8 Buffer, PULONG Index, int l, int r)
|
||||
{
|
||||
int i = l - 1, j = r;
|
||||
ULONG v = Index[r];
|
||||
|
||||
for (;;)
|
||||
{
|
||||
while (less(Index[++i], v))
|
||||
;
|
||||
|
||||
while (less(v, Index[--j]))
|
||||
if (j == l)
|
||||
break;
|
||||
|
||||
if (i >= j)
|
||||
break;
|
||||
|
||||
exch(Index[i], Index[j]);
|
||||
}
|
||||
|
||||
exch(Index[i], Index[r]);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static VOID FspFileSystemQSortDirectoryBuffer(PUINT8 Buffer, PULONG Index, int l, int r)
|
||||
{
|
||||
int stack[64], stackpos = 0;
|
||||
int i;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
while (r > l)
|
||||
{
|
||||
#if 0
|
||||
exch(Index[(l + r) / 2], Index[r - 1]);
|
||||
compexch(Index[l], Index[r - 1]);
|
||||
compexch(Index[l], Index[r]);
|
||||
compexch(Index[r - 1], Index[r]);
|
||||
|
||||
i = FspFileSystemPartitionDirectoryBuffer(Buffer, Index, l + 1, r - 1);
|
||||
#else
|
||||
i = FspFileSystemPartitionDirectoryBuffer(Buffer, Index, l, r);
|
||||
#endif
|
||||
|
||||
if (i - l > r - i)
|
||||
{
|
||||
push(l); push(i - 1);
|
||||
l = i + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
push(i + 1); push(r);
|
||||
r = i - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == stackpos)
|
||||
break;
|
||||
|
||||
r = pop(); l = pop();
|
||||
}
|
||||
}
|
||||
|
||||
#undef push
|
||||
#undef pop
|
||||
#undef less
|
||||
#undef compexch
|
||||
#undef exch
|
||||
|
||||
static inline VOID FspFileSystemSortDirectoryBuffer(FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer)
|
||||
{
|
||||
PUINT8 Buffer = DirBuffer->Buffer;
|
||||
PULONG Index = (PULONG)(DirBuffer->Buffer + DirBuffer->HiMark);
|
||||
ULONG Count = (DirBuffer->Capacity - DirBuffer->HiMark) / sizeof(ULONG);
|
||||
|
||||
FspFileSystemQSortDirectoryBuffer(Buffer, Index, 0, Count - 1);
|
||||
}
|
||||
|
||||
FSP_API BOOLEAN FspFileSystemAcquireDirectoryBuffer(PVOID *PDirBuffer,
|
||||
BOOLEAN Reset, PNTSTATUS PResult)
|
||||
{
|
||||
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
|
||||
MemoryBarrier();
|
||||
|
||||
if (0 == DirBuffer)
|
||||
{
|
||||
static SRWLOCK CreateLock = SRWLOCK_INIT;
|
||||
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *NewDirBuffer;
|
||||
|
||||
NewDirBuffer = MemAlloc(sizeof *NewDirBuffer);
|
||||
if (0 == NewDirBuffer)
|
||||
RETURN(STATUS_INSUFFICIENT_RESOURCES, FALSE);
|
||||
memset(NewDirBuffer, 0, sizeof *NewDirBuffer);
|
||||
InitializeSRWLock(&NewDirBuffer->Lock);
|
||||
AcquireSRWLockExclusive(&NewDirBuffer->Lock);
|
||||
|
||||
AcquireSRWLockExclusive(&CreateLock);
|
||||
DirBuffer = *PDirBuffer;
|
||||
MemoryBarrier();
|
||||
if (0 == DirBuffer)
|
||||
*PDirBuffer = DirBuffer = NewDirBuffer;
|
||||
ReleaseSRWLockExclusive(&CreateLock);
|
||||
|
||||
if (DirBuffer == NewDirBuffer)
|
||||
RETURN(STATUS_SUCCESS, TRUE);
|
||||
|
||||
ReleaseSRWLockExclusive(&NewDirBuffer->Lock);
|
||||
MemFree(NewDirBuffer);
|
||||
}
|
||||
|
||||
if (Reset)
|
||||
{
|
||||
AcquireSRWLockExclusive(&DirBuffer->Lock);
|
||||
|
||||
DirBuffer->LoMark = 0;
|
||||
DirBuffer->HiMark = DirBuffer->Capacity;
|
||||
|
||||
RETURN(STATUS_SUCCESS, TRUE);
|
||||
}
|
||||
|
||||
RETURN(STATUS_SUCCESS, FALSE);
|
||||
}
|
||||
|
||||
FSP_API BOOLEAN FspFileSystemFillDirectoryBuffer(PVOID *PDirBuffer,
|
||||
FSP_FSCTL_DIR_INFO *DirInfo, PNTSTATUS PResult)
|
||||
{
|
||||
/* assume that FspFileSystemAcquireDirectoryBuffer has been called */
|
||||
|
||||
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
|
||||
ULONG Capacity, LoMark, HiMark;
|
||||
PUINT8 Buffer;
|
||||
|
||||
if (0 == DirInfo)
|
||||
RETURN(STATUS_INVALID_PARAMETER, FALSE);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
LoMark = DirBuffer->LoMark;
|
||||
HiMark = DirBuffer->HiMark;
|
||||
Buffer = DirBuffer->Buffer;
|
||||
|
||||
if (FspFileSystemAddDirInfo(DirInfo,
|
||||
Buffer,
|
||||
HiMark > sizeof(ULONG) ? HiMark - sizeof(ULONG)/*space for new index entry*/ : HiMark,
|
||||
&LoMark))
|
||||
{
|
||||
HiMark -= sizeof(ULONG);
|
||||
*(PULONG)(Buffer + HiMark) = DirBuffer->LoMark;
|
||||
|
||||
DirBuffer->LoMark = LoMark;
|
||||
DirBuffer->HiMark = HiMark;
|
||||
|
||||
RETURN (STATUS_SUCCESS, TRUE);
|
||||
}
|
||||
|
||||
if (0 == Buffer)
|
||||
{
|
||||
Buffer = MemAlloc(Capacity = 512);
|
||||
if (0 == Buffer)
|
||||
RETURN(STATUS_INSUFFICIENT_RESOURCES, FALSE);
|
||||
|
||||
HiMark = Capacity;
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer = MemRealloc(Buffer, Capacity = DirBuffer->Capacity * 2);
|
||||
if (0 == Buffer)
|
||||
RETURN(STATUS_INSUFFICIENT_RESOURCES, FALSE);
|
||||
|
||||
ULONG IndexSize = DirBuffer->Capacity - HiMark;
|
||||
ULONG NewHiMark = Capacity - IndexSize;
|
||||
|
||||
memmove(Buffer + NewHiMark, Buffer + HiMark, IndexSize);
|
||||
HiMark = NewHiMark;
|
||||
}
|
||||
|
||||
DirBuffer->Capacity = Capacity;
|
||||
DirBuffer->LoMark = LoMark;
|
||||
DirBuffer->HiMark = HiMark;
|
||||
DirBuffer->Buffer = Buffer;
|
||||
}
|
||||
}
|
||||
|
||||
FSP_API VOID FspFileSystemReleaseDirectoryBuffer(PVOID *PDirBuffer)
|
||||
{
|
||||
/* assume that FspFileSystemAcquireDirectoryBuffer has been called */
|
||||
|
||||
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
|
||||
|
||||
FspFileSystemSortDirectoryBuffer(DirBuffer);
|
||||
|
||||
ReleaseSRWLockExclusive(&DirBuffer->Lock);
|
||||
}
|
||||
|
||||
FSP_API VOID FspFileSystemReadDirectoryBuffer(PVOID *PDirBuffer,
|
||||
PWSTR Marker,
|
||||
PVOID Buffer, ULONG Length, PULONG PBytesTransferred)
|
||||
{
|
||||
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
|
||||
MemoryBarrier();
|
||||
|
||||
if (0 != DirBuffer)
|
||||
{
|
||||
AcquireSRWLockShared(&DirBuffer->Lock);
|
||||
|
||||
PULONG Index = (PULONG)(DirBuffer->Buffer + DirBuffer->HiMark);
|
||||
ULONG Count = (DirBuffer->Capacity - DirBuffer->HiMark) / sizeof(ULONG);
|
||||
ULONG IndexNum;
|
||||
FSP_FSCTL_DIR_INFO *DirInfo;
|
||||
|
||||
if (0 == Marker)
|
||||
IndexNum = 0;
|
||||
else
|
||||
{
|
||||
FspFileSystemSearchDirectoryBuffer(DirBuffer,
|
||||
Marker, lstrlenW(Marker),
|
||||
&IndexNum);
|
||||
IndexNum++;
|
||||
}
|
||||
|
||||
for (; IndexNum < Count; IndexNum++)
|
||||
{
|
||||
DirInfo = (PVOID)(DirBuffer->Buffer + Index[IndexNum]);
|
||||
if (!FspFileSystemAddDirInfo(DirInfo, Buffer, Length, PBytesTransferred))
|
||||
{
|
||||
ReleaseSRWLockShared(&DirBuffer->Lock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseSRWLockShared(&DirBuffer->Lock);
|
||||
}
|
||||
|
||||
FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred);
|
||||
}
|
||||
|
||||
FSP_API VOID FspFileSystemDeleteDirectoryBuffer(PVOID *PDirBuffer)
|
||||
{
|
||||
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
|
||||
MemoryBarrier();
|
||||
|
||||
if (0 != DirBuffer)
|
||||
{
|
||||
MemFree(DirBuffer->Buffer);
|
||||
MemFree(DirBuffer);
|
||||
*PDirBuffer = 0;
|
||||
}
|
||||
}
|
@ -126,6 +126,10 @@ static inline void *MemAlloc(size_t Size)
|
||||
{
|
||||
return HeapAlloc(GetProcessHeap(), 0, Size);
|
||||
}
|
||||
static inline void *MemRealloc(void *Pointer, size_t Size)
|
||||
{
|
||||
return HeapReAlloc(GetProcessHeap(), 0, Pointer, Size);
|
||||
}
|
||||
static inline void MemFree(void *Pointer)
|
||||
{
|
||||
if (0 != Pointer)
|
||||
|
322
tst/winfsp-tests/dirbuf-test.c
Normal file
322
tst/winfsp-tests/dirbuf-test.c
Normal file
@ -0,0 +1,322 @@
|
||||
/**
|
||||
* @file dirbuf-test.c
|
||||
*
|
||||
* @copyright 2015-2017 Bill Zissimopoulos
|
||||
*/
|
||||
/*
|
||||
* This file is part of WinFsp.
|
||||
*
|
||||
* You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License version 3 as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Licensees holding a valid commercial license may use this file in
|
||||
* accordance with the commercial license agreement provided with the
|
||||
* software.
|
||||
*/
|
||||
|
||||
#include <winfsp/winfsp.h>
|
||||
#include <tlib/testsuite.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "winfsp-tests.h"
|
||||
|
||||
static void dirbuf_empty_test(void)
|
||||
{
|
||||
PVOID DirBuffer = 0;
|
||||
NTSTATUS Result;
|
||||
BOOLEAN Success;
|
||||
UINT8 Buffer[64];
|
||||
ULONG BytesTransferred;
|
||||
|
||||
BytesTransferred = 0;
|
||||
FspFileSystemReadDirectoryBuffer(&DirBuffer, 0, Buffer, sizeof Buffer, &BytesTransferred);
|
||||
ASSERT(sizeof(UINT16) == BytesTransferred);
|
||||
|
||||
Result = STATUS_UNSUCCESSFUL;
|
||||
Success = FspFileSystemAcquireDirectoryBuffer(&DirBuffer, FALSE, &Result);
|
||||
ASSERT(Success);
|
||||
ASSERT(STATUS_SUCCESS == Result);
|
||||
|
||||
FspFileSystemReleaseDirectoryBuffer(&DirBuffer);
|
||||
|
||||
BytesTransferred = 0;
|
||||
FspFileSystemReadDirectoryBuffer(&DirBuffer, 0, Buffer, sizeof Buffer, &BytesTransferred);
|
||||
ASSERT(sizeof(UINT16) == BytesTransferred);
|
||||
|
||||
Result = STATUS_UNSUCCESSFUL;
|
||||
Success = FspFileSystemAcquireDirectoryBuffer(&DirBuffer, FALSE, &Result);
|
||||
ASSERT(!Success);
|
||||
ASSERT(STATUS_SUCCESS == Result);
|
||||
|
||||
BytesTransferred = 0;
|
||||
FspFileSystemReadDirectoryBuffer(&DirBuffer, 0, Buffer, sizeof Buffer, &BytesTransferred);
|
||||
ASSERT(sizeof(UINT16) == BytesTransferred);
|
||||
|
||||
Result = STATUS_UNSUCCESSFUL;
|
||||
Success = FspFileSystemAcquireDirectoryBuffer(&DirBuffer, TRUE, &Result);
|
||||
ASSERT(Success);
|
||||
ASSERT(STATUS_SUCCESS == Result);
|
||||
|
||||
FspFileSystemReleaseDirectoryBuffer(&DirBuffer);
|
||||
|
||||
BytesTransferred = 0;
|
||||
FspFileSystemReadDirectoryBuffer(&DirBuffer, 0, Buffer, sizeof Buffer, &BytesTransferred);
|
||||
ASSERT(sizeof(UINT16) == BytesTransferred);
|
||||
|
||||
FspFileSystemDeleteDirectoryBuffer(&DirBuffer);
|
||||
FspFileSystemDeleteDirectoryBuffer(&DirBuffer);
|
||||
}
|
||||
|
||||
static void dirbuf_dots_test(void)
|
||||
{
|
||||
PVOID DirBuffer = 0;
|
||||
NTSTATUS Result;
|
||||
BOOLEAN Success;
|
||||
union
|
||||
{
|
||||
UINT8 B[sizeof(FSP_FSCTL_DIR_INFO) + MAX_PATH * sizeof(WCHAR)];
|
||||
FSP_FSCTL_DIR_INFO D;
|
||||
} DirInfoBuf;
|
||||
FSP_FSCTL_DIR_INFO *DirInfo = &DirInfoBuf.D, *DirInfoEnd;
|
||||
UINT8 Buffer[1024];
|
||||
ULONG Length, BytesTransferred;
|
||||
WCHAR CurrFileName[MAX_PATH];
|
||||
ULONG N;
|
||||
|
||||
Length = sizeof Buffer;
|
||||
|
||||
Result = STATUS_UNSUCCESSFUL;
|
||||
Success = FspFileSystemAcquireDirectoryBuffer(&DirBuffer, FALSE, &Result);
|
||||
ASSERT(Success);
|
||||
ASSERT(STATUS_SUCCESS == Result);
|
||||
|
||||
memset(&DirInfoBuf, 0, sizeof DirInfoBuf);
|
||||
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + 1 * sizeof(WCHAR));
|
||||
DirInfo->FileNameBuf[0] = L'.';
|
||||
Success = FspFileSystemFillDirectoryBuffer(&DirBuffer, DirInfo, &Result);
|
||||
ASSERT(Success);
|
||||
ASSERT(STATUS_SUCCESS == Result);
|
||||
|
||||
memset(&DirInfoBuf, 0, sizeof DirInfoBuf);
|
||||
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + 1 * sizeof(WCHAR));
|
||||
DirInfo->FileNameBuf[0] = L' ';
|
||||
Success = FspFileSystemFillDirectoryBuffer(&DirBuffer, DirInfo, &Result);
|
||||
ASSERT(Success);
|
||||
ASSERT(STATUS_SUCCESS == Result);
|
||||
|
||||
memset(&DirInfoBuf, 0, sizeof DirInfoBuf);
|
||||
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + 2 * sizeof(WCHAR));
|
||||
DirInfo->FileNameBuf[0] = L'.';
|
||||
DirInfo->FileNameBuf[1] = L'.';
|
||||
Success = FspFileSystemFillDirectoryBuffer(&DirBuffer, DirInfo, &Result);
|
||||
ASSERT(Success);
|
||||
ASSERT(STATUS_SUCCESS == Result);
|
||||
|
||||
FspFileSystemReleaseDirectoryBuffer(&DirBuffer);
|
||||
|
||||
BytesTransferred = 0;
|
||||
FspFileSystemReadDirectoryBuffer(&DirBuffer, 0, Buffer, Length, &BytesTransferred);
|
||||
|
||||
N = 0;
|
||||
for (
|
||||
DirInfo = (PVOID)Buffer, DirInfoEnd = (PVOID)(Buffer + BytesTransferred);
|
||||
DirInfoEnd > DirInfo && 0 != DirInfo->Size;
|
||||
DirInfo = (PVOID)((PUINT8)DirInfo + FSP_FSCTL_DEFAULT_ALIGN_UP(DirInfo->Size)), N++)
|
||||
{
|
||||
memcpy(CurrFileName, DirInfo->FileNameBuf, DirInfo->Size - sizeof *DirInfo);
|
||||
CurrFileName[(DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR)] = L'\0';
|
||||
|
||||
if (0 == N)
|
||||
ASSERT(0 == wcscmp(CurrFileName, L"."));
|
||||
else if (1 == N)
|
||||
ASSERT(0 == wcscmp(CurrFileName, L".."));
|
||||
else if (2 == N)
|
||||
ASSERT(0 == wcscmp(CurrFileName, L" "));
|
||||
}
|
||||
ASSERT(DirInfoEnd > DirInfo);
|
||||
ASSERT(0 == DirInfo->Size);
|
||||
ASSERT(N == 3);
|
||||
|
||||
FspFileSystemDeleteDirectoryBuffer(&DirBuffer);
|
||||
}
|
||||
|
||||
static void dirbuf_fill_dotest(unsigned seed, ULONG Count)
|
||||
{
|
||||
PVOID DirBuffer = 0;
|
||||
NTSTATUS Result;
|
||||
BOOLEAN Success;
|
||||
union
|
||||
{
|
||||
UINT8 B[sizeof(FSP_FSCTL_DIR_INFO) + MAX_PATH * sizeof(WCHAR)];
|
||||
FSP_FSCTL_DIR_INFO D;
|
||||
} DirInfoBuf;
|
||||
FSP_FSCTL_DIR_INFO *DirInfo = &DirInfoBuf.D, *DirInfoEnd;
|
||||
PUINT8 Buffer;
|
||||
ULONG Length, BytesTransferred;
|
||||
WCHAR CurrFileName[MAX_PATH], PrevFileName[MAX_PATH];
|
||||
ULONG DotIndex = Count / 3, DotDotIndex = Count / 3 * 2;
|
||||
WCHAR Marker[MAX_PATH];
|
||||
ULONG N, MarkerIndex, MarkerLength;
|
||||
|
||||
srand(seed);
|
||||
|
||||
Length = Count * FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof DirInfoBuf) + sizeof(UINT16);
|
||||
Buffer = malloc(Length);
|
||||
ASSERT(0 != Buffer);
|
||||
|
||||
Result = STATUS_UNSUCCESSFUL;
|
||||
Success = FspFileSystemAcquireDirectoryBuffer(&DirBuffer, FALSE, &Result);
|
||||
ASSERT(Success);
|
||||
ASSERT(STATUS_SUCCESS == Result);
|
||||
|
||||
for (ULONG I = 0; Count > I; I++)
|
||||
{
|
||||
memset(&DirInfoBuf, 0, sizeof DirInfoBuf);
|
||||
|
||||
if (I == DotIndex)
|
||||
{
|
||||
N = 1;
|
||||
DirInfo->FileNameBuf[0] = L'.';
|
||||
}
|
||||
else if (I == DotDotIndex)
|
||||
{
|
||||
N = 2;
|
||||
DirInfo->FileNameBuf[0] = L'.';
|
||||
DirInfo->FileNameBuf[1] = L'.';
|
||||
}
|
||||
else
|
||||
{
|
||||
N = 24 + rand() % (32 - 24);
|
||||
for (ULONG J = 0; N > J; J++)
|
||||
DirInfo->FileNameBuf[J] = 'A' + rand() % 26;
|
||||
}
|
||||
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + N * sizeof(WCHAR));
|
||||
|
||||
Success = FspFileSystemFillDirectoryBuffer(&DirBuffer, DirInfo, &Result);
|
||||
ASSERT(Success);
|
||||
ASSERT(STATUS_SUCCESS == Result);
|
||||
}
|
||||
|
||||
FspFileSystemReleaseDirectoryBuffer(&DirBuffer);
|
||||
|
||||
MarkerIndex = rand() % Count;
|
||||
|
||||
BytesTransferred = 0;
|
||||
FspFileSystemReadDirectoryBuffer(&DirBuffer, 0, Buffer, Length, &BytesTransferred);
|
||||
|
||||
N = 0;
|
||||
PrevFileName[0] = L'\0';
|
||||
for (
|
||||
DirInfo = (PVOID)Buffer, DirInfoEnd = (PVOID)(Buffer + BytesTransferred);
|
||||
DirInfoEnd > DirInfo && 0 != DirInfo->Size;
|
||||
DirInfo = (PVOID)((PUINT8)DirInfo + FSP_FSCTL_DEFAULT_ALIGN_UP(DirInfo->Size)), N++)
|
||||
{
|
||||
memcpy(CurrFileName, DirInfo->FileNameBuf, DirInfo->Size - sizeof *DirInfo);
|
||||
CurrFileName[(DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR)] = L'\0';
|
||||
|
||||
if (0 == N)
|
||||
ASSERT(0 == wcscmp(CurrFileName, L"."));
|
||||
else if (1 == N)
|
||||
ASSERT(0 == wcscmp(CurrFileName, L".."));
|
||||
else
|
||||
ASSERT(0 != wcscmp(CurrFileName, L".") && 0 != wcscmp(CurrFileName, L".."));
|
||||
|
||||
//ASSERT(wcscmp(PrevFileName, CurrFileName) <= 0);
|
||||
/* filenames are random enought that should not happen in practice */
|
||||
ASSERT(wcscmp(PrevFileName, CurrFileName) < 0);
|
||||
|
||||
memcpy(PrevFileName, CurrFileName, sizeof CurrFileName);
|
||||
|
||||
if (N == MarkerIndex)
|
||||
{
|
||||
memcpy(Marker, CurrFileName, sizeof CurrFileName);
|
||||
MarkerLength = (ULONG)((PUINT8)DirInfo + FSP_FSCTL_DEFAULT_ALIGN_UP(DirInfo->Size) - Buffer);
|
||||
}
|
||||
}
|
||||
ASSERT(DirInfoEnd > DirInfo);
|
||||
ASSERT(0 == DirInfo->Size);
|
||||
ASSERT(N == Count);
|
||||
|
||||
BytesTransferred = 0;
|
||||
FspFileSystemReadDirectoryBuffer(&DirBuffer, Marker, Buffer, Length, &BytesTransferred);
|
||||
|
||||
N = 0;
|
||||
PrevFileName[0] = L'\0';
|
||||
for (
|
||||
DirInfo = (PVOID)Buffer, DirInfoEnd = (PVOID)(Buffer + BytesTransferred);
|
||||
DirInfoEnd > DirInfo && 0 != DirInfo->Size;
|
||||
DirInfo = (PVOID)((PUINT8)DirInfo + FSP_FSCTL_DEFAULT_ALIGN_UP(DirInfo->Size)), N++)
|
||||
{
|
||||
memcpy(CurrFileName, DirInfo->FileNameBuf, DirInfo->Size - sizeof *DirInfo);
|
||||
CurrFileName[(DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR)] = L'\0';
|
||||
|
||||
ASSERT(0 != wcscmp(CurrFileName, Marker));
|
||||
|
||||
//ASSERT(wcscmp(PrevFileName, CurrFileName) <= 0);
|
||||
/* filenames are random enought that should not happen in practice */
|
||||
ASSERT(wcscmp(PrevFileName, CurrFileName) < 0);
|
||||
|
||||
memcpy(PrevFileName, CurrFileName, sizeof CurrFileName);
|
||||
}
|
||||
ASSERT(DirInfoEnd > DirInfo);
|
||||
ASSERT(0 == DirInfo->Size);
|
||||
ASSERT(N == Count - MarkerIndex - 1);
|
||||
|
||||
BytesTransferred = 0;
|
||||
FspFileSystemReadDirectoryBuffer(&DirBuffer, 0, Buffer, MarkerLength, &BytesTransferred);
|
||||
|
||||
N = 0;
|
||||
PrevFileName[0] = L'\0';
|
||||
for (
|
||||
DirInfo = (PVOID)Buffer, DirInfoEnd = (PVOID)(Buffer + BytesTransferred);
|
||||
DirInfoEnd > DirInfo && 0 != DirInfo->Size;
|
||||
DirInfo = (PVOID)((PUINT8)DirInfo + FSP_FSCTL_DEFAULT_ALIGN_UP(DirInfo->Size)), N++)
|
||||
{
|
||||
memcpy(CurrFileName, DirInfo->FileNameBuf, DirInfo->Size - sizeof *DirInfo);
|
||||
CurrFileName[(DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR)] = L'\0';
|
||||
|
||||
if (N == MarkerIndex)
|
||||
ASSERT(0 == wcscmp(CurrFileName, Marker));
|
||||
else
|
||||
ASSERT(0 != wcscmp(CurrFileName, Marker));
|
||||
|
||||
//ASSERT(wcscmp(PrevFileName, CurrFileName) <= 0);
|
||||
/* filenames are random enought that should not happen in practice */
|
||||
ASSERT(wcscmp(PrevFileName, CurrFileName) < 0);
|
||||
|
||||
memcpy(PrevFileName, CurrFileName, sizeof CurrFileName);
|
||||
}
|
||||
ASSERT(DirInfoEnd <= DirInfo);
|
||||
ASSERT(N == MarkerIndex + 1);
|
||||
|
||||
FspFileSystemDeleteDirectoryBuffer(&DirBuffer);
|
||||
|
||||
free(Buffer);
|
||||
}
|
||||
|
||||
static void dirbuf_fill_test(void)
|
||||
{
|
||||
unsigned seed = (unsigned)time(0);
|
||||
|
||||
dirbuf_fill_dotest(1485473509, 10);
|
||||
|
||||
for (ULONG I = 0; 10000 > I; I++)
|
||||
dirbuf_fill_dotest(seed + I, 10);
|
||||
|
||||
for (ULONG I = 0; 1000 > I; I++)
|
||||
dirbuf_fill_dotest(seed + I, 100);
|
||||
|
||||
for (ULONG I = 0; 100 > I; I++)
|
||||
dirbuf_fill_dotest(seed + I, 1000);
|
||||
|
||||
for (ULONG I = 0; 10 > I; I++)
|
||||
dirbuf_fill_dotest(seed + I, 10000);
|
||||
}
|
||||
|
||||
void dirbuf_tests(void)
|
||||
{
|
||||
TEST(dirbuf_empty_test);
|
||||
TEST(dirbuf_dots_test);
|
||||
TEST(dirbuf_fill_test);
|
||||
}
|
@ -182,6 +182,7 @@ int main(int argc, char *argv[])
|
||||
TESTSUITE(posix_tests);
|
||||
TESTSUITE(eventlog_tests);
|
||||
TESTSUITE(path_tests);
|
||||
TESTSUITE(dirbuf_tests);
|
||||
TESTSUITE(mount_tests);
|
||||
TESTSUITE(timeout_tests);
|
||||
TESTSUITE(memfs_tests);
|
||||
|
Loading…
x
Reference in New Issue
Block a user