From ff449464fcc06924312db6ecf86e35e18a6d2029 Mon Sep 17 00:00:00 2001 From: karakasa Date: Sat, 30 Nov 2024 16:56:53 +0800 Subject: [PATCH 1/7] pass HResult to IOException ctor in SafeFileHandle.Preallocate --- .../src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs index 91b863e22f7a51..ad07353e30a546 100644 --- a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs @@ -147,7 +147,7 @@ private static unsafe void Preallocate(string fullPath, long preallocationSize, throw new IOException(SR.Format(errorCode == Interop.Errors.ERROR_DISK_FULL ? SR.IO_DiskFull_Path_AllocationSize : SR.IO_FileTooLarge_Path_AllocationSize, - fullPath, preallocationSize)); + fullPath, preallocationSize), Win32Marshal.MakeHRFromErrorCode(errorCode)); } } } From ad221ad7d11c05770b4e59390ab381b8d8f19d9c Mon Sep 17 00:00:00 2001 From: karakasa Date: Sat, 30 Nov 2024 17:26:35 +0800 Subject: [PATCH 2/7] added test --- .../File/OpenHandle.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/OpenHandle.cs b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/OpenHandle.cs index 36349e8b993b7c..26322cdc9c34eb 100644 --- a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/OpenHandle.cs +++ b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/OpenHandle.cs @@ -95,5 +95,35 @@ public void DeleteOnClose_FileDeletedAfterSafeHandleDispose(FileOptions options) } Assert.False(File.Exists(path)); } + + [Fact] + [PlatformSpecific(TestPlatforms.Windows)] + public void PreallocateLargeFileAndFail() + { + const long VeryLargeFileSize = (long)128 * 1024 * 1024 * 1024 * 1024; // 128TB, large but still allowed by NTFS + const int ERROR_DISK_FULL = unchecked((int)0x80070070); + + string path = GetTestFilePath(); + if (!IOServices.IsDriveNTFS(Path.GetPathRoot(path))) + { + // Skip the test for non-NTFS filesystems + return; + } + + if (new DriveInfo(path).TotalFreeSpace >= VeryLargeFileSize) + { + // Skip the test if somehow the drive is really big. + return; + } + + try + { + using (File.OpenHandle(path, mode: FileMode.Create, access: FileAccess.ReadWrite, preallocationSize: VeryLargeFileSize)) { } + } + catch (IOException ex) + { + Assert.Equal(ERROR_DISK_FULL, ex.HResult); + } + } } } From 02f7e8ff2e9a9ddadf7c3f794ce2f9460f7264b6 Mon Sep 17 00:00:00 2001 From: karakasa Date: Sat, 30 Nov 2024 17:32:29 +0800 Subject: [PATCH 3/7] changed method name --- .../tests/System.IO.FileSystem.Tests/File/OpenHandle.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/OpenHandle.cs b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/OpenHandle.cs index 26322cdc9c34eb..3ba0fd64952ca1 100644 --- a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/OpenHandle.cs +++ b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/OpenHandle.cs @@ -98,7 +98,7 @@ public void DeleteOnClose_FileDeletedAfterSafeHandleDispose(FileOptions options) [Fact] [PlatformSpecific(TestPlatforms.Windows)] - public void PreallocateLargeFileAndFail() + public void PreallocationSizeVeryLargeThrowsCorrectHResult() { const long VeryLargeFileSize = (long)128 * 1024 * 1024 * 1024 * 1024; // 128TB, large but still allowed by NTFS const int ERROR_DISK_FULL = unchecked((int)0x80070070); From 0c9442d49c9e9217883830a67c31ee7da917b489 Mon Sep 17 00:00:00 2001 From: karakasa Date: Sat, 30 Nov 2024 17:35:29 +0800 Subject: [PATCH 4/7] amended the test --- .../tests/System.IO.FileSystem.Tests/File/OpenHandle.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/OpenHandle.cs b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/OpenHandle.cs index 3ba0fd64952ca1..930e0309bb4f9c 100644 --- a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/OpenHandle.cs +++ b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/OpenHandle.cs @@ -119,6 +119,7 @@ public void PreallocationSizeVeryLargeThrowsCorrectHResult() try { using (File.OpenHandle(path, mode: FileMode.Create, access: FileAccess.ReadWrite, preallocationSize: VeryLargeFileSize)) { } + Assert.Fail("The test should fail due to failure to preallocate a very large file."); } catch (IOException ex) { From 63fc0cbc2bf7d3512d4df1111d7b1a7e379fe4b2 Mon Sep 17 00:00:00 2001 From: karakasa Date: Thu, 9 Jan 2025 22:39:21 +0800 Subject: [PATCH 5/7] fix test issue --- .../Win32/SafeHandles/SafeFileHandle.Windows.cs | 5 +++-- .../System.IO.FileSystem.Tests/File/OpenHandle.cs | 11 +++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs index ad07353e30a546..d1e70527f8a0b7 100644 --- a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs @@ -136,8 +136,9 @@ private static unsafe void Preallocate(string fullPath, long preallocationSize, int errorCode = Marshal.GetLastPInvokeError(); // Only throw for errors that indicate there is not enough space. - if (errorCode == Interop.Errors.ERROR_DISK_FULL || - errorCode == Interop.Errors.ERROR_FILE_TOO_LARGE) + if (errorCode is Interop.Errors.ERROR_DISK_FULL or + Interop.Errors.ERROR_FILE_TOO_LARGE or + Interop.Errors.ERROR_INVALID_PARAMETER) { fileHandle.Dispose(); diff --git a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/OpenHandle.cs b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/OpenHandle.cs index 930e0309bb4f9c..affa3c39856ec0 100644 --- a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/OpenHandle.cs +++ b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/OpenHandle.cs @@ -100,7 +100,13 @@ public void DeleteOnClose_FileDeletedAfterSafeHandleDispose(FileOptions options) [PlatformSpecific(TestPlatforms.Windows)] public void PreallocationSizeVeryLargeThrowsCorrectHResult() { - const long VeryLargeFileSize = (long)128 * 1024 * 1024 * 1024 * 1024; // 128TB, large but still allowed by NTFS + const long VeryLargeFileSize = (long)128 * 1024 * 1024 * 1024 * 1024; // 128TB + + // The largest file size depends on cluster size. + // See https://learn.microsoft.com/en-us/windows-server/storage/file-server/ntfs-overview#support-for-large-volumes + + + const int ERROR_INVALID_PARAMETER = unchecked((int)0x80070057); const int ERROR_DISK_FULL = unchecked((int)0x80070070); string path = GetTestFilePath(); @@ -123,7 +129,8 @@ public void PreallocationSizeVeryLargeThrowsCorrectHResult() } catch (IOException ex) { - Assert.Equal(ERROR_DISK_FULL, ex.HResult); + // Accept both results since we cannot assume the cluster size of testing volume + Assert.True(ex.HResult is ERROR_INVALID_PARAMETER or ERROR_DISK_FULL); } } } From 00b4202875075dae7aa5884c4ca561fe16327c00 Mon Sep 17 00:00:00 2001 From: karakasa Date: Thu, 9 Jan 2025 22:42:01 +0800 Subject: [PATCH 6/7] added comment --- .../src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs index d1e70527f8a0b7..760dfdb37bf518 100644 --- a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs @@ -149,6 +149,9 @@ Interop.Errors.ERROR_FILE_TOO_LARGE or ? SR.IO_DiskFull_Path_AllocationSize : SR.IO_FileTooLarge_Path_AllocationSize, fullPath, preallocationSize), Win32Marshal.MakeHRFromErrorCode(errorCode)); + + // SetFileInformationByHandle fails with ERROR_DISK_FULL in certain cases where the size is disallowed by filesystem + // such as >4GB on FAT32 volume. We cannot distinguish them currently. } } } From 5bbd9372c49f4eba41ce18dc5d346307a2da16d8 Mon Sep 17 00:00:00 2001 From: karakasa Date: Thu, 9 Jan 2025 22:58:25 +0800 Subject: [PATCH 7/7] tidy up comments --- .../Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs | 5 ++--- .../tests/System.IO.FileSystem.Tests/File/OpenHandle.cs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs index 760dfdb37bf518..5b87aba0918650 100644 --- a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs @@ -136,6 +136,8 @@ private static unsafe void Preallocate(string fullPath, long preallocationSize, int errorCode = Marshal.GetLastPInvokeError(); // Only throw for errors that indicate there is not enough space. + // SetFileInformationByHandle fails with ERROR_DISK_FULL in certain cases when the size is disallowed by filesystem, + // such as >4GB on FAT32 volume. We cannot distinguish them currently. if (errorCode is Interop.Errors.ERROR_DISK_FULL or Interop.Errors.ERROR_FILE_TOO_LARGE or Interop.Errors.ERROR_INVALID_PARAMETER) @@ -149,9 +151,6 @@ Interop.Errors.ERROR_FILE_TOO_LARGE or ? SR.IO_DiskFull_Path_AllocationSize : SR.IO_FileTooLarge_Path_AllocationSize, fullPath, preallocationSize), Win32Marshal.MakeHRFromErrorCode(errorCode)); - - // SetFileInformationByHandle fails with ERROR_DISK_FULL in certain cases where the size is disallowed by filesystem - // such as >4GB on FAT32 volume. We cannot distinguish them currently. } } } diff --git a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/OpenHandle.cs b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/OpenHandle.cs index affa3c39856ec0..3d7bcb303b4ce7 100644 --- a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/OpenHandle.cs +++ b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/OpenHandle.cs @@ -125,7 +125,7 @@ public void PreallocationSizeVeryLargeThrowsCorrectHResult() try { using (File.OpenHandle(path, mode: FileMode.Create, access: FileAccess.ReadWrite, preallocationSize: VeryLargeFileSize)) { } - Assert.Fail("The test should fail due to failure to preallocate a very large file."); + Assert.Fail("File.OpenHandle should throw due to failure to preallocate a very large file."); } catch (IOException ex) {