diff --git a/tst/winfsp-tests/hooks.c b/tst/winfsp-tests/hooks.c index 54878d0a..ef376c97 100644 --- a/tst/winfsp-tests/hooks.c +++ b/tst/winfsp-tests/hooks.c @@ -21,6 +21,7 @@ #define WINFSP_TESTS_NO_HOOKS #include "winfsp-tests.h" +#include #define FILENAMEBUF_SIZE 1024 @@ -107,6 +108,75 @@ static VOID PrepareFileName(PCWSTR FileName, PWSTR FileNameBuf) } } +typedef struct +{ + HANDLE VolumeHandle; + FSP_FSCTL_NOTIFY_INFO *NotifyInfo; +} MAYBE_NOTIFY_DATA; + +static DWORD WINAPI MaybeNotifyRoutine(PVOID Context) +{ + MAYBE_NOTIFY_DATA *NotifyData = Context; + + /* + * The supplied VolumeHandle may be invalid or refer to the wrong object. + * This is ok because: + * + * - If the VolumeHandle is invalid, Windows will catch it and will fail the operation. + * - If the VolumeHandle refers to the wrong object, the FspFsctlNotify "should" fail + * because of an unknown DeviceIoControl code. + * - If the VolumeHandle refers to the wrong file system, it is still ok if we send an + * extraneous notify. + */ + + FspFsctlNotify(NotifyData->VolumeHandle, + NotifyData->NotifyInfo, NotifyData->NotifyInfo->Size); + + HeapFree(GetProcessHeap(), 0, NotifyData->NotifyInfo); + HeapFree(GetProcessHeap(), 0, NotifyData); + + return 0; +} + +static VOID MaybeNotify(PWSTR FileName, ULONG Filter, ULONG Action) +{ + static WCHAR DevicePrefix[] = + L"\\\\?\\GLOBALROOT\\Device\\Volume{01234567-0123-0123-0101-010101010101}"; + static WCHAR MemfsSharePrefix[] = + L"\\\\memfs\\share"; + MAYBE_NOTIFY_DATA *NotifyData; + FSP_FSCTL_NOTIFY_INFO *NotifyInfo; + size_t L; + + if (!OptNotify || OptExternal || 0 == memfs_handle) + return; + + if (0 == wcsncmp(FileName, DevicePrefix, wcschr(DevicePrefix, L'{') - DevicePrefix)) + FileName += wcslen(DevicePrefix); + else if (0 == mywcscmp( + FileName, (int)wcslen(MemfsSharePrefix), MemfsSharePrefix, (int)wcslen(MemfsSharePrefix))) + FileName += wcslen(MemfsSharePrefix); + else + return; + + L = wcslen(FileName); + NotifyData = HeapAlloc(GetProcessHeap(), 0, sizeof *NotifyData); + NotifyInfo = HeapAlloc(GetProcessHeap(), 0, sizeof *NotifyInfo + L * sizeof(WCHAR)); + if (0 == NotifyData || 0 == NotifyInfo) + ABORT("cannot malloc notify data"); + + NotifyInfo->Size = (UINT16)(sizeof *NotifyInfo + L * sizeof(WCHAR)); + NotifyInfo->Filter = Filter; + NotifyInfo->Action = Action; + memcpy(NotifyInfo->FileNameBuf, FileName, L * sizeof(WCHAR)); + + NotifyData->VolumeHandle = memfs_handle; + NotifyData->NotifyInfo = NotifyInfo; + + if (!QueueUserWorkItem(MaybeNotifyRoutine, NotifyData, 0)) + ABORT("cannot queue notify data"); +} + typedef struct { HANDLE File; @@ -210,6 +280,9 @@ HANDLE WINAPI HookCreateFileW( PrepareFileName(lpFileName, FileNameBuf); + MaybeNotify(FileNameBuf, + FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED); + MaybeRequestOplock(FileNameBuf); MaybeAdjustTraversePrivilege(FALSE); @@ -241,6 +314,9 @@ BOOL WINAPI HookSetFileAttributesW( PrepareFileName(lpFileName, FileNameBuf); + MaybeNotify(FileNameBuf, + FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED); + MaybeAdjustTraversePrivilege(FALSE); Success = SetFileAttributesW(FileNameBuf, dwFileAttributes); MaybeAdjustTraversePrivilege(TRUE); @@ -256,6 +332,9 @@ BOOL WINAPI HookCreateDirectoryW( PrepareFileName(lpPathName, FileNameBuf); + MaybeNotify(FileNameBuf, + FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED); + MaybeAdjustTraversePrivilege(FALSE); Success = CreateDirectoryW(FileNameBuf, lpSecurityAttributes); MaybeAdjustTraversePrivilege(TRUE); @@ -270,6 +349,9 @@ BOOL WINAPI HookDeleteFileW( PrepareFileName(lpFileName, FileNameBuf); + MaybeNotify(FileNameBuf, + FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED); + MaybeRequestOplock(FileNameBuf); MaybeAdjustTraversePrivilege(FALSE); @@ -287,6 +369,9 @@ BOOL WINAPI HookRemoveDirectoryW( PrepareFileName(lpPathName, FileNameBuf); + MaybeNotify(FileNameBuf, + FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED); + MaybeAdjustTraversePrivilege(FALSE); Success = (OptResilient ? ResilientRemoveDirectoryW : RemoveDirectoryW)( FileNameBuf); @@ -306,6 +391,13 @@ BOOL WINAPI HookMoveFileExW( PrepareFileName(lpExistingFileName, OldFileNameBuf); PrepareFileName(lpNewFileName, NewFileNameBuf); + MaybeNotify(OldFileNameBuf, + FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED); + if (OptCaseInsensitive ? + _wcsicmp(OldFileNameBuf, NewFileNameBuf) : wcscmp(OldFileNameBuf, NewFileNameBuf)) + MaybeNotify(NewFileNameBuf, + FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED); + MaybeRequestOplock(OldFileNameBuf); if (OptCaseInsensitive ? _wcsicmp(OldFileNameBuf, NewFileNameBuf) : wcscmp(OldFileNameBuf, NewFileNameBuf)) @@ -326,6 +418,9 @@ HANDLE WINAPI HookFindFirstFileW( PrepareFileName(lpFileName, FileNameBuf); + MaybeNotify(FileNameBuf, + FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED); + MaybeAdjustTraversePrivilege(FALSE); Handle = FindFirstFileW(FileNameBuf, lpFindFileData); MaybeAdjustTraversePrivilege(TRUE); @@ -343,6 +438,9 @@ HANDLE WINAPI HookFindFirstStreamW( PrepareFileName(lpFileName, FileNameBuf); + MaybeNotify(FileNameBuf, + FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED); + MaybeAdjustTraversePrivilege(FALSE); Handle = FindFirstStreamW(FileNameBuf, InfoLevel, lpFindStreamData, dwFlags); MaybeAdjustTraversePrivilege(TRUE); @@ -426,6 +524,9 @@ BOOL WINAPI HookSetCurrentDirectoryW( PrepareFileName(lpPathName, FileNameBuf); + MaybeNotify(FileNameBuf, + FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED); + MaybeAdjustTraversePrivilege(FALSE); Success = SetCurrentDirectoryW(FileNameBuf); MaybeAdjustTraversePrivilege(TRUE); @@ -449,6 +550,9 @@ BOOL WINAPI HookCreateProcessW( PrepareFileName(lpApplicationName, FileNameBuf); + MaybeNotify(FileNameBuf, + FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED); + MaybeAdjustTraversePrivilege(FALSE); Success = CreateProcessW(FileNameBuf, lpCommandLine, /* we should probably change this as well */ diff --git a/tst/winfsp-tests/memfs-test.c b/tst/winfsp-tests/memfs-test.c index af5291f9..584b3549 100644 --- a/tst/winfsp-tests/memfs-test.c +++ b/tst/winfsp-tests/memfs-test.c @@ -27,6 +27,7 @@ #include "winfsp-tests.h" int memfs_running; +HANDLE memfs_handle; void *memfs_start_ex(ULONG Flags, ULONG FileInfoTimeout) { @@ -66,6 +67,7 @@ void *memfs_start_ex(ULONG Flags, ULONG FileInfoTimeout) ASSERT(NT_SUCCESS(Result)); memfs_running = 1; + memfs_handle = MemfsFileSystem(Memfs)->VolumeHandle; return Memfs; } @@ -77,6 +79,7 @@ void *memfs_start(ULONG Flags) void memfs_stop(void *data) { + memfs_handle = 0; memfs_running = 0; if (0 == data) diff --git a/tst/winfsp-tests/notify-test.c b/tst/winfsp-tests/notify-test.c index 1a5c8894..6ddcc9a5 100644 --- a/tst/winfsp-tests/notify-test.c +++ b/tst/winfsp-tests/notify-test.c @@ -342,12 +342,12 @@ void notify_open_change_test(void) void notify_tests(void) { - if (!OptExternal) - { - TEST(notify_abandon_test); - TEST(notify_abandon_rename_test); - TEST(notify_timeout_test); - TEST(notify_change_test); - TEST(notify_open_change_test); - } + if (OptExternal || OptNotify) + return; + + TEST(notify_abandon_test); + TEST(notify_abandon_rename_test); + TEST(notify_timeout_test); + TEST(notify_change_test); + TEST(notify_open_change_test); } diff --git a/tst/winfsp-tests/winfsp-tests.c b/tst/winfsp-tests/winfsp-tests.c index 0f5aa0da..f6b33e10 100644 --- a/tst/winfsp-tests/winfsp-tests.c +++ b/tst/winfsp-tests/winfsp-tests.c @@ -38,6 +38,7 @@ BOOLEAN OptCaseInsensitiveCmp = FALSE; BOOLEAN OptCaseInsensitive = FALSE; BOOLEAN OptCaseRandomize = FALSE; BOOLEAN OptFlushAndPurgeOnCleanup = FALSE; +BOOLEAN OptNotify = FALSE; WCHAR OptOplock = 0; WCHAR OptMountPointBuf[MAX_PATH], *OptMountPoint; WCHAR OptShareNameBuf[MAX_PATH], *OptShareName, *OptShareTarget; @@ -259,6 +260,11 @@ int main(int argc, char *argv[]) OptFlushAndPurgeOnCleanup = TRUE; rmarg(argv, argc, argi); } + else if (0 == strcmp("--notify", a)) + { + OptNotify = TRUE; + rmarg(argv, argc, argi); + } else if (0 == strcmp("--oplock=batch", a)) { OptOplock = 'B'; diff --git a/tst/winfsp-tests/winfsp-tests.h b/tst/winfsp-tests/winfsp-tests.h index b744b8ef..8dac2ead 100644 --- a/tst/winfsp-tests/winfsp-tests.h +++ b/tst/winfsp-tests/winfsp-tests.h @@ -159,6 +159,7 @@ extern BOOLEAN OptCaseInsensitiveCmp; extern BOOLEAN OptCaseInsensitive; extern BOOLEAN OptCaseRandomize; extern BOOLEAN OptFlushAndPurgeOnCleanup; +extern BOOLEAN OptNotify; extern WCHAR OptOplock; extern WCHAR OptMountPointBuf[], *OptMountPoint; extern WCHAR OptShareNameBuf[], *OptShareName, *OptShareTarget; @@ -168,3 +169,4 @@ extern HANDLE OptNoTraverseToken; extern LUID OptNoTraverseLuid; extern int memfs_running; +extern HANDLE memfs_handle;