From 13d6ec36387d480e0b6cd8914e9355bae261e42f Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Sat, 31 Dec 2016 15:28:26 -0800 Subject: [PATCH] sys: FspFileNodeRenameCheck: allow multiple handles open on the file being renamed --- src/sys/file.c | 3 +- tools/run-tests.bat | 4 +- tst/winfsp-tests/info-test.c | 97 ++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 4 deletions(-) diff --git a/src/sys/file.c b/src/sys/file.c index e4a3c1c6..78becd7c 100644 --- a/src/sys/file.c +++ b/src/sys/file.c @@ -1293,8 +1293,7 @@ NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp if (0 == DescendantFileNode) break; - /* if this is the FileNode being renamed then HandleCount must be 1, else 0 */ - if ((DescendantFileNode == FileNode) < DescendantFileNode->HandleCount) + if (DescendantFileNode != FileNode && 0 < DescendantFileNode->HandleCount) { /* release the FileNode in case of failure! */ FspFileNodeReleaseF(FileNode, AcquireFlags); diff --git a/tools/run-tests.bat b/tools/run-tests.bat index 0af0147b..a228860f 100755 --- a/tools/run-tests.bat +++ b/tools/run-tests.bat @@ -394,8 +394,8 @@ call :__ifstest %1 /d %2 /g DirectoryInformation /z /v if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1 call :__ifstest %1 /d %2 /g FileLocking /z /v if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1 -rem call :__ifstest %1 /d %2 /g OpLocks /z /v -rem if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1 +call :__ifstest %1 /d %2 /g OpLocks /z /v +if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1 call :__ifstest %1 /d %2 /g ChangeNotification /z /v if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1 call :__ifstest %1 /d %2 /g ReadWrite /z /v diff --git a/tst/winfsp-tests/info-test.c b/tst/winfsp-tests/info-test.c index b42c630e..92ae4d89 100644 --- a/tst/winfsp-tests/info-test.c +++ b/tst/winfsp-tests/info-test.c @@ -735,6 +735,102 @@ void rename_test(void) } } +static void rename_open_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout) +{ + void *memfs = memfs_start_ex(Flags, FileInfoTimeout); + + NTSYSCALLAPI NTSTATUS NTAPI + NtSetInformationFile( + HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass); + typedef struct + { + BOOLEAN ReplaceIfExists; + HANDLE RootDirectory; + ULONG FileNameLength; + WCHAR FileName[1]; + } FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION; + + HANDLE Handle0, Handle1, Handle2; + WCHAR File0Path[MAX_PATH]; + WCHAR File2Path[MAX_PATH]; + union + { + FILE_RENAME_INFORMATION I; + UINT8 B[sizeof(FILE_RENAME_INFORMATION) + MAX_PATH * sizeof(WCHAR)]; + } RenameInfo; + IO_STATUS_BLOCK IoStatus; + BOOLEAN Success; + + StringCbPrintfW(File0Path, sizeof File0Path, L"%s%s\\file0", + Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs)); + + StringCbPrintfW(File2Path, sizeof File2Path, L"%s%s\\file2", + Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs)); + + Handle0 = CreateFileW(File0Path, + GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, + CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0); + ASSERT(INVALID_HANDLE_VALUE != Handle0); + CloseHandle(Handle0); + + Handle0 = CreateFileW(File0Path, + DELETE, 0, 0, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + ASSERT(INVALID_HANDLE_VALUE != Handle0); + + Handle1 = CreateFileW(File0Path, + FILE_READ_ATTRIBUTES, 0, 0, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + ASSERT(INVALID_HANDLE_VALUE != Handle1); + + memset(&RenameInfo.I, 0, sizeof RenameInfo.I); + RenameInfo.I.FileNameLength = (ULONG)(wcslen(L"file2") * sizeof(WCHAR)); + memcpy(RenameInfo.I.FileName, L"file2", RenameInfo.I.FileNameLength); + IoStatus.Status = NtSetInformationFile( + Handle0, &IoStatus, + &RenameInfo.I, FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) + RenameInfo.I.FileNameLength, + 10/*FileRenameInformation*/); + ASSERT(0 == IoStatus.Status); + + Handle2 = CreateFileW(File2Path, + FILE_READ_ATTRIBUTES, 0, 0, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + ASSERT(INVALID_HANDLE_VALUE != Handle1); + + CloseHandle(Handle2); + CloseHandle(Handle1); + CloseHandle(Handle0); + + Success = DeleteFileW(File2Path); + ASSERT(Success); + + memfs_stop(memfs); +} + +void rename_open_test(void) +{ + if (NtfsTests) + { + WCHAR DirBuf[MAX_PATH]; + GetTestDirectory(DirBuf); + rename_open_dotest(-1, DirBuf, 0); + } + if (WinFspDiskTests) + { + rename_open_dotest(MemfsDisk, 0, 0); + rename_open_dotest(MemfsDisk, 0, 1000); + } + if (WinFspNetTests) + { + rename_open_dotest(MemfsNet, L"\\\\memfs\\share", 0); + rename_open_dotest(MemfsNet, L"\\\\memfs\\share", 1000); + } +} + static void rename_caseins_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout) { void *memfs = memfs_start_ex(Flags, FileInfoTimeout); @@ -1236,6 +1332,7 @@ void info_tests(void) if (!OptShareName) TEST(delete_mmap_test); TEST(rename_test); + TEST(rename_open_test); TEST(rename_caseins_test); if (!OptShareName) TEST(rename_flipflop_test);