mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 16:33:02 -05:00
dll: FspFileSystem*DirectoryBuffer API's
This commit is contained in:
parent
4fe72ab332
commit
55a7864173
@ -182,6 +182,7 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\tst\memfs\memfs.cpp" />
|
<ClCompile Include="..\..\..\tst\memfs\memfs.cpp" />
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\create-test.c" />
|
<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\dirctl-test.c" />
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\eventlog-test.c" />
|
<ClCompile Include="..\..\..\tst\winfsp-tests\eventlog-test.c" />
|
||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\flush-test.c" />
|
<ClCompile Include="..\..\..\tst\winfsp-tests\flush-test.c" />
|
||||||
|
@ -76,6 +76,9 @@
|
|||||||
<ClCompile Include="..\..\..\tst\winfsp-tests\oplock-test.c">
|
<ClCompile Include="..\..\..\tst\winfsp-tests\oplock-test.c">
|
||||||
<Filter>Source</Filter>
|
<Filter>Source</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\tst\winfsp-tests\dirbuf-test.c">
|
||||||
|
<Filter>Source</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">
|
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
<ClInclude Include="..\..\src\shared\minimal.h" />
|
<ClInclude Include="..\..\src\shared\minimal.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\..\src\dll\dirbuf.c" />
|
||||||
<ClCompile Include="..\..\src\dll\eventlog.c" />
|
<ClCompile Include="..\..\src\dll\eventlog.c" />
|
||||||
<ClCompile Include="..\..\src\dll\fuse\fuse.c" />
|
<ClCompile Include="..\..\src\dll\fuse\fuse.c" />
|
||||||
<ClCompile Include="..\..\src\dll\fuse\fuse_intf.c" />
|
<ClCompile Include="..\..\src\dll\fuse\fuse_intf.c" />
|
||||||
|
@ -103,6 +103,9 @@
|
|||||||
<ClCompile Include="..\..\src\dll\fuse\fuse_intf.c">
|
<ClCompile Include="..\..\src\dll\fuse\fuse_intf.c">
|
||||||
<Filter>Source\fuse</Filter>
|
<Filter>Source\fuse</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\dll\dirbuf.c">
|
||||||
|
<Filter>Source</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\..\src\dll\library.def">
|
<None Include="..\..\src\dll\library.def">
|
||||||
|
@ -1293,6 +1293,19 @@ FSP_API NTSTATUS FspFileSystemCanReplaceReparsePoint(
|
|||||||
FSP_API BOOLEAN FspFileSystemAddStreamInfo(FSP_FSCTL_STREAM_INFO *StreamInfo,
|
FSP_API BOOLEAN FspFileSystemAddStreamInfo(FSP_FSCTL_STREAM_INFO *StreamInfo,
|
||||||
PVOID Buffer, ULONG Length, PULONG PBytesTransferred);
|
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
|
* 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);
|
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)
|
static inline void MemFree(void *Pointer)
|
||||||
{
|
{
|
||||||
if (0 != 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(posix_tests);
|
||||||
TESTSUITE(eventlog_tests);
|
TESTSUITE(eventlog_tests);
|
||||||
TESTSUITE(path_tests);
|
TESTSUITE(path_tests);
|
||||||
|
TESTSUITE(dirbuf_tests);
|
||||||
TESTSUITE(mount_tests);
|
TESTSUITE(mount_tests);
|
||||||
TESTSUITE(timeout_tests);
|
TESTSUITE(timeout_tests);
|
||||||
TESTSUITE(memfs_tests);
|
TESTSUITE(memfs_tests);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user