From 8ce68366741f8812e5e5eabae2b8c42383f8c1fb Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Fri, 3 Dec 2021 14:47:19 +0000 Subject: [PATCH] dll: FspFileSystemSearchDirectoryBuffer: fix #351 --- src/dll/dirbuf.c | 2 +- tools/run-tests.bat | 4 ++ tst/winfsp-tests/dirbuf-test.c | 89 ++++++++++++++++++++++++++++++++++ tst/winfsp-tests/dirctl-test.c | 89 ++++++++++++++++++++++++++++++++++ tst/winfsp-tests/hooks.c | 6 +-- 5 files changed, 186 insertions(+), 4 deletions(-) diff --git a/src/dll/dirbuf.c b/src/dll/dirbuf.c index fa8bcb00..d1265bf1 100644 --- a/src/dll/dirbuf.c +++ b/src/dll/dirbuf.c @@ -114,7 +114,7 @@ static BOOLEAN FspFileSystemSearchDirectoryBuffer(FSP_FILE_SYSTEM_DIRECTORY_BUFF } } - *PIndexNum = Lo; + *PIndexNum = Hi; return FALSE; } diff --git a/tools/run-tests.bat b/tools/run-tests.bat index b4afe92f..31e83f67 100755 --- a/tools/run-tests.bat +++ b/tools/run-tests.bat @@ -889,6 +889,10 @@ if X%5==XNOEXCL ( -reparse* -stream* %~5 ) if !ERRORLEVEL! neq 0 set RunSampleTestExit=1 +"%ProjRoot%\build\VStudio\build\%Configuration%\%4.exe" ^ + --external --resilient --case-insensitive-cmp --share-prefix="\%1\%TMP::=$%\%1\test" ^ + +querydir_single_test +if !ERRORLEVEL! neq 0 set RunSampleTestExit=1 popd echo net use L: /delete net use L: /delete diff --git a/tst/winfsp-tests/dirbuf-test.c b/tst/winfsp-tests/dirbuf-test.c index 470afffb..3662801d 100644 --- a/tst/winfsp-tests/dirbuf-test.c +++ b/tst/winfsp-tests/dirbuf-test.c @@ -376,6 +376,94 @@ static void dirbuf_fill_test(void) } } +static void dirbuf_boundary_dotest(PWSTR Marker, ULONG ExpectI, ULONG ExpectN, ...) +{ + 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; + PWSTR Name; + va_list Names0, Names1; + + va_start(Names0, ExpectN); + va_copy(Names1, Names0); + + Length = sizeof Buffer; + + Result = STATUS_UNSUCCESSFUL; + Success = FspFileSystemAcquireDirectoryBuffer(&DirBuffer, FALSE, &Result); + ASSERT(Success); + ASSERT(STATUS_SUCCESS == Result); + + while (0 != (Name = va_arg(Names0, PWSTR))) + { + memset(&DirInfoBuf, 0, sizeof DirInfoBuf); + DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + wcslen(Name) * sizeof(WCHAR)); + wcscpy_s(DirInfo->FileNameBuf, MAX_PATH, Name); + Success = FspFileSystemFillDirectoryBuffer(&DirBuffer, DirInfo, &Result); + ASSERT(Success); + ASSERT(STATUS_SUCCESS == Result); + } + + FspFileSystemReleaseDirectoryBuffer(&DirBuffer); + + BytesTransferred = 0; + FspFileSystemReadDirectoryBuffer(&DirBuffer, Marker, Buffer, Length, &BytesTransferred); + + for (N = 0; ExpectI > N; N++) + va_arg(Names1, PWSTR); + + for (N = 0, + 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'; + + Name = va_arg(Names1, PWSTR); + ASSERT(0 == wcscmp(CurrFileName, Name)); + } + ASSERT(ExpectN == N); + + FspFileSystemDeleteDirectoryBuffer(&DirBuffer); + + va_end(Names1); + va_end(Names0); +} + +static void dirbuf_boundary_test(void) +{ + dirbuf_boundary_dotest(L"A", 0, 0, 0); + + dirbuf_boundary_dotest(L"A", 0, 1, L"B", 0); + dirbuf_boundary_dotest(L"B", 0, 0, L"B", 0); + dirbuf_boundary_dotest(L"C", 0, 0, L"B", 0); + + dirbuf_boundary_dotest(L"A", 0, 2, L"B", L"D", 0); + dirbuf_boundary_dotest(L"B", 1, 1, L"B", L"D", 0); + dirbuf_boundary_dotest(L"C", 1, 1, L"B", L"D", 0); + dirbuf_boundary_dotest(L"D", 0, 0, L"B", L"D", 0); + dirbuf_boundary_dotest(L"E", 0, 0, L"B", L"D", 0); + + dirbuf_boundary_dotest(L"A", 0, 3, L"B", L"D", L"F", 0); + dirbuf_boundary_dotest(L"B", 1, 2, L"B", L"D", L"F", 0); + dirbuf_boundary_dotest(L"C", 1, 2, L"B", L"D", L"F", 0); + dirbuf_boundary_dotest(L"D", 2, 1, L"B", L"D", L"F", 0); + dirbuf_boundary_dotest(L"E", 2, 1, L"B", L"D", L"F", 0); + dirbuf_boundary_dotest(L"F", 0, 0, L"B", L"D", L"F", 0); + dirbuf_boundary_dotest(L"G", 0, 0, L"B", L"D", L"F", 0); +} + void dirbuf_tests(void) { if (OptExternal) @@ -384,4 +472,5 @@ void dirbuf_tests(void) TEST(dirbuf_empty_test); TEST(dirbuf_dots_test); TEST(dirbuf_fill_test); + TEST(dirbuf_boundary_test); } diff --git a/tst/winfsp-tests/dirctl-test.c b/tst/winfsp-tests/dirctl-test.c index f5e9f851..7a98fab3 100644 --- a/tst/winfsp-tests/dirctl-test.c +++ b/tst/winfsp-tests/dirctl-test.c @@ -269,6 +269,93 @@ void querydir_test(void) } } +static void querydir_single_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, ULONG SleepTimeout) +{ + void *memfs = memfs_start_ex(Flags, FileInfoTimeout); + + HANDLE Handle; + BOOL Success; + WCHAR CurrentDirectory[MAX_PATH], FileName[MAX_PATH]; + WIN32_FIND_DATAW FindData; + + StringCbPrintfW(FileName, sizeof FileName, L"%s%s\\", + Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs)); + + Success = GetCurrentDirectoryW(MAX_PATH, CurrentDirectory); + ASSERT(Success); + + Success = SetCurrentDirectoryW(FileName); + ASSERT(Success); + + for (ULONG Index = 0; 1000 > Index; Index++) + { + StringCbPrintfW(FileName, sizeof FileName, L"xxxxxxx-file%lu", Index); + Handle = CreateFileW(FileName, + GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, + CREATE_NEW, FILE_ATTRIBUTE_NORMAL, + 0); + ASSERT(INVALID_HANDLE_VALUE != Handle); + Success = CloseHandle(Handle); + ASSERT(Success); + } + + Handle = FindFirstFileW(L"*", &FindData); + ASSERT(INVALID_HANDLE_VALUE != Handle); + do + { + } while (FindNextFileW(Handle, &FindData)); + Success = FindClose(Handle); + ASSERT(Success); + + for (ULONG Index = 0; 1000 > Index; Index++) + { + StringCbPrintfW(FileName, sizeof FileName, L"xxxxxxx-file%lu", Index); + Handle = FindFirstFileW(FileName, &FindData); + ASSERT(INVALID_HANDLE_VALUE != Handle); + do + { + } while (FindNextFileW(Handle, &FindData)); + Success = FindClose(Handle); + ASSERT(Success); + } + + for (ULONG Index = 0; 1000 > Index; Index++) + { + StringCbPrintfW(FileName, sizeof FileName, L"xxxxxxx-file%lu", Index); + Success = DeleteFileW(FileName); + ASSERT(Success); + } + + Success = RealSetCurrentDirectoryW(CurrentDirectory); + ASSERT(Success); + + memfs_stop(memfs); +} + +void querydir_single_test(void) +{ + if (OptShareName) + return; + + if (NtfsTests) + { + WCHAR DirBuf[MAX_PATH]; + GetTestDirectory(DirBuf); + querydir_single_dotest(-1, DirBuf, 0, 0); + } + if (WinFspDiskTests) + { + querydir_single_dotest(MemfsDisk, 0, 0, 0); + querydir_single_dotest(MemfsDisk, 0, 1000, 0); + } + if (WinFspNetTests) + { + querydir_single_dotest(MemfsNet, L"\\\\memfs\\share", 0, 0); + querydir_single_dotest(MemfsNet, L"\\\\memfs\\share", 1000, 0); + } +} + void querydir_expire_cache_test(void) { if (WinFspDiskTests) @@ -645,6 +732,8 @@ void dirnotify_test(void) void dirctl_tests(void) { TEST(querydir_test); + if (!OptShareName) + TEST_OPT(querydir_single_test); TEST(querydir_expire_cache_test); if (!OptShareName) TEST(querydir_buffer_overflow_test); diff --git a/tst/winfsp-tests/hooks.c b/tst/winfsp-tests/hooks.c index 30d8e206..d1f652dc 100644 --- a/tst/winfsp-tests/hooks.c +++ b/tst/winfsp-tests/hooks.c @@ -50,7 +50,7 @@ static VOID PrepareFileName(PCWSTR FileName, PWSTR FileNameBuf) else if (testalpha(FileNameBuf[0]) && L':' == FileNameBuf[1] && L'\\' == FileNameBuf[2]) P = FileNameBuf + 2; else - ABORT("unknown filename format"); + P = FileNameBuf; for (EndP = P + wcslen(P); EndP > P; P++) if (testalpha(*P) && myrand() <= (TogglePercent) * 0x7fff / 100) @@ -71,7 +71,7 @@ static VOID PrepareFileName(PCWSTR FileName, PWSTR FileNameBuf) else if (testalpha(FileNameBuf[0]) && L':' == FileNameBuf[1] && L'\\' == FileNameBuf[2]) ABORT("--mountpoint not supported with NTFS"); else - ABORT("unknown filename format"); + P = FileNameBuf; L1 = wcslen(P) + 1; L2 = wcslen(OptMountPoint); @@ -96,7 +96,7 @@ static VOID PrepareFileName(PCWSTR FileName, PWSTR FileNameBuf) /* NTFS testing can only been done when the whole drive is being shared */ P = FileNameBuf + 2; else - ABORT("unknown filename format"); + P = FileNameBuf; L1 = wcslen(P) + 1; L2 = wcslen(OptShareComputer);