From 316a2940dcfd6dd4862551925698366d1ff950cf Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Thu, 15 Sep 2016 15:28:55 -0700 Subject: [PATCH] sys: write: FspFsvolWriteCached: fix simple but major bug when using FILE_APPEND_DATA --- src/sys/write.c | 5 +- tst/winfsp-tests/rdwr-test.c | 159 +++++++++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+), 2 deletions(-) diff --git a/src/sys/write.c b/src/sys/write.c index 3abba430..b8052eea 100644 --- a/src/sys/write.c +++ b/src/sys/write.c @@ -151,8 +151,9 @@ static NTSTATUS FspFsvolWriteCached( ASSERT(FspTimeoutInfinity32 == FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.FileInfoTimeout); FspFileNodeGetFileInfo(FileNode, &FileInfo); - WriteEndOffset = WriteToEndOfFile ? - FileInfo.FileSize + WriteLength : WriteOffset.QuadPart + WriteLength; + if (WriteToEndOfFile) + WriteOffset.QuadPart = FileInfo.FileSize; + WriteEndOffset = WriteOffset.QuadPart + WriteLength; ExtendingFile = FileInfo.FileSize < WriteEndOffset; if (ExtendingFile && !CanWait) { diff --git a/tst/winfsp-tests/rdwr-test.c b/tst/winfsp-tests/rdwr-test.c index 2f55d4d7..87cf9bd4 100644 --- a/tst/winfsp-tests/rdwr-test.c +++ b/tst/winfsp-tests/rdwr-test.c @@ -192,6 +192,90 @@ static void rdwr_dotest(ULONG Flags, PWSTR VolPrefix, PWSTR Prefix, ULONG FileIn memfs_stop(memfs); } +static void rdwr_append_dotest(ULONG Flags, PWSTR VolPrefix, PWSTR Prefix, ULONG FileInfoTimeout, DWORD CreateFlags) +{ + void *memfs = memfs_start_ex(Flags, FileInfoTimeout); + + HANDLE Handle; + BOOL Success; + WCHAR FilePath[MAX_PATH]; + SYSTEM_INFO SystemInfo; + DWORD SectorsPerCluster; + DWORD BytesPerSector; + DWORD FreeClusters; + DWORD TotalClusters; + PVOID AllocBuffer[2], Buffer[2]; + ULONG AllocBufferSize; + DWORD BytesTransferred; + DWORD FilePointer; + + GetSystemInfo(&SystemInfo); + + StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\", + VolPrefix ? L"" : L"\\\\?\\GLOBALROOT", VolPrefix ? VolPrefix : memfs_volumename(memfs)); + + Success = GetDiskFreeSpaceW(FilePath, &SectorsPerCluster, &BytesPerSector, &FreeClusters, &TotalClusters); + ASSERT(Success); + AllocBufferSize = 16 * SystemInfo.dwPageSize; + + AllocBuffer[0] = _aligned_malloc(AllocBufferSize, SystemInfo.dwPageSize); + AllocBuffer[1] = _aligned_malloc(AllocBufferSize, SystemInfo.dwPageSize); + ASSERT(0 != AllocBuffer[0] && 0 != AllocBuffer[1]); + + srand((unsigned)time(0)); + for (PUINT8 Bgn = AllocBuffer[0], End = Bgn + AllocBufferSize; End > Bgn; Bgn++) + *Bgn = rand(); + + Buffer[0] = (PVOID)((PUINT8)AllocBuffer[0] + BytesPerSector); + Buffer[1] = (PVOID)((PUINT8)AllocBuffer[1] + BytesPerSector); + + StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\file0", + Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs)); + + Handle = CreateFileW(FilePath, + FILE_APPEND_DATA, FILE_SHARE_READ, 0, + CREATE_NEW, FILE_ATTRIBUTE_NORMAL | CreateFlags, 0); + ASSERT(INVALID_HANDLE_VALUE != Handle); + + Success = WriteFile(Handle, Buffer[0], BytesPerSector, &BytesTransferred, 0); + ASSERT(Success); + ASSERT(BytesPerSector == BytesTransferred); + + Success = WriteFile(Handle, (PUINT8)Buffer[0] + BytesPerSector, BytesPerSector, &BytesTransferred, 0); + ASSERT(Success); + ASSERT(BytesPerSector == BytesTransferred); + + Success = CloseHandle(Handle); + ASSERT(Success); + + Handle = CreateFileW(FilePath, + GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | CreateFlags | FILE_FLAG_DELETE_ON_CLOSE, 0); + ASSERT(INVALID_HANDLE_VALUE != Handle); + + FilePointer = SetFilePointer(Handle, 0, 0, FILE_BEGIN); + ASSERT(0 == FilePointer); + memset(AllocBuffer[1], 0, AllocBufferSize); + Success = ReadFile(Handle, Buffer[1], 2 * BytesPerSector, &BytesTransferred, 0); + ASSERT(Success); + ASSERT(2 * BytesPerSector == BytesTransferred); + ASSERT(0 == memcmp(Buffer[0], Buffer[1], BytesTransferred)); + + Success = CloseHandle(Handle); + ASSERT(Success); + + Handle = CreateFileW(FilePath, + GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, + OPEN_EXISTING, 0, 0); + ASSERT(INVALID_HANDLE_VALUE == Handle); + ASSERT(ERROR_FILE_NOT_FOUND == GetLastError()); + + _aligned_free(AllocBuffer[0]); + _aligned_free(AllocBuffer[1]); + + memfs_stop(memfs); +} + static void rdwr_overlapped_dotest(ULONG Flags, PWSTR VolPrefix, PWSTR Prefix, ULONG FileInfoTimeout, DWORD CreateFlags) { void *memfs = memfs_start_ex(Flags, FileInfoTimeout); @@ -742,6 +826,32 @@ void rdwr_noncached_test(void) } } +/* + * According to NtCreateFile documentation the FILE_NO_INTERMEDIATE_BUFFERING flag + * "is incompatible with the DesiredAccess FILE_APPEND_DATA flag". + */ +#if 0 +void rdwr_noncached_append_test(void) +{ + if (NtfsTests) + { + WCHAR DirBuf[MAX_PATH] = L"\\\\?\\"; + GetCurrentDirectoryW(MAX_PATH - 4, DirBuf + 4); + rdwr_append_dotest(-1, L"C:", DirBuf, 0, FILE_FLAG_NO_BUFFERING); + } + if (WinFspDiskTests) + { + rdwr_append_dotest(MemfsDisk, 0, 0, 1000, FILE_FLAG_NO_BUFFERING); + rdwr_append_dotest(MemfsDisk, 0, 0, INFINITE, FILE_FLAG_NO_BUFFERING); + } + if (WinFspNetTests) + { + rdwr_append_dotest(MemfsNet, L"\\\\memfs\\share", L"\\\\memfs\\share", 1000, FILE_FLAG_NO_BUFFERING); + rdwr_append_dotest(MemfsNet, L"\\\\memfs\\share", L"\\\\memfs\\share", INFINITE, FILE_FLAG_NO_BUFFERING); + } +} +#endif + void rdwr_noncached_overlapped_test(void) { if (NtfsTests) @@ -782,6 +892,26 @@ void rdwr_cached_test(void) } } +void rdwr_cached_append_test(void) +{ + if (NtfsTests) + { + WCHAR DirBuf[MAX_PATH] = L"\\\\?\\"; + GetCurrentDirectoryW(MAX_PATH - 4, DirBuf + 4); + rdwr_append_dotest(-1, L"C:", DirBuf, 0, 0); + } + if (WinFspDiskTests) + { + rdwr_append_dotest(MemfsDisk, 0, 0, 1000, 0); + rdwr_append_dotest(MemfsDisk, 0, 0, INFINITE, 0); + } + if (WinFspNetTests) + { + rdwr_append_dotest(MemfsNet, L"\\\\memfs\\share", L"\\\\memfs\\share", 1000, 0); + rdwr_append_dotest(MemfsNet, L"\\\\memfs\\share", L"\\\\memfs\\share", INFINITE, 0); + } +} + void rdwr_cached_overlapped_test(void) { if (NtfsTests) @@ -822,6 +952,26 @@ void rdwr_writethru_test(void) } } +void rdwr_writethru_append_test(void) +{ + if (NtfsTests) + { + WCHAR DirBuf[MAX_PATH] = L"\\\\?\\"; + GetCurrentDirectoryW(MAX_PATH - 4, DirBuf + 4); + rdwr_append_dotest(-1, L"C:", DirBuf, 0, FILE_FLAG_WRITE_THROUGH); + } + if (WinFspDiskTests) + { + rdwr_append_dotest(MemfsDisk, 0, 0, 1000, FILE_FLAG_WRITE_THROUGH); + rdwr_append_dotest(MemfsDisk, 0, 0, INFINITE, FILE_FLAG_WRITE_THROUGH); + } + if (WinFspNetTests) + { + rdwr_append_dotest(MemfsNet, L"\\\\memfs\\share", L"\\\\memfs\\share", 1000, FILE_FLAG_WRITE_THROUGH); + rdwr_append_dotest(MemfsNet, L"\\\\memfs\\share", L"\\\\memfs\\share", INFINITE, FILE_FLAG_WRITE_THROUGH); + } +} + void rdwr_writethru_overlapped_test(void) { if (NtfsTests) @@ -940,10 +1090,19 @@ void rdwr_mixed_test(void) void rdwr_tests(void) { TEST(rdwr_noncached_test); +#if 0 + /* + * According to NtCreateFile documentation the FILE_NO_INTERMEDIATE_BUFFERING flag + * "is incompatible with the DesiredAccess FILE_APPEND_DATA flag". + */ + TEST(rdwr_noncached_append_test); +#endif TEST(rdwr_noncached_overlapped_test); TEST(rdwr_cached_test); + TEST(rdwr_cached_append_test); TEST(rdwr_cached_overlapped_test); TEST(rdwr_writethru_test); + TEST(rdwr_writethru_append_test); TEST(rdwr_writethru_overlapped_test); TEST(rdwr_mmap_test); TEST(rdwr_mixed_test);