-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Clone files on OSX-like platforms when possible, instead of copying t…
…he whole file (#79243) Co-authored-by: Stephen Toub <[email protected]> Co-authored-by: Dan Moseley <[email protected]>
- Loading branch information
1 parent
90c5f05
commit 8fb25a8
Showing
5 changed files
with
131 additions
and
9 deletions.
There are no files selected for viewing
This file contains 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 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 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
92 changes: 92 additions & 0 deletions
92
src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.TryCloneFile.OSX.cs
This file contains 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,92 @@ | ||
// 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.Diagnostics; | ||
|
||
namespace System.IO | ||
{ | ||
internal static partial class FileSystem | ||
{ | ||
static partial void TryCloneFile(string sourceFullPath, string destFullPath, bool overwrite, ref bool cloned) | ||
{ | ||
// This helper function calls out to clonefile, and returns the error. | ||
static bool TryCloneFile(string sourceFullPath, string destFullPath, int flags, out Interop.Error error) | ||
{ | ||
if (Interop.@libc.clonefile(sourceFullPath, destFullPath, flags) == 0) | ||
{ | ||
// Success. | ||
error = Interop.Error.SUCCESS; | ||
return true; | ||
} | ||
|
||
error = Interop.Sys.GetLastError(); | ||
return false; | ||
} | ||
|
||
// Try to clone the file immediately, this will only succeed if the | ||
// destination doesn't exist, so we don't worry about locking for this one. | ||
int flags = Interop.@libc.CLONE_ACL; | ||
Interop.Error error; | ||
if (TryCloneFile(sourceFullPath, destFullPath, flags, out error)) | ||
{ | ||
cloned = true; | ||
return; | ||
} | ||
|
||
// Some filesystems don't support ACLs, so may fail due to trying to copy ACLs. | ||
// This will disable them and allow trying again (a maximum of 1 time). | ||
if (error == Interop.Error.EINVAL) | ||
{ | ||
flags = 0; | ||
if (TryCloneFile(sourceFullPath, destFullPath, flags, out error)) | ||
{ | ||
cloned = true; | ||
return; | ||
} | ||
} | ||
|
||
// Try to delete the destination file if we're overwriting. | ||
if (error == Interop.Error.EEXIST && overwrite) | ||
{ | ||
// Delete the destination. This should fail on directories. Get a lock to the dest file to ensure we don't copy onto it when | ||
// it's locked by something else, and then delete it. It should also fail if destination == source since it's already locked. | ||
try | ||
{ | ||
using SafeFileHandle? dstHandle = SafeFileHandle.Open(destFullPath, FileMode.Open, FileAccess.ReadWrite, | ||
FileShare.None, FileOptions.None, preallocationSize: 0, createOpenException: CreateOpenExceptionForCopyFile); | ||
if (Interop.Sys.Unlink(destFullPath) < 0 && | ||
Interop.Sys.GetLastError() != Interop.Error.ENOENT) | ||
{ | ||
// Fall back to standard copy as an unexpected error has occurred. | ||
return; | ||
} | ||
} | ||
catch (FileNotFoundException) | ||
{ | ||
// We don't want to throw if it's just the file not existing, since we're trying to delete it. | ||
} | ||
|
||
// Try clonefile now we've deleted the destination file. | ||
if (TryCloneFile(sourceFullPath, destFullPath, flags, out error)) | ||
{ | ||
cloned = true; | ||
return; | ||
} | ||
} | ||
|
||
if (error is Interop.Error.ENOTSUP // Check if it's not supported, | ||
or Interop.Error.EXDEV // if files are on different filesystems, | ||
or Interop.Error.EEXIST) // or if the destination file still exists. | ||
{ | ||
// Fall back to normal copy. | ||
return; | ||
} | ||
|
||
// Throw the appropriate exception. | ||
Debug.Assert(error != Interop.Error.EINVAL); // We shouldn't fail due to an invalid parameter. | ||
Debug.Assert(error != Interop.Error.SUCCESS); // We shouldn't fail with success. | ||
throw Interop.GetExceptionForIoErrno(error.Info(), destFullPath); | ||
} | ||
} | ||
} |
This file contains 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