diff --git a/src/dll/dirbuf.c b/src/dll/dirbuf.c index cca13d67..d2605578 100644 --- a/src/dll/dirbuf.c +++ b/src/dll/dirbuf.c @@ -335,6 +335,18 @@ FSP_API VOID FspFileSystemReleaseDirectoryBuffer(PVOID *PDirBuffer) FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer; + /* eliminate invalidated entries from the index */ + PULONG Index = (PULONG)(DirBuffer->Buffer + DirBuffer->HiMark); + ULONG Count = (DirBuffer->Capacity - DirBuffer->HiMark) / sizeof(ULONG); + ULONG I, J; + for (I = Count - 1, J = Count; I < Count; I--) + { + if (FspFileSystemDirectoryBufferEntryInvalid == Index[I]) + continue; + Index[--J] = Index[I]; + } + DirBuffer->HiMark = (ULONG)((PUINT8)&Index[J] - DirBuffer->Buffer); + FspFileSystemSortDirectoryBuffer(DirBuffer); ReleaseSRWLockExclusive(&DirBuffer->Lock); diff --git a/src/dll/fuse/fuse_intf.c b/src/dll/fuse/fuse_intf.c index ae79d737..bc0fea5a 100644 --- a/src/dll/fuse/fuse_intf.c +++ b/src/dll/fuse/fuse_intf.c @@ -1866,7 +1866,8 @@ static NTSTATUS fsp_fuse_intf_FixDirInfo(FSP_FILE_SYSTEM *FileSystem, Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, 0, &Uid, &Gid, &Mode, &DirInfo->FileInfo); if (!NT_SUCCESS(Result)) - goto exit; + /* mark the directory buffer entry as invalid */ + *Index = FspFileSystemDirectoryBufferEntryInvalid; if (0 != PosixPathEnd) *PosixPathEnd = SavedPathChar; diff --git a/src/dll/library.h b/src/dll/library.h index d8582f8e..b90c8528 100644 --- a/src/dll/library.h +++ b/src/dll/library.h @@ -66,6 +66,7 @@ PSID FspWksidGet(WELL_KNOWN_SID_TYPE WellKnownSidType); PWSTR FspDiagIdent(VOID); +#define FspFileSystemDirectoryBufferEntryInvalid ((ULONG)-1) VOID FspFileSystemPeekInDirectoryBuffer(PVOID *PDirBuffer, PUINT8 *PBuffer, PULONG *PIndex, PULONG PCount); diff --git a/tst/winfsp-tests/dirbuf-test.c b/tst/winfsp-tests/dirbuf-test.c index e965a2e1..7ef05c12 100644 --- a/tst/winfsp-tests/dirbuf-test.c +++ b/tst/winfsp-tests/dirbuf-test.c @@ -145,7 +145,7 @@ static void dirbuf_dots_test(void) FspFileSystemDeleteDirectoryBuffer(&DirBuffer); } -static void dirbuf_fill_dotest(unsigned seed, ULONG Count) +static void dirbuf_fill_dotest(unsigned seed, ULONG Count, ULONG InvalidCount) { PVOID DirBuffer = 0; NTSTATUS Result; @@ -202,6 +202,51 @@ static void dirbuf_fill_dotest(unsigned seed, ULONG Count) ASSERT(STATUS_SUCCESS == Result); } +#if 1 + { + ASSERT(Count > InvalidCount); + +#if !defined(FspFileSystemDirectoryBufferEntryInvalid) + const ULONG FspFileSystemDirectoryBufferEntryInvalid = ((ULONG)-1); +#endif + typedef struct + { + SRWLOCK Lock; + ULONG Capacity, LoMark, HiMark; + PUINT8 Buffer; + } FSP_FILE_SYSTEM_DIRECTORY_BUFFER; + FSP_FILE_SYSTEM_DIRECTORY_BUFFER *PeekDirBuffer = DirBuffer; + PUINT8 PeekBuffer = PeekDirBuffer->Buffer; + PULONG PeekIndex = (PULONG)(PeekDirBuffer->Buffer + PeekDirBuffer->HiMark); + ULONG PeekCount = (PeekDirBuffer->Capacity - PeekDirBuffer->HiMark) / sizeof(ULONG); + + ASSERT(Count == PeekCount); + + for (ULONG I = 0; InvalidCount > I; I++) + { + for (;;) + { + N = rand() % PeekCount; + if (FspFileSystemDirectoryBufferEntryInvalid == PeekIndex[N]) + continue; + + DirInfo = (PVOID)(PeekBuffer + PeekIndex[N]); + memcpy(CurrFileName, DirInfo->FileNameBuf, DirInfo->Size - sizeof *DirInfo); + CurrFileName[(DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR)] = L'\0'; + + /* do not invalidate dot entries as they are used in testing below */ + if (0 == wcscmp(CurrFileName, L".") || 0 == wcscmp(CurrFileName, L"..")) + continue; + + PeekIndex[N] = FspFileSystemDirectoryBufferEntryInvalid; + break; + } + } + + Count -= InvalidCount; + } +#endif + FspFileSystemReleaseDirectoryBuffer(&DirBuffer); MarkerIndex = rand() % Count; @@ -303,19 +348,32 @@ static void dirbuf_fill_test(void) { unsigned seed = (unsigned)time(0); - dirbuf_fill_dotest(1485473509, 10); + dirbuf_fill_dotest(1485473509, 10, 0); + dirbuf_fill_dotest(1485473509, 10, 3); for (ULONG I = 0; 10000 > I; I++) - dirbuf_fill_dotest(seed + I, 10); + { + dirbuf_fill_dotest(seed + I, 10, 0); + dirbuf_fill_dotest(seed + I, 10, 3); + } for (ULONG I = 0; 1000 > I; I++) - dirbuf_fill_dotest(seed + I, 100); + { + dirbuf_fill_dotest(seed + I, 100, 0); + dirbuf_fill_dotest(seed + I, 100, 30); + } for (ULONG I = 0; 100 > I; I++) - dirbuf_fill_dotest(seed + I, 1000); + { + dirbuf_fill_dotest(seed + I, 1000, 0); + dirbuf_fill_dotest(seed + I, 1000, 300); + } for (ULONG I = 0; 10 > I; I++) - dirbuf_fill_dotest(seed + I, 10000); + { + dirbuf_fill_dotest(seed + I, 10000, 0); + dirbuf_fill_dotest(seed + I, 10000, 3000); + } } void dirbuf_tests(void)