-
Notifications
You must be signed in to change notification settings - Fork 5.1k
[WIP] Improve File.Copy
by using the block copy operation for ReFS on Windows
#88695
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
4711fde
WIP commit
hamarb123 f864fec
Merge branch 'main' of https://github.com/hamarb123/runtime
hamarb123 306ca00
Fix `LARGE_INTEGER` alignment/packing
hamarb123 e1be061
Fix some p/invoke issues
hamarb123 0b9b36a
Implement more feedback
hamarb123 2a8f650
Fix usage of ValueStringBuilder
hamarb123 ee32bef
Readonly structs where possible
hamarb123 33b6090
Implement feedback for test project
hamarb123 ddb816b
Implement feedback
hamarb123 cf8fbf6
Fix file imports for test project
hamarb123 29ef3d3
Move structs in to their own files
hamarb123 fba6f0f
Implement feedback for GetVolumeInformationByHandle
hamarb123 5b1180d
Improve impl of GetVolumePathName
hamarb123 7f21a4c
Split WindowsCheckSparseness to a new file
hamarb123 a7a74a0
Implement improved logic & other changes
hamarb123 b6ff8b9
Fix signature of GetDiskFreeSpace
hamarb123 f6df015
Remove unnecessary check (which only pessimises a particular case)
hamarb123 ce80ab2
Fix name of `bytesPerSector` local
hamarb123 b02e4bc
Merge remote-tracking branch 'upstream/main'
hamarb123 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
19 changes: 19 additions & 0 deletions
19
src/libraries/Common/src/Interop/Windows/Kernel32/Interop.DUPLICATE_EXTENTS_DATA.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System; | ||
|
||
internal static partial class Interop | ||
{ | ||
internal static partial class Kernel32 | ||
{ | ||
// https://learn.microsoft.com/windows/win32/api/winioctl/ns-winioctl-duplicate_extents_data | ||
internal struct DUPLICATE_EXTENTS_DATA | ||
{ | ||
internal IntPtr FileHandle; | ||
internal long SourceFileOffset; | ||
internal long TargetFileOffset; | ||
internal long ByteCount; | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
17 changes: 17 additions & 0 deletions
17
src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FILE_DISPOSITION_INFO.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
internal static partial class Interop | ||
{ | ||
internal static partial class Kernel32 | ||
{ | ||
// From FILE_INFO_BY_HANDLE_CLASS | ||
// Use for SetFileInformationByHandle | ||
internal const int FileDispositionInfo = 4; | ||
|
||
internal struct FILE_DISPOSITION_INFO | ||
{ | ||
internal BOOLEAN DeleteFile; | ||
} | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FILE_SET_SPARSE_BUFFER.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
internal static partial class Interop | ||
{ | ||
internal static partial class Kernel32 | ||
{ | ||
// https://learn.microsoft.com/windows/win32/api/winioctl/ns-winioctl-file_set_sparse_buffer | ||
internal struct FILE_SET_SPARSE_BUFFER | ||
{ | ||
internal BOOLEAN SetSparse; | ||
} | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
...ies/Common/src/Interop/Windows/Kernel32/Interop.FSCTL_GET_INTEGRITY_INFORMATION_BUFFER.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
internal static partial class Interop | ||
{ | ||
internal static partial class Kernel32 | ||
{ | ||
// https://learn.microsoft.com/windows/win32/api/winioctl/ns-winioctl-fsctl_get_integrity_information_buffer | ||
internal struct FSCTL_GET_INTEGRITY_INFORMATION_BUFFER | ||
{ | ||
internal ushort ChecksumAlgorithm; | ||
internal ushort Reserved; | ||
internal uint Flags; | ||
internal uint ChecksumChunkSizeInBytes; | ||
internal uint ClusterSizeInBytes; | ||
} | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
...ies/Common/src/Interop/Windows/Kernel32/Interop.FSCTL_SET_INTEGRITY_INFORMATION_BUFFER.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
internal static partial class Interop | ||
{ | ||
internal static partial class Kernel32 | ||
{ | ||
// https://learn.microsoft.com/windows/win32/api/winioctl/ns-winioctl-fsctl_set_integrity_information_buffer | ||
internal struct FSCTL_SET_INTEGRITY_INFORMATION_BUFFER | ||
{ | ||
internal ushort ChecksumAlgorithm; | ||
internal ushort Reserved; | ||
internal uint Flags; | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 14 additions & 0 deletions
14
src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetDiskFreeSpace.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.Runtime.InteropServices; | ||
|
||
internal static partial class Interop | ||
{ | ||
internal static partial class Kernel32 | ||
{ | ||
[LibraryImport(Libraries.Kernel32, EntryPoint = "GetDiskFreeSpaceW", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)] | ||
[return: MarshalAs(UnmanagedType.Bool)] | ||
internal static unsafe partial bool GetDiskFreeSpace(string drive, uint* sectorsPerCluster, uint* bytesPerSector, uint* numberOfFreeClusters, uint* totalNumberOfClusters); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetVolumeInformationByHandle.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System; | ||
using System.Diagnostics; | ||
using System.IO; | ||
using System.Runtime.InteropServices; | ||
using System.Text; | ||
using Microsoft.Win32.SafeHandles; | ||
|
||
internal static partial class Interop | ||
{ | ||
internal static partial class Kernel32 | ||
{ | ||
[LibraryImport(Libraries.Kernel32, EntryPoint = "GetVolumeInformationByHandleW", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)] | ||
[return: MarshalAs(UnmanagedType.Bool)] | ||
internal static unsafe partial bool GetVolumeInformationByHandle( | ||
SafeFileHandle hFile, | ||
char* volumeName, | ||
uint volumeNameBufLen, | ||
uint* volSerialNumber, | ||
uint* maxFileNameLen, | ||
uint* fileSystemFlags, | ||
char* fileSystemName, | ||
uint fileSystemNameBufLen); | ||
} | ||
} |
52 changes: 52 additions & 0 deletions
52
src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetVolumePathName.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System; | ||
using System.Diagnostics; | ||
using System.IO; | ||
using System.Runtime.CompilerServices; | ||
using System.Runtime.InteropServices; | ||
using System.Text; | ||
|
||
internal static partial class Interop | ||
{ | ||
internal static partial class Kernel32 | ||
{ | ||
[LibraryImport(Libraries.Kernel32, EntryPoint = "GetVolumePathNameW", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)] | ||
[return: MarshalAs(UnmanagedType.Bool)] | ||
private static unsafe partial bool GetVolumePathName(char* lpszFileName, char* lpszVolumePathName, int cchBufferLength); | ||
|
||
internal static unsafe string GetVolumePathName(string fileName) | ||
{ | ||
// Ensure we have the prefix | ||
fileName = PathInternal.EnsureExtendedPrefixIfNeeded(fileName); | ||
|
||
// Ensure our output buffer will be long enough (see https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumepathnamew#remarks) | ||
int requiredBufferLength = (int)GetFullPathNameW(ref MemoryMarshal.GetReference<char>(fileName), 0, ref Unsafe.NullRef<char>(), 0); | ||
if (requiredBufferLength == 0) throw Win32Marshal.GetExceptionForWin32Error(Marshal.GetLastWin32Error(), fileName); | ||
|
||
// Allocate a value string builder | ||
// note: MAX_PATH is not a hard limit, but would only be exceeded by a long path | ||
ValueStringBuilder vsb = new(requiredBufferLength <= Interop.Kernel32.MAX_PATH ? stackalloc char[Interop.Kernel32.MAX_PATH] : default); | ||
vsb.EnsureCapacity(requiredBufferLength); | ||
|
||
// Call the actual API | ||
fixed (char* lpszFileName = fileName) | ||
{ | ||
fixed (char* lpszVolumePathName = vsb.RawChars) | ||
{ | ||
if (GetVolumePathName(lpszFileName, lpszVolumePathName, requiredBufferLength)) | ||
{ | ||
vsb.Length = vsb.RawChars.IndexOf('\0'); | ||
return vsb.ToString(); | ||
} | ||
} | ||
} | ||
|
||
// Deal with error | ||
int error = Marshal.GetLastWin32Error(); | ||
Debug.Assert(error != Interop.Errors.ERROR_INSUFFICIENT_BUFFER); | ||
throw Win32Marshal.GetExceptionForWin32Error(error, fileName); | ||
} | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SetEndOfFile.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using Microsoft.Win32.SafeHandles; | ||
using System.Runtime.InteropServices; | ||
|
||
internal static partial class Interop | ||
{ | ||
internal static partial class Kernel32 | ||
{ | ||
[LibraryImport(Libraries.Kernel32, SetLastError = true)] | ||
[return: MarshalAs(UnmanagedType.Bool)] | ||
internal static partial bool SetEndOfFile(SafeFileHandle hFile); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
43 changes: 43 additions & 0 deletions
43
src/libraries/System.IO.FileSystem/tests/File/Copy.Windows.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Runtime.InteropServices; | ||
using System.Security.Cryptography; | ||
using Xunit; | ||
|
||
namespace System.IO.Tests | ||
{ | ||
partial class File_Copy_Single | ||
{ | ||
[Fact] | ||
[PlatformSpecific(TestPlatforms.Windows)] | ||
public unsafe void WindowsCheckSparseness() | ||
{ | ||
string sourceFile = GetTestFilePath(); | ||
string destFile = GetTestFilePath(); | ||
|
||
File.WriteAllText(sourceFile, "abc"); | ||
File.WriteAllText(destFile, "def"); | ||
|
||
Assert.True((File.GetAttributes(sourceFile) & FileAttributes.SparseFile) == 0); | ||
File.Copy(sourceFile, destFile, true); | ||
Assert.True((File.GetAttributes(destFile) & FileAttributes.SparseFile) == 0); | ||
Assert.Equal("abc", File.ReadAllText(sourceFile)); | ||
|
||
using (FileStream file = File.Open(sourceFile, FileMode.Open)) | ||
{ | ||
Assert.True(Interop.Kernel32.DeviceIoControl(file.SafeFileHandle, Interop.Kernel32.FSCTL_SET_SPARSE, null, 0, null, 0, out _, 0)); | ||
} | ||
File.WriteAllText(destFile, "def"); | ||
|
||
Assert.True((File.GetAttributes(sourceFile) & FileAttributes.SparseFile) != 0); | ||
File.Copy(sourceFile, destFile, true); | ||
Assert.True((File.GetAttributes(destFile) & FileAttributes.SparseFile) != 0); | ||
Assert.Equal("abc", File.ReadAllText(sourceFile)); | ||
} | ||
|
||
// Todo: add a way to run all these on ReFS, and a test to check we actually cloned the reference, not just the data on ReFS. | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.