зеркало из https://github.com/microsoft/BuildXL.git
Merged PR 711007: Move CopyOnWrite out of BuildXL.Native
Moving the CopyOnWrite functionality to a separate dll. This will also break the dependency to CopyOnWrite package to prevent a diamond dependency when Processes gets used externally
This commit is contained in:
Родитель
bf69e574f6
Коммит
11c66c7478
|
@ -39,6 +39,7 @@ namespace Library {
|
|||
importFrom("BuildXL.Utilities").KeyValueStore.dll,
|
||||
...importFrom("Sdk.Selfhost.RocksDbSharp").pkgs,
|
||||
importFrom("BuildXL.Utilities").Native.dll,
|
||||
importFrom("BuildXL.Utilities").Native.Extensions.dll,
|
||||
importFrom("BuildXL.Utilities").Configuration.dll,
|
||||
importFrom("BuildXL.Cache.DistributedCache.Host").Configuration.dll,
|
||||
...getGrpcPackages(true),
|
||||
|
|
|
@ -14,7 +14,6 @@ using BuildXL.Cache.ContentStore.Hashing;
|
|||
using BuildXL.Cache.ContentStore.Interfaces.Extensions;
|
||||
using BuildXL.Cache.ContentStore.Interfaces.FileSystem;
|
||||
using BuildXL.Cache.ContentStore.Interfaces.Logging;
|
||||
using BuildXL.Cache.ContentStore.UtilitiesCore;
|
||||
using BuildXL.Native.IO;
|
||||
using BuildXL.Utilities.Core;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
@ -130,9 +129,9 @@ namespace BuildXL.Cache.ContentStore.FileSystem
|
|||
|
||||
CreateDirectory(destinationPath.GetParent());
|
||||
|
||||
if (FileUtilities.IsCopyOnWriteSupportedByEnlistmentVolume)
|
||||
if (FileUtilitiesExtensions.IsCopyOnWriteSupportedByEnlistmentVolume)
|
||||
{
|
||||
var possiblyCreateCopyOnWrite = FileUtilities.TryCreateCopyOnWrite(sourcePath.Path, destinationPath.Path, followSymlink: false);
|
||||
var possiblyCreateCopyOnWrite = FileUtilitiesExtensions.TryCreateCopyOnWrite(sourcePath.Path, destinationPath.Path, followSymlink: false);
|
||||
if (possiblyCreateCopyOnWrite.Succeeded)
|
||||
{
|
||||
return;
|
||||
|
@ -432,7 +431,7 @@ namespace BuildXL.Cache.ContentStore.FileSystem
|
|||
|
||||
CreateDirectory(destinationPath.GetParent());
|
||||
|
||||
var possiblyCreateCopyOnWrite = FileUtilities.TryCreateCopyOnWrite(sourcePath.Path, destinationPath.Path, followSymlink: false);
|
||||
var possiblyCreateCopyOnWrite = FileUtilitiesExtensions.TryCreateCopyOnWrite(sourcePath.Path, destinationPath.Path, followSymlink: false);
|
||||
|
||||
return possiblyCreateCopyOnWrite.Succeeded;
|
||||
});
|
||||
|
@ -656,7 +655,7 @@ namespace BuildXL.Cache.ContentStore.FileSystem
|
|||
sourcePath.ThrowIfPathTooLong();
|
||||
destinationPath.ThrowIfPathTooLong();
|
||||
|
||||
if (FileUtilities.IsCopyOnWriteSupportedByEnlistmentVolume)
|
||||
if (FileUtilitiesExtensions.IsCopyOnWriteSupportedByEnlistmentVolume)
|
||||
{
|
||||
if (await TryCopyOnWriteFileInsideSemaphoreAsync(sourcePath, destinationPath, replaceExisting))
|
||||
{
|
||||
|
|
|
@ -130,6 +130,12 @@ namespace NugetPackages {
|
|||
importFrom("BuildXL.Utilities").withQualifier(net7PackageQualifier).Native.dll,
|
||||
importFrom("BuildXL.Utilities").withQualifier(netstandard20PackageQualifier).Native.dll,
|
||||
|
||||
// BuildXL.Native.Extensions
|
||||
importFrom("BuildXL.Utilities").withQualifier(net472packageQualifier).Native.Extensions.dll,
|
||||
importFrom("BuildXL.Utilities").withQualifier(net6PackageQualifier).Native.Extensions.dll,
|
||||
importFrom("BuildXL.Utilities").withQualifier(net7PackageQualifier).Native.Extensions.dll,
|
||||
importFrom("BuildXL.Utilities").withQualifier(netstandard20PackageQualifier).Native.Extensions.dll,
|
||||
|
||||
// BuildXL.Configuration
|
||||
importFrom("BuildXL.Utilities").withQualifier(net472packageQualifier).Configuration.dll,
|
||||
importFrom("BuildXL.Utilities").withQualifier(net6PackageQualifier).Configuration.dll,
|
||||
|
|
|
@ -44,6 +44,7 @@ namespace Engine {
|
|||
importFrom("BuildXL.Utilities").dll,
|
||||
importFrom("BuildXL.Utilities").Configuration.dll,
|
||||
importFrom("BuildXL.Utilities").Native.dll,
|
||||
importFrom("BuildXL.Utilities").Native.Extensions.dll,
|
||||
importFrom("BuildXL.Utilities").Interop.dll,
|
||||
importFrom("BuildXL.Utilities").Ipc.dll,
|
||||
importFrom("BuildXL.Utilities").Storage.dll,
|
||||
|
|
|
@ -874,7 +874,7 @@ namespace BuildXL.Engine
|
|||
FileShare.Read | FileShare.Delete))
|
||||
{
|
||||
FileUtilities.IsPreciseFileVersionSupportedByEnlistmentVolume = VersionedFileIdentity.HasPreciseFileVersion(configFileStream.SafeFileHandle);
|
||||
FileUtilities.IsCopyOnWriteSupportedByEnlistmentVolume = FileUtilities.CheckIfVolumeSupportsCopyOnWriteByHandle(configFileStream.SafeFileHandle);
|
||||
FileUtilitiesExtensions.IsCopyOnWriteSupportedByEnlistmentVolume = FileUtilitiesExtensions.CheckIfVolumeSupportsCopyOnWriteByHandle(configFileStream.SafeFileHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2217,7 +2217,7 @@ namespace BuildXL.Engine
|
|||
try
|
||||
{
|
||||
var sw = System.Diagnostics.Stopwatch.StartNew();
|
||||
var result = await FileUtilities.TryDuplicateOneFileAsync(sourcePath, destinationPath);
|
||||
var result = await FileUtilitiesExtensions.TryDuplicateOneFileAsync(sourcePath, destinationPath);
|
||||
|
||||
if (result == FileDuplicationResult.Copied)
|
||||
{
|
||||
|
|
|
@ -44,6 +44,7 @@ namespace Scheduler {
|
|||
importFrom("BuildXL.Utilities").Plugin.dll,
|
||||
importFrom("BuildXL.Utilities").KeyValueStore.dll,
|
||||
importFrom("BuildXL.Utilities").Native.dll,
|
||||
importFrom("BuildXL.Utilities").Native.Extensions.dll,
|
||||
importFrom("BuildXL.Utilities").Storage.dll,
|
||||
importFrom("BuildXL.Utilities").Utilities.Core.dll,
|
||||
importFrom("BuildXL.Utilities.Instrumentation").AriaCommon.dll,
|
||||
|
|
|
@ -16,7 +16,6 @@ using System.Text;
|
|||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BuildXL.Cache.ContentStore.Hashing;
|
||||
using BuildXL.Cache.ContentStore.Interfaces.Extensions;
|
||||
using BuildXL.Engine.Cache;
|
||||
using BuildXL.Engine.Cache.Artifacts;
|
||||
|
@ -741,7 +740,7 @@ namespace BuildXL.Scheduler
|
|||
|
||||
try
|
||||
{
|
||||
await FileUtilities.TryDuplicateOneFileAsync(sourcePath, destinationPath);
|
||||
await FileUtilitiesExtensions.TryDuplicateOneFileAsync(sourcePath, destinationPath);
|
||||
}
|
||||
catch (BuildXLException ex)
|
||||
{
|
||||
|
|
|
@ -21,7 +21,6 @@ using BuildXL.Utilities.Collections;
|
|||
using BuildXL.Utilities.Configuration;
|
||||
using BuildXL.Utilities.Instrumentation.Common;
|
||||
using BuildXL.Utilities.Core.Tasks;
|
||||
using BuildXL.Utilities.Tracing;
|
||||
using static BuildXL.Scheduler.Tracing.CacheMissAnalysisUtilities;
|
||||
using KVP = System.Collections.Generic.KeyValuePair<string, string>;
|
||||
using PipKVP = System.Collections.Generic.KeyValuePair<string, BuildXL.Scheduler.Tracing.FingerprintStore.PipFingerprintKeys>;
|
||||
|
@ -1753,9 +1752,9 @@ namespace BuildXL.Scheduler.Tracing
|
|||
// Assume if the first hard link fails, all the hard links will fail
|
||||
if (!hardLinkFailureSeen)
|
||||
{
|
||||
if (FileUtilities.IsCopyOnWriteSupportedByEnlistmentVolume)
|
||||
if (FileUtilitiesExtensions.IsCopyOnWriteSupportedByEnlistmentVolume)
|
||||
{
|
||||
var possiblyCreateCopyOnWrite = FileUtilities.TryCreateCopyOnWrite(storeFile, logFile, followSymlink: false);
|
||||
var possiblyCreateCopyOnWrite = FileUtilitiesExtensions.TryCreateCopyOnWrite(storeFile, logFile, followSymlink: false);
|
||||
|
||||
if (possiblyCreateCopyOnWrite.Succeeded)
|
||||
{
|
||||
|
|
|
@ -668,11 +668,11 @@ namespace Test.BuildXL.EngineTestUtilities
|
|||
|
||||
private Task<bool> CopyFileInternalAsync(string source, string destination)
|
||||
{
|
||||
if (FileUtilities.IsCopyOnWriteSupportedByEnlistmentVolume)
|
||||
if (FileUtilitiesExtensions.IsCopyOnWriteSupportedByEnlistmentVolume)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
var possiblyCreateCopyOnWrite = FileUtilities.TryCreateCopyOnWrite(source, destination, followSymlink: false);
|
||||
var possiblyCreateCopyOnWrite = FileUtilitiesExtensions.TryCreateCopyOnWrite(source, destination, followSymlink: false);
|
||||
|
||||
if (!possiblyCreateCopyOnWrite.Succeeded)
|
||||
{
|
||||
|
|
|
@ -22,6 +22,7 @@ namespace EngineTestUtilities {
|
|||
importFrom("BuildXL.Utilities").dll,
|
||||
importFrom("BuildXL.Utilities").Configuration.dll,
|
||||
importFrom("BuildXL.Utilities").Native.dll,
|
||||
importFrom("BuildXL.Utilities").Native.Extensions.dll,
|
||||
importFrom("BuildXL.Utilities").Ipc.dll,
|
||||
importFrom("BuildXL.Utilities").Ipc.Providers.dll,
|
||||
importFrom("BuildXL.Utilities").Storage.dll,
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace Native.Extensions {
|
||||
@@public
|
||||
export const dll = BuildXLSdk.library({
|
||||
assemblyName: "BuildXL.Native.Extensions",
|
||||
sources: globR(d`.`, "*.cs"),
|
||||
nullable: true,
|
||||
references: [
|
||||
Native.dll,
|
||||
Interop.dll,
|
||||
Utilities.Core.dll,
|
||||
importFrom("CopyOnWrite").pkg,
|
||||
],
|
||||
});
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using BuildXL.Utilities.Core;
|
||||
using BuildXL.Utilities.Core.Tasks;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using static BuildXL.Interop.Unix.IO;
|
||||
using static BuildXL.Native.IO.FileUtilities;
|
||||
using static BuildXL.Utilities.Core.FormattableStringEx;
|
||||
|
||||
namespace BuildXL.Native.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// FileSystem related native implementations for Unix based systems
|
||||
/// </summary>
|
||||
internal sealed class FileSystemExtensionsUnix : IFileSystemExtensions
|
||||
{
|
||||
private Lazy<bool> m_supportCopyOnWrite = new Lazy<bool>(() => SupportsCopyOnWrite());
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsCopyOnWriteSupportedByEnlistmentVolume
|
||||
{
|
||||
get => m_supportCopyOnWrite.Value;
|
||||
set => m_supportCopyOnWrite = new Lazy<bool>(() => value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public static bool CheckIfVolumeSupportsCopyOnWriteByHandle(SafeFileHandle fileHandle)
|
||||
{
|
||||
try
|
||||
{
|
||||
return GetVolumeFileSystemByHandle(fileHandle) == FileSystemType.APFS;
|
||||
}
|
||||
catch (NativeWin32Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Possible<Unit> CloneFile(string source, string destination, bool followSymlink)
|
||||
{
|
||||
var flags = followSymlink ? CloneFileFlags.CLONE_NONE : CloneFileFlags.CLONE_NOFOLLOW;
|
||||
int result = Interop.Unix.IO.CloneFile(source, destination, flags);
|
||||
if (result != 0)
|
||||
{
|
||||
return new NativeFailure(Marshal.GetLastWin32Error(), I($"Failed to clone '{source}' to '{destination}'"));
|
||||
}
|
||||
|
||||
return Unit.Void;
|
||||
}
|
||||
|
||||
private static bool SupportsCopyOnWrite()
|
||||
{
|
||||
// Use temp file name as an approximation whether file system supports copy-on-write.
|
||||
string path = FileUtilities.GetTempFileName();
|
||||
bool result = false;
|
||||
|
||||
using (var fileStream = CreateFileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete, FileOptions.None, false))
|
||||
{
|
||||
result = CheckIfVolumeSupportsCopyOnWriteByHandle(fileStream.SafeFileHandle);
|
||||
}
|
||||
|
||||
File.Delete(path);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using BuildXL.Utilities.Core;
|
||||
using BuildXL.Utilities.Core.Tasks;
|
||||
using Microsoft.CopyOnWrite;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using static BuildXL.Native.IO.FileUtilities;
|
||||
|
||||
namespace BuildXL.Native.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// FileSystem related native implementations for Windows based systems
|
||||
/// </summary>
|
||||
internal sealed class FileSystemExtensionsWin : IFileSystemExtensions
|
||||
{
|
||||
private Lazy<bool> m_supportCopyOnWrite = new Lazy<bool>(() => SupportsCopyOnWrite());
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsCopyOnWriteSupportedByEnlistmentVolume
|
||||
{
|
||||
get => m_supportCopyOnWrite.Value;
|
||||
set => m_supportCopyOnWrite = new Lazy<bool>(() => value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public static bool CheckIfVolumeSupportsCopyOnWriteByHandle(SafeFileHandle fileHandle)
|
||||
{
|
||||
#if NETCOREAPP
|
||||
try
|
||||
{
|
||||
return GetVolumeFileSystemByHandle(fileHandle) == FileSystemType.ReFS;
|
||||
}
|
||||
catch (NativeWin32Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
public Possible<Unit> CloneFile(string source, string destination, bool followSymlink)
|
||||
{
|
||||
#if NETCOREAPP
|
||||
try
|
||||
{
|
||||
// NoFileIntegrityCheck: Cache does not use Windows file integrity.
|
||||
// PathIsFullyResolved: No need for CoW library to do Path.GetFullPath() again, full paths are provided from PathTable.
|
||||
ICopyOnWriteFilesystem cow = CopyOnWriteFilesystemFactory.GetInstance();
|
||||
cow.CloneFile(source, destination, CloneFlags.NoFileIntegrityCheck | CloneFlags.PathIsFullyResolved);
|
||||
}
|
||||
catch (NotSupportedException ex)
|
||||
{
|
||||
return new Failure<string>(ex.Message);
|
||||
}
|
||||
|
||||
return Unit.Void;
|
||||
#else
|
||||
throw new NotImplementedException();
|
||||
#endif
|
||||
}
|
||||
|
||||
private static bool SupportsCopyOnWrite()
|
||||
{
|
||||
#if NETCOREAPP
|
||||
bool disableCopyOnWrite = string.Equals(Environment.GetEnvironmentVariable("DisableCopyOnWriteWin"), "1", StringComparison.Ordinal);
|
||||
|
||||
if (disableCopyOnWrite)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string workingDir = Environment.CurrentDirectory;
|
||||
OpenFileResult directoryOpenResult = TryOpenDirectory(
|
||||
workingDir,
|
||||
FileShare.ReadWrite | FileShare.Delete,
|
||||
out SafeFileHandle directoryHandle);
|
||||
|
||||
if (directoryOpenResult.Succeeded)
|
||||
{
|
||||
using (directoryHandle)
|
||||
{
|
||||
return CheckIfVolumeSupportsCopyOnWriteByHandle(directoryHandle);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System.Diagnostics.ContractsLight;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using BuildXL.Utilities.Core;
|
||||
using BuildXL.Utilities.Core.Tasks;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace BuildXL.Native.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension for FileUtilities.
|
||||
/// </summary>
|
||||
public static class FileUtilitiesExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// A platform specific concrete implementation of the file system layer functions
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When running on Windows but inside the CoreCLR, we use the same concrete implementation
|
||||
/// as the vanilla BuildXL build for Windows and skip Unix implementations completely
|
||||
/// </remarks>
|
||||
private static readonly IFileSystemExtensions s_fileSystemExtensions = OperatingSystemHelper.IsUnixOS
|
||||
? new FileSystemExtensionsWin()
|
||||
: new FileSystemExtensionsUnix();
|
||||
|
||||
/// <see cref="IFileSystemExtensions.IsCopyOnWriteSupportedByEnlistmentVolume"/>
|
||||
public static bool IsCopyOnWriteSupportedByEnlistmentVolume
|
||||
{
|
||||
get => s_fileSystemExtensions.IsCopyOnWriteSupportedByEnlistmentVolume;
|
||||
set => s_fileSystemExtensions.IsCopyOnWriteSupportedByEnlistmentVolume = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a file system volume supports copy on write.
|
||||
/// </summary>
|
||||
/// <param name="fileHandle"></param>
|
||||
/// <returns>true iff copy on write is supported</returns>
|
||||
public static bool CheckIfVolumeSupportsCopyOnWriteByHandle(SafeFileHandle fileHandle) => OperatingSystemHelper.IsUnixOS
|
||||
? FileSystemExtensionsUnix.CheckIfVolumeSupportsCopyOnWriteByHandle(fileHandle)
|
||||
: FileSystemExtensionsWin.CheckIfVolumeSupportsCopyOnWriteByHandle(fileHandle);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to create copy-on-write by calling <see cref="IFileSystemExtensions.CloneFile(string, string, bool)"/>.
|
||||
/// </summary>
|
||||
/// <param name="source">Source of copy.</param>
|
||||
/// <param name="destination">Destination path.</param>
|
||||
/// <param name="followSymlink">Flag indicating whether to follow source symlink or not.</param>
|
||||
public static Possible<Unit> TryCreateCopyOnWrite(string source, string destination, bool followSymlink)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (FileUtilities.Counters?.StartStopwatch(StorageCounters.CopyOnWriteDuration))
|
||||
{
|
||||
FileUtilities.Counters?.IncrementCounter(StorageCounters.CopyOnWriteCount);
|
||||
Possible<Unit> result = s_fileSystemExtensions.CloneFile(source, destination, followSymlink);
|
||||
|
||||
if (result.Succeeded)
|
||||
{
|
||||
FileUtilities.Counters?.IncrementCounter(StorageCounters.SuccessfulCopyOnWriteCount);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
catch (NativeWin32Exception ex)
|
||||
{
|
||||
return NativeFailure.CreateFromException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to duplicate a file.
|
||||
/// </summary>
|
||||
public static Task<FileDuplicationResult> TryDuplicateOneFileAsync(string sourcePath, string destinationPath)
|
||||
{
|
||||
Contract.Requires(!string.IsNullOrWhiteSpace(sourcePath));
|
||||
Contract.Requires(!string.IsNullOrWhiteSpace(destinationPath));
|
||||
|
||||
if (string.Compare(sourcePath, destinationPath, OperatingSystemHelper.PathComparison) == 0)
|
||||
{
|
||||
return Task.FromResult(FileDuplicationResult.Existed); // Nothing to do.
|
||||
}
|
||||
|
||||
return ExceptionUtilities.HandleRecoverableIOExceptionAsync(
|
||||
async () =>
|
||||
{
|
||||
var destinationDirectory = Path.GetDirectoryName(destinationPath);
|
||||
if (FileUtilities.DirectoryExistsNoFollow(destinationDirectory))
|
||||
{
|
||||
if (FileUtilities.FileExistsNoFollow(destinationPath))
|
||||
{
|
||||
FileUtilities.DeleteFile(destinationPath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FileUtilities.CreateDirectory(destinationDirectory);
|
||||
}
|
||||
|
||||
if (!OperatingSystemHelper.IsUnixOS)
|
||||
{
|
||||
var hardlinkResult = FileUtilities.OsFileSystem.TryCreateHardLinkViaSetInformationFile(destinationPath, sourcePath);
|
||||
|
||||
if (hardlinkResult == CreateHardLinkStatus.Success)
|
||||
{
|
||||
return FileDuplicationResult.Hardlinked;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsCopyOnWriteSupportedByEnlistmentVolume)
|
||||
{
|
||||
var possiblyCreateCopyOnWrite = TryCreateCopyOnWrite(sourcePath, destinationPath, followSymlink: false);
|
||||
if (possiblyCreateCopyOnWrite.Succeeded)
|
||||
{
|
||||
return FileDuplicationResult.Copied;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await FileUtilities.CopyFileAsync(sourcePath, destinationPath);
|
||||
return FileDuplicationResult.Copied;
|
||||
},
|
||||
ex => { throw new BuildXLException(ex.Message); });
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using BuildXL.Utilities.Core;
|
||||
using BuildXL.Utilities.Core.Tasks;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace BuildXL.Native.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for file system related functions and calls
|
||||
/// </summary>
|
||||
internal interface IFileSystemExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Flag indicating if the enlistment volume supports copy on write.
|
||||
/// </summary>
|
||||
bool IsCopyOnWriteSupportedByEnlistmentVolume { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy on write clone of files if supported by the underlying OS.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method must be implemented if <see cref="IsCopyOnWriteSupportedByEnlistmentVolume"/> returns true.
|
||||
/// </remarks>
|
||||
/// <exception cref="NativeWin32Exception">Throw native exception upon failure.</exception>
|
||||
Possible<Unit> CloneFile(string source, string destination, bool followSymlink);
|
||||
}
|
||||
}
|
|
@ -63,10 +63,12 @@ namespace Native {
|
|||
generateLogs: true,
|
||||
addNotNullAttributeFile: true,
|
||||
references: [
|
||||
// IMPORTANT!!! Do not add non-bxl dependencies or any bxl projects with external dependencies into this project
|
||||
// any non-bxl dependencies should go to BuildXL.Native.Extensions instead
|
||||
|
||||
Interop.dll,
|
||||
...securityDlls,
|
||||
Utilities.Core.dll,
|
||||
importFrom("CopyOnWrite").pkg,
|
||||
],
|
||||
runtimeContent: [
|
||||
...nativeMac,
|
||||
|
@ -74,6 +76,7 @@ namespace Native {
|
|||
...nativeLinux,
|
||||
],
|
||||
internalsVisibleTo: [
|
||||
"BuildXL.Native.Extensions",
|
||||
"BuildXL.Processes",
|
||||
"BuildXL.ProcessPipExecutor",
|
||||
"Test.BuildXL.Storage",
|
||||
|
|
|
@ -50,9 +50,9 @@ namespace BuildXL.Native.IO
|
|||
/// When running on Windows but inside the CoreCLR, we use the same concrete implementation
|
||||
/// as the vanilla BuildXL build for Windows and skip Unix implementations completely
|
||||
/// </remarks>
|
||||
private static readonly IFileUtilities s_fileUtilities = OperatingSystemHelper.IsUnixOS
|
||||
? (IFileUtilities)new Unix.FileUtilitiesUnix()
|
||||
: (IFileUtilities)new Windows.FileUtilitiesWin(LoggingContext);
|
||||
internal static readonly IFileUtilities OsFileUtilities = OperatingSystemHelper.IsUnixOS
|
||||
? new Unix.FileUtilitiesUnix()
|
||||
: new Windows.FileUtilitiesWin(LoggingContext);
|
||||
|
||||
/// <summary>
|
||||
/// A platform specific concrete implementation of the file system layer functions
|
||||
|
@ -61,9 +61,9 @@ namespace BuildXL.Native.IO
|
|||
/// When running on Windows but inside the CoreCLR, we use the same concrete implementation
|
||||
/// as the vanilla BuildXL build for Windows and skip Unix implementations completely
|
||||
/// </remarks>
|
||||
private static readonly IFileSystem s_fileSystem = OperatingSystemHelper.IsUnixOS
|
||||
? ((Unix.FileUtilitiesUnix)s_fileUtilities).FileSystem
|
||||
: ((Windows.FileUtilitiesWin)s_fileUtilities).FileSystem;
|
||||
internal static readonly IFileSystem OsFileSystem = OperatingSystemHelper.IsUnixOS
|
||||
? ((Unix.FileUtilitiesUnix)OsFileUtilities).FileSystem
|
||||
: ((Windows.FileUtilitiesWin)OsFileUtilities).FileSystem;
|
||||
|
||||
/// <summary>
|
||||
/// Directory separator as string.
|
||||
|
@ -107,7 +107,7 @@ namespace BuildXL.Native.IO
|
|||
public static void CreateDirectory(string path)
|
||||
{
|
||||
Contract.Requires(!string.IsNullOrEmpty(path));
|
||||
s_fileSystem.CreateDirectory(path);
|
||||
OsFileSystem.CreateDirectory(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -136,13 +136,13 @@ namespace BuildXL.Native.IO
|
|||
/// <see cref="IFileSystem.RemoveDirectory(string)"/>
|
||||
public static void RemoveDirectory(string path)
|
||||
{
|
||||
s_fileSystem.RemoveDirectory(path);
|
||||
OsFileSystem.RemoveDirectory(path);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.TryRemoveDirectory(string, out int)"/>
|
||||
public static bool TryRemoveDirectory(string path, out int hr)
|
||||
{
|
||||
return s_fileSystem.TryRemoveDirectory(path, out hr);
|
||||
return OsFileSystem.TryRemoveDirectory(path, out hr);
|
||||
}
|
||||
|
||||
/// <see cref="IFileUtilities.DeleteDirectoryContents(string, bool, Func{string, bool, bool}, ITempCleaner, bool, CancellationToken?)"/>
|
||||
|
@ -153,7 +153,7 @@ namespace BuildXL.Native.IO
|
|||
ITempCleaner tempDirectoryCleaner = null,
|
||||
bool bestEffort = false,
|
||||
CancellationToken? cancellationToken = default) =>
|
||||
s_fileUtilities.DeleteDirectoryContents(path, deleteRootDirectory, shouldDelete, tempDirectoryCleaner, bestEffort, cancellationToken);
|
||||
OsFileUtilities.DeleteDirectoryContents(path, deleteRootDirectory, shouldDelete, tempDirectoryCleaner, bestEffort, cancellationToken);
|
||||
|
||||
/// <see cref="IFileSystem.EnumerateDirectoryEntries(string, bool, Action{string, string, FileAttributes}, bool)"/>
|
||||
public static EnumerateDirectoryResult EnumerateDirectoryEntries(
|
||||
|
@ -161,7 +161,7 @@ namespace BuildXL.Native.IO
|
|||
bool recursive,
|
||||
Action<string, string, FileAttributes> handleEntry)
|
||||
{
|
||||
return s_fileSystem.EnumerateDirectoryEntries(directoryPath, recursive, handleEntry);
|
||||
return OsFileSystem.EnumerateDirectoryEntries(directoryPath, recursive, handleEntry);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.EnumerateDirectoryEntries(string, bool, string, Action{string, string, FileAttributes}, bool, bool)"/>
|
||||
|
@ -171,7 +171,7 @@ namespace BuildXL.Native.IO
|
|||
string pattern,
|
||||
Action<string, string, FileAttributes> handleEntry)
|
||||
{
|
||||
return s_fileSystem.EnumerateDirectoryEntries(directoryPath, recursive, pattern, handleEntry, followSymlinksToDirectories: true);
|
||||
return OsFileSystem.EnumerateDirectoryEntries(directoryPath, recursive, pattern, handleEntry, followSymlinksToDirectories: true);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.EnumerateFiles(string, bool, string, Action{string, string, FileAttributes, long})"/>
|
||||
|
@ -181,7 +181,7 @@ namespace BuildXL.Native.IO
|
|||
string pattern,
|
||||
Action<string /*filePath*/, string /*fileName*/, FileAttributes /*attributes*/, long /*fileSize*/> handleFileEntry)
|
||||
{
|
||||
return s_fileSystem.EnumerateFiles(directoryPath, recursive, pattern, handleFileEntry);
|
||||
return OsFileSystem.EnumerateFiles(directoryPath, recursive, pattern, handleFileEntry);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.EnumerateDirectoryEntries(string, Action{string, FileAttributes}, bool)"/>
|
||||
|
@ -199,12 +199,12 @@ namespace BuildXL.Native.IO
|
|||
bool recursive,
|
||||
IDirectoryEntriesAccumulator accumulators)
|
||||
{
|
||||
return s_fileSystem.EnumerateDirectoryEntries(directoryPath, enumerateDirectory, pattern, directoriesToSkipRecursively, recursive, accumulators);
|
||||
return OsFileSystem.EnumerateDirectoryEntries(directoryPath, enumerateDirectory, pattern, directoriesToSkipRecursively, recursive, accumulators);
|
||||
}
|
||||
|
||||
/// <see cref="IFileUtilities.FindAllOpenHandlesInDirectory(string, HashSet{string},Func{String, bool, bool})"/>
|
||||
public static string FindAllOpenHandlesInDirectory(string directoryPath, HashSet<string> pathsPossiblyPendingDelete = null) =>
|
||||
s_fileUtilities.FindAllOpenHandlesInDirectory(directoryPath, pathsPossiblyPendingDelete);
|
||||
OsFileUtilities.FindAllOpenHandlesInDirectory(directoryPath, pathsPossiblyPendingDelete);
|
||||
|
||||
/// <see cref="IFileSystem.TryOpenDirectory(string, FileDesiredAccess, FileShare, FileFlagsAndAttributes, out SafeFileHandle)"/>
|
||||
public static OpenFileResult TryOpenDirectory(
|
||||
|
@ -214,13 +214,13 @@ namespace BuildXL.Native.IO
|
|||
FileFlagsAndAttributes flagsAndAttributes,
|
||||
out SafeFileHandle handle)
|
||||
{
|
||||
return s_fileSystem.TryOpenDirectory(directoryPath, desiredAccess, shareMode, flagsAndAttributes, out handle);
|
||||
return OsFileSystem.TryOpenDirectory(directoryPath, desiredAccess, shareMode, flagsAndAttributes, out handle);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.TryOpenDirectory(string, FileShare, out SafeFileHandle)"/>
|
||||
public static OpenFileResult TryOpenDirectory(string directoryPath, FileShare shareMode, out SafeFileHandle handle)
|
||||
{
|
||||
return s_fileSystem.TryOpenDirectory(directoryPath, shareMode, out handle);
|
||||
return OsFileSystem.TryOpenDirectory(directoryPath, shareMode, out handle);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -232,42 +232,13 @@ namespace BuildXL.Native.IO
|
|||
string source,
|
||||
string destination,
|
||||
Func<SafeFileHandle, SafeFileHandle, bool> predicate = null,
|
||||
Action<SafeFileHandle, SafeFileHandle> onCompletion = null) => s_fileUtilities.CopyFileAsync(source, destination, predicate, onCompletion);
|
||||
Action<SafeFileHandle, SafeFileHandle> onCompletion = null) => OsFileUtilities.CopyFileAsync(source, destination, predicate, onCompletion);
|
||||
|
||||
/// <see cref="IFileUtilities.MoveFileAsync(string, string, bool)"/>
|
||||
public static Task MoveFileAsync(
|
||||
string source,
|
||||
string destination,
|
||||
bool replaceExisting = false) => s_fileUtilities.MoveFileAsync(source, destination, replaceExisting);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to create copy-on-write by calling <see cref="IFileUtilities.CloneFile(string, string, bool)"/>.
|
||||
/// </summary>
|
||||
/// <param name="source">Source of copy.</param>
|
||||
/// <param name="destination">Destination path.</param>
|
||||
/// <param name="followSymlink">Flag indicating whether to follow source symlink or not.</param>
|
||||
public static Possible<Unit> TryCreateCopyOnWrite(string source, string destination, bool followSymlink)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (Counters?.StartStopwatch(StorageCounters.CopyOnWriteDuration))
|
||||
{
|
||||
Counters?.IncrementCounter(StorageCounters.CopyOnWriteCount);
|
||||
Possible<Unit> result = s_fileUtilities.CloneFile(source, destination, followSymlink);
|
||||
|
||||
if (result.Succeeded)
|
||||
{
|
||||
Counters?.IncrementCounter(StorageCounters.SuccessfulCopyOnWriteCount);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
catch (NativeWin32Exception ex)
|
||||
{
|
||||
return NativeFailure.CreateFromException(ex);
|
||||
}
|
||||
}
|
||||
bool replaceExisting = false) => OsFileUtilities.MoveFileAsync(source, destination, replaceExisting);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to copy using <see cref="IFileUtilities.InKernelFileCopy(string, string, bool)"/>.
|
||||
|
@ -279,7 +250,7 @@ namespace BuildXL.Native.IO
|
|||
using (Counters?.StartStopwatch(StorageCounters.InKernelFileCopyDuration))
|
||||
{
|
||||
Counters?.IncrementCounter(StorageCounters.InKernelFileCopyCount);
|
||||
Possible<Unit> result = s_fileUtilities.InKernelFileCopy(source, destination, followSymlink);
|
||||
Possible<Unit> result = OsFileUtilities.InKernelFileCopy(source, destination, followSymlink);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
Counters?.IncrementCounter(StorageCounters.SuccessfulInKernelFileCopyCount);
|
||||
|
@ -303,17 +274,17 @@ namespace BuildXL.Native.IO
|
|||
string path,
|
||||
FileShare fileShare,
|
||||
bool openAsync = true,
|
||||
bool allowExcludeFileShareDelete = false) => s_fileUtilities.CreateReplacementFile(path, fileShare, openAsync, allowExcludeFileShareDelete);
|
||||
bool allowExcludeFileShareDelete = false) => OsFileUtilities.CreateReplacementFile(path, fileShare, openAsync, allowExcludeFileShareDelete);
|
||||
|
||||
/// <see cref="IFileUtilities.DeleteFile(string, bool, ITempCleaner)"/>
|
||||
public static void DeleteFile(string path, bool retryOnFailure = true, ITempCleaner tempDirectoryCleaner = null) =>
|
||||
s_fileUtilities.DeleteFile(path, retryOnFailure, tempDirectoryCleaner);
|
||||
OsFileUtilities.DeleteFile(path, retryOnFailure, tempDirectoryCleaner);
|
||||
|
||||
/// <see cref="IFileUtilities.PosixDeleteMode"/>
|
||||
public static PosixDeleteMode PosixDeleteMode
|
||||
{
|
||||
get { return s_fileUtilities.PosixDeleteMode; }
|
||||
set { s_fileUtilities.PosixDeleteMode = value; }
|
||||
get { return OsFileUtilities.PosixDeleteMode; }
|
||||
set { OsFileUtilities.PosixDeleteMode = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -324,25 +295,25 @@ namespace BuildXL.Native.IO
|
|||
{
|
||||
get
|
||||
{
|
||||
return s_fileUtilities.PosixDeleteMode == PosixDeleteMode.NoRun;
|
||||
return OsFileUtilities.PosixDeleteMode == PosixDeleteMode.NoRun;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
s_fileUtilities.PosixDeleteMode = PosixDeleteMode.NoRun;
|
||||
OsFileUtilities.PosixDeleteMode = PosixDeleteMode.NoRun;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_fileUtilities.PosixDeleteMode = PosixDeleteMode.RunFirst;
|
||||
OsFileUtilities.PosixDeleteMode = PosixDeleteMode.RunFirst;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <see cref="IFileUtilities.TryDeleteFile(string, bool, ITempCleaner)"/>
|
||||
public static Possible<string, DeletionFailure> TryDeleteFile(string path, bool retryOnFailure = true, ITempCleaner tempDirectoryCleaner = null) =>
|
||||
s_fileUtilities.TryDeleteFile(path, retryOnFailure, tempDirectoryCleaner);
|
||||
OsFileUtilities.TryDeleteFile(path, retryOnFailure, tempDirectoryCleaner);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to delete file or directory if exists.
|
||||
|
@ -437,44 +408,44 @@ namespace BuildXL.Native.IO
|
|||
}
|
||||
|
||||
/// <see cref="IFileUtilities.TryMoveDelete(string, string)"/>
|
||||
public static bool TryMoveDelete(string path, string deletionTempDirectory) => s_fileUtilities.TryMoveDelete(path, deletionTempDirectory);
|
||||
public static bool TryMoveDelete(string path, string deletionTempDirectory) => OsFileUtilities.TryMoveDelete(path, deletionTempDirectory);
|
||||
|
||||
/// <see cref="IFileUtilities.GetFileName(string)"/>
|
||||
public static Possible<string> GetFileName(string path) => s_fileUtilities.GetFileName(path);
|
||||
public static Possible<string> GetFileName(string path) => OsFileUtilities.GetFileName(path);
|
||||
|
||||
/// <see cref="IFileUtilities.GetFileTimestamps"/>
|
||||
public static FileTimestamps GetFileTimestamps(string path, bool followSymlink = false)
|
||||
=> s_fileUtilities.GetFileTimestamps(path, followSymlink);
|
||||
=> OsFileUtilities.GetFileTimestamps(path, followSymlink);
|
||||
|
||||
/// <see cref="IFileUtilities.SetFileTimestamps"/>
|
||||
public static void SetFileTimestamps(string path, FileTimestamps timestamps, bool followSymlink = false)
|
||||
=> s_fileUtilities.SetFileTimestamps(path, timestamps, followSymlink);
|
||||
=> OsFileUtilities.SetFileTimestamps(path, timestamps, followSymlink);
|
||||
|
||||
/// <see cref="IFileUtilities.WriteAllTextAsync(string, string, Encoding)"/>
|
||||
public static Task WriteAllTextAsync(
|
||||
string filePath,
|
||||
string text,
|
||||
Encoding encoding) => s_fileUtilities.WriteAllTextAsync(filePath, text, encoding);
|
||||
Encoding encoding) => OsFileUtilities.WriteAllTextAsync(filePath, text, encoding);
|
||||
|
||||
/// <see cref="IFileUtilities.WriteAllBytesAsync(string, byte[], Func{SafeFileHandle, bool}, Action{SafeFileHandle})"/>
|
||||
public static Task<bool> WriteAllBytesAsync(
|
||||
string filePath,
|
||||
byte[] bytes,
|
||||
Func<SafeFileHandle, bool> predicate = null,
|
||||
Action<SafeFileHandle> onCompletion = null) => s_fileUtilities.WriteAllBytesAsync(filePath, bytes, predicate, onCompletion);
|
||||
Action<SafeFileHandle> onCompletion = null) => OsFileUtilities.WriteAllBytesAsync(filePath, bytes, predicate, onCompletion);
|
||||
|
||||
/// <see cref="IFileUtilities.TryFindOpenHandlesToFile"/>
|
||||
public static bool TryFindOpenHandlesToFile(string filePath, out string diagnosticInfo, bool printCurrentFilePath = true)
|
||||
=> s_fileUtilities.TryFindOpenHandlesToFile(filePath, out diagnosticInfo, printCurrentFilePath);
|
||||
=> OsFileUtilities.TryFindOpenHandlesToFile(filePath, out diagnosticInfo, printCurrentFilePath);
|
||||
|
||||
/// <see cref="IFileUtilities.GetHardLinkCount(string)"/>
|
||||
public static uint GetHardLinkCount(string path) => s_fileUtilities.GetHardLinkCount(path);
|
||||
public static uint GetHardLinkCount(string path) => OsFileUtilities.GetHardLinkCount(path);
|
||||
|
||||
/// <see cref="IFileUtilities.HasWritableAccessControl(string)"/>
|
||||
public static bool HasWritableAccessControl(string path) => s_fileUtilities.HasWritableAccessControl(path);
|
||||
public static bool HasWritableAccessControl(string path) => OsFileUtilities.HasWritableAccessControl(path);
|
||||
|
||||
/// <see cref="IFileUtilities.HasWritableAttributeAccessControl(string)"/>
|
||||
public static bool HasWritableAttributeAccessControl(string path) => s_fileUtilities.HasWritableAttributeAccessControl(path);
|
||||
public static bool HasWritableAttributeAccessControl(string path) => OsFileUtilities.HasWritableAttributeAccessControl(path);
|
||||
|
||||
/// <see cref="IFileUtilities.CreateFileStream(string, FileMode, FileAccess, FileShare, FileOptions, bool, bool)"/>
|
||||
public static FileStream CreateFileStream(
|
||||
|
@ -486,7 +457,7 @@ namespace BuildXL.Native.IO
|
|||
bool force = false,
|
||||
bool allowExcludeFileShareDelete = false)
|
||||
{
|
||||
return s_fileUtilities.CreateFileStream(path, fileMode, fileAccess, fileShare, options, force, allowExcludeFileShareDelete);
|
||||
return OsFileUtilities.CreateFileStream(path, fileMode, fileAccess, fileShare, options, force, allowExcludeFileShareDelete);
|
||||
}
|
||||
|
||||
/// <see cref="IFileUtilities.CreateAsyncFileStream(string, FileMode, FileAccess, FileShare, FileOptions, bool, bool)"/>
|
||||
|
@ -499,7 +470,7 @@ namespace BuildXL.Native.IO
|
|||
bool force = false,
|
||||
bool allowExcludeFileShareDelete = false)
|
||||
{
|
||||
return s_fileUtilities.CreateAsyncFileStream(path, fileMode, fileAccess, fileShare, options, force, allowExcludeFileShareDelete);
|
||||
return OsFileUtilities.CreateAsyncFileStream(path, fileMode, fileAccess, fileShare, options, force, allowExcludeFileShareDelete);
|
||||
}
|
||||
|
||||
/// <see cref="IFileUtilities.UsingFileHandleAndFileLength"/>
|
||||
|
@ -511,7 +482,7 @@ namespace BuildXL.Native.IO
|
|||
FileFlagsAndAttributes flagsAndAttributes,
|
||||
Func<SafeFileHandle, long, TResult> handleStream)
|
||||
=>
|
||||
s_fileUtilities.UsingFileHandleAndFileLength(
|
||||
OsFileUtilities.UsingFileHandleAndFileLength(
|
||||
path,
|
||||
desiredAccess,
|
||||
shareMode,
|
||||
|
@ -519,62 +490,6 @@ namespace BuildXL.Native.IO
|
|||
flagsAndAttributes,
|
||||
handleStream);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to duplicate a file.
|
||||
/// </summary>
|
||||
public static Task<FileDuplicationResult> TryDuplicateOneFileAsync(string sourcePath, string destinationPath)
|
||||
{
|
||||
Contract.Requires(!string.IsNullOrWhiteSpace(sourcePath));
|
||||
Contract.Requires(!string.IsNullOrWhiteSpace(destinationPath));
|
||||
|
||||
if (string.Compare(sourcePath, destinationPath, OperatingSystemHelper.PathComparison) == 0)
|
||||
{
|
||||
return Task.FromResult(FileDuplicationResult.Existed); // Nothing to do.
|
||||
}
|
||||
|
||||
return ExceptionUtilities.HandleRecoverableIOExceptionAsync(
|
||||
async () =>
|
||||
{
|
||||
var destinationDirectory = Path.GetDirectoryName(destinationPath);
|
||||
if (DirectoryExistsNoFollow(destinationDirectory))
|
||||
{
|
||||
if (FileExistsNoFollow(destinationPath))
|
||||
{
|
||||
DeleteFile(destinationPath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateDirectory(destinationDirectory);
|
||||
}
|
||||
|
||||
if (!OperatingSystemHelper.IsUnixOS)
|
||||
{
|
||||
var hardlinkResult = s_fileSystem.TryCreateHardLinkViaSetInformationFile(destinationPath, sourcePath);
|
||||
|
||||
if (hardlinkResult == CreateHardLinkStatus.Success)
|
||||
{
|
||||
return FileDuplicationResult.Hardlinked;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsCopyOnWriteSupportedByEnlistmentVolume)
|
||||
{
|
||||
var possiblyCreateCopyOnWrite = TryCreateCopyOnWrite(sourcePath, destinationPath, followSymlink: false);
|
||||
if (possiblyCreateCopyOnWrite.Succeeded)
|
||||
{
|
||||
return FileDuplicationResult.Copied;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await CopyFileAsync(sourcePath, destinationPath);
|
||||
return FileDuplicationResult.Copied;
|
||||
},
|
||||
ex => { throw new BuildXLException(ex.Message); });
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.TryCreateOrOpenFile(string, FileDesiredAccess, FileShare, FileMode, FileFlagsAndAttributes, out SafeFileHandle)"/>
|
||||
public static OpenFileResult TryCreateOrOpenFile(
|
||||
string path,
|
||||
|
@ -584,7 +499,7 @@ namespace BuildXL.Native.IO
|
|||
FileFlagsAndAttributes flagsAndAttributes,
|
||||
out SafeFileHandle handle)
|
||||
{
|
||||
return s_fileSystem.TryCreateOrOpenFile(path, desiredAccess, shareMode, creationDisposition, flagsAndAttributes, out handle);
|
||||
return OsFileSystem.TryCreateOrOpenFile(path, desiredAccess, shareMode, creationDisposition, flagsAndAttributes, out handle);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.TryOpenFileById(SafeFileHandle, FileId, FileDesiredAccess, FileShare, FileFlagsAndAttributes, out SafeFileHandle)"/>
|
||||
|
@ -596,7 +511,7 @@ namespace BuildXL.Native.IO
|
|||
FileFlagsAndAttributes flagsAndAttributes,
|
||||
out SafeFileHandle handle)
|
||||
{
|
||||
return s_fileSystem.TryOpenFileById(existingHandleOnVolume, fileId, desiredAccess, shareMode, flagsAndAttributes, out handle);
|
||||
return OsFileSystem.TryOpenFileById(existingHandleOnVolume, fileId, desiredAccess, shareMode, flagsAndAttributes, out handle);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.TryReOpenFile(SafeFileHandle, FileDesiredAccess, FileShare, FileFlagsAndAttributes, out SafeFileHandle)"/>
|
||||
|
@ -607,19 +522,19 @@ namespace BuildXL.Native.IO
|
|||
FileFlagsAndAttributes flagsAndAttributes,
|
||||
out SafeFileHandle reopenedHandle)
|
||||
{
|
||||
return s_fileSystem.TryReOpenFile(existing, desiredAccess, shareMode, flagsAndAttributes, out reopenedHandle);
|
||||
return OsFileSystem.TryReOpenFile(existing, desiredAccess, shareMode, flagsAndAttributes, out reopenedHandle);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.TryPosixDelete(string, out OpenFileResult)"/>
|
||||
public static unsafe bool TryPosixDelete(string pathToDelete, out OpenFileResult openFileResult)
|
||||
{
|
||||
return s_fileSystem.TryPosixDelete(pathToDelete, out openFileResult);
|
||||
return OsFileSystem.TryPosixDelete(pathToDelete, out openFileResult);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.TrySetDeletionDisposition(SafeFileHandle)"/>
|
||||
public static unsafe bool TrySetDeletionDisposition(SafeFileHandle handle)
|
||||
{
|
||||
return s_fileSystem.TrySetDeletionDisposition(handle);
|
||||
return OsFileSystem.TrySetDeletionDisposition(handle);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.GetFileFlagsAndAttributesForPossibleReparsePoint"/>
|
||||
|
@ -627,7 +542,7 @@ namespace BuildXL.Native.IO
|
|||
{
|
||||
using (Counters?.StartStopwatch(StorageCounters.GetFileFlagsAndAttributesForPossibleReparsePointDuration))
|
||||
{
|
||||
return s_fileSystem.GetFileFlagsAndAttributesForPossibleReparsePoint(expandedPath);
|
||||
return OsFileSystem.GetFileFlagsAndAttributesForPossibleReparsePoint(expandedPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -636,41 +551,41 @@ namespace BuildXL.Native.IO
|
|||
{
|
||||
using (Counters?.StartStopwatch(StorageCounters.GetFileAttributesByHandleDuration))
|
||||
{
|
||||
return s_fileSystem.GetFileAttributesByHandle(fileHandle);
|
||||
return OsFileSystem.GetFileAttributesByHandle(fileHandle);
|
||||
}
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.GetFileAttributes(string)"/>
|
||||
public static FileAttributes GetFileAttributes(string path) => s_fileSystem.GetFileAttributes(path);
|
||||
public static FileAttributes GetFileAttributes(string path) => OsFileSystem.GetFileAttributes(path);
|
||||
|
||||
/// <see cref="IFileSystem.SetFileAttributes(string, FileAttributes)"/>
|
||||
public static void SetFileAttributes(string path, FileAttributes attributes)
|
||||
{
|
||||
s_fileSystem.SetFileAttributes(path, attributes);
|
||||
OsFileSystem.SetFileAttributes(path, attributes);
|
||||
}
|
||||
|
||||
/// <see cref="IFileUtilities.SetFileAccessControl(string, FileSystemRights, bool, bool)"/>
|
||||
public static void SetFileAccessControl(string path, FileSystemRights fileSystemRights, bool allow, bool disableInheritance = false)
|
||||
{
|
||||
s_fileUtilities.SetFileAccessControl(path, fileSystemRights, allow, disableInheritance);
|
||||
OsFileUtilities.SetFileAccessControl(path, fileSystemRights, allow, disableInheritance);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.TryWriteFileSync(SafeFileHandle, byte[], out int)"/>
|
||||
public static bool TryWriteFileSync(SafeFileHandle handle, byte[] content, out int nativeErrorCode)
|
||||
{
|
||||
return s_fileSystem.TryWriteFileSync(handle, content, out nativeErrorCode);
|
||||
return OsFileSystem.TryWriteFileSync(handle, content, out nativeErrorCode);
|
||||
}
|
||||
|
||||
/// <see cref="IFileUtilities.DisableAuditRuleInheritance(string)"/>
|
||||
public static void DisableAuditRuleInheritance(string path)
|
||||
{
|
||||
s_fileUtilities.DisableAuditRuleInheritance(path);
|
||||
OsFileUtilities.DisableAuditRuleInheritance(path);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public static bool IsFileAccessRuleInheritanceDisabled(string path)
|
||||
{
|
||||
return s_fileUtilities.IsAclInheritanceDisabled(path);
|
||||
return OsFileUtilities.IsAclInheritanceDisabled(path);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -678,19 +593,19 @@ namespace BuildXL.Native.IO
|
|||
#region General file and directory utilities
|
||||
|
||||
/// <see cref="IFileUtilities.Exists(string)"/>
|
||||
public static bool Exists(string path) => s_fileUtilities.Exists(path);
|
||||
public static bool Exists(string path) => OsFileUtilities.Exists(path);
|
||||
|
||||
/// <see cref="IFileUtilities.DoesLogicalDriveHaveSeekPenalty(char)"/>
|
||||
public static bool? DoesLogicalDriveHaveSeekPenalty(char driveLetter) => s_fileUtilities.DoesLogicalDriveHaveSeekPenalty(driveLetter);
|
||||
public static bool? DoesLogicalDriveHaveSeekPenalty(char driveLetter) => OsFileUtilities.DoesLogicalDriveHaveSeekPenalty(driveLetter);
|
||||
|
||||
/// <see cref="IFileUtilities.GetKnownFolderPath(Guid)"/>
|
||||
public static string GetKnownFolderPath(Guid knownFolder) => s_fileUtilities.GetKnownFolderPath(knownFolder);
|
||||
public static string GetKnownFolderPath(Guid knownFolder) => OsFileUtilities.GetKnownFolderPath(knownFolder);
|
||||
|
||||
/// <see cref="IFileUtilities.GetUserSettingsFolder(string)"/>
|
||||
public static string GetUserSettingsFolder(string appName) => s_fileUtilities.GetUserSettingsFolder(appName);
|
||||
public static string GetUserSettingsFolder(string appName) => OsFileUtilities.GetUserSettingsFolder(appName);
|
||||
|
||||
/// <see cref="IFileUtilities.TryTakeOwnershipAndSetWriteable(string)"/>
|
||||
public static bool TryTakeOwnershipAndSetWriteable(string path) => s_fileUtilities.TryTakeOwnershipAndSetWriteable(path);
|
||||
public static bool TryTakeOwnershipAndSetWriteable(string path) => OsFileUtilities.TryTakeOwnershipAndSetWriteable(path);
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -699,13 +614,13 @@ namespace BuildXL.Native.IO
|
|||
/// <see cref="IFileSystem.CreateJunction(string, string, bool, bool)"/>
|
||||
public static void CreateJunction(string junctionPoint, string targetDir, bool createDirectoryForJunction = true, bool allowNonExistentTarget = false)
|
||||
{
|
||||
s_fileSystem.CreateJunction(junctionPoint, targetDir, createDirectoryForJunction, allowNonExistentTarget);
|
||||
OsFileSystem.CreateJunction(junctionPoint, targetDir, createDirectoryForJunction, allowNonExistentTarget);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.TryCreateSymbolicLink(string, string, bool)"/>
|
||||
public static Possible<Unit> TryCreateSymbolicLink(string symLinkFileName, string targetFileName, bool isTargetFile)
|
||||
{
|
||||
return s_fileSystem.TryCreateSymbolicLink(symLinkFileName, targetFileName, isTargetFile);
|
||||
return OsFileSystem.TryCreateSymbolicLink(symLinkFileName, targetFileName, isTargetFile);
|
||||
}
|
||||
|
||||
|
||||
|
@ -747,7 +662,7 @@ namespace BuildXL.Native.IO
|
|||
|
||||
if (shouldCreate)
|
||||
{
|
||||
s_fileUtilities.DeleteFile(reparsePoint, retryOnFailure: true);
|
||||
OsFileUtilities.DeleteFile(reparsePoint, retryOnFailure: true);
|
||||
return TryCreateReparsePoint(reparsePoint, reparsePointTarget, type);
|
||||
}
|
||||
|
||||
|
@ -766,7 +681,7 @@ namespace BuildXL.Native.IO
|
|||
{
|
||||
try
|
||||
{
|
||||
s_fileSystem.CreateJunction(path, reparsePointTarget, allowNonExistentTarget: true);
|
||||
OsFileSystem.CreateJunction(path, reparsePointTarget, allowNonExistentTarget: true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -780,7 +695,7 @@ namespace BuildXL.Native.IO
|
|||
{
|
||||
CreateDirectory(Path.GetDirectoryName(path));
|
||||
|
||||
var maybeSymbolicLink = s_fileSystem.TryCreateSymbolicLink(path, reparsePointTarget, isTargetFile: type != ReparsePointType.DirectorySymlink);
|
||||
var maybeSymbolicLink = OsFileSystem.TryCreateSymbolicLink(path, reparsePointTarget, isTargetFile: type != ReparsePointType.DirectorySymlink);
|
||||
if (!maybeSymbolicLink.Succeeded)
|
||||
{
|
||||
return maybeSymbolicLink.Failure;
|
||||
|
@ -798,19 +713,19 @@ namespace BuildXL.Native.IO
|
|||
/// <see cref="IFileSystem.TryCreateHardLink(string, string)"/>
|
||||
public static CreateHardLinkStatus TryCreateHardLink(string link, string linkTarget)
|
||||
{
|
||||
return s_fileSystem.TryCreateHardLink(link, linkTarget);
|
||||
return OsFileSystem.TryCreateHardLink(link, linkTarget);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.TryCreateHardLinkViaSetInformationFile(string, string, bool)"/>
|
||||
public static CreateHardLinkStatus TryCreateHardLinkViaSetInformationFile(string link, string linkTarget, bool replaceExisting = true)
|
||||
{
|
||||
return s_fileSystem.TryCreateHardLinkViaSetInformationFile(link, linkTarget, replaceExisting);
|
||||
return OsFileSystem.TryCreateHardLinkViaSetInformationFile(link, linkTarget, replaceExisting);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.IsReparsePointActionable(ReparsePointType)"/>
|
||||
public static bool IsReparsePointActionable(ReparsePointType reparsePointType)
|
||||
{
|
||||
return s_fileSystem.IsReparsePointActionable(reparsePointType);
|
||||
return OsFileSystem.IsReparsePointActionable(reparsePointType);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.TryGetReparsePointType(string)"/>
|
||||
|
@ -818,38 +733,38 @@ namespace BuildXL.Native.IO
|
|||
{
|
||||
using (Counters?.StartStopwatch(StorageCounters.GetReparsePointTypeDuration))
|
||||
{
|
||||
return s_fileSystem.TryGetReparsePointType(path);
|
||||
return OsFileSystem.TryGetReparsePointType(path);
|
||||
}
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.IsWciReparseArtifact(string)"/>
|
||||
public static bool IsWciReparseArtifact(string path)
|
||||
{
|
||||
return s_fileSystem.IsWciReparseArtifact(path);
|
||||
return OsFileSystem.IsWciReparseArtifact(path);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.IsWciReparsePoint(string)"/>
|
||||
public static bool IsWciReparsePoint(string path)
|
||||
{
|
||||
return s_fileSystem.IsWciReparsePoint(path);
|
||||
return OsFileSystem.IsWciReparsePoint(path);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.IsWciTombstoneFile(string)"/>
|
||||
public static bool IsWciTombstoneFile(string path)
|
||||
{
|
||||
return s_fileSystem.IsWciTombstoneFile(path);
|
||||
return OsFileSystem.IsWciTombstoneFile(path);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.GetChainOfReparsePoints(SafeFileHandle, string, IList{string})"/>
|
||||
public static void GetChainOfReparsePoints(SafeFileHandle handle, string sourcePath, IList<string> chainOfReparsePoints)
|
||||
{
|
||||
s_fileSystem.GetChainOfReparsePoints(handle, sourcePath, chainOfReparsePoints);
|
||||
OsFileSystem.GetChainOfReparsePoints(handle, sourcePath, chainOfReparsePoints);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.TryGetReparsePointTarget(SafeFileHandle, string)"/>
|
||||
public static Possible<string> TryGetReparsePointTarget(SafeFileHandle handle, string sourcePath)
|
||||
{
|
||||
return s_fileSystem.TryGetReparsePointTarget(handle, sourcePath);
|
||||
return OsFileSystem.TryGetReparsePointTarget(handle, sourcePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -885,10 +800,10 @@ namespace BuildXL.Native.IO
|
|||
}
|
||||
|
||||
/// <see cref="IFileSystem.IsDirectorySymlinkOrJunction(string)"/>
|
||||
public static bool IsDirectorySymlinkOrJunction(string path) => s_fileSystem.IsDirectorySymlinkOrJunction(path);
|
||||
public static bool IsDirectorySymlinkOrJunction(string path) => OsFileSystem.IsDirectorySymlinkOrJunction(path);
|
||||
|
||||
/// <see cref="IFileSystem.GetFullPath(string)"/>
|
||||
public static string GetFullPath(string path) => s_fileSystem.GetFullPath(path);
|
||||
public static string GetFullPath(string path) => OsFileSystem.GetFullPath(path);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a unique temporary file name, and creates a 0-byte file by that name on disk.
|
||||
|
@ -919,7 +834,7 @@ namespace BuildXL.Native.IO
|
|||
}
|
||||
|
||||
/// <see cref="IFileSystem.SupportsCreationDate"/>
|
||||
public static bool SupportsCreationDate() => s_fileSystem.SupportsCreationDate();
|
||||
public static bool SupportsCreationDate() => OsFileSystem.SupportsCreationDate();
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -930,7 +845,7 @@ namespace BuildXL.Native.IO
|
|||
{
|
||||
using (Counters?.StartStopwatch(StorageCounters.ReadFileUsnByHandleDuration))
|
||||
{
|
||||
return s_fileSystem.ReadFileUsnByHandle(fileHandle, forceJournalVersion2);
|
||||
return OsFileSystem.ReadFileUsnByHandle(fileHandle, forceJournalVersion2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -945,14 +860,14 @@ namespace BuildXL.Native.IO
|
|||
{
|
||||
using (Counters?.StartStopwatch(StorageCounters.ReadUsnJournalDuration))
|
||||
{
|
||||
return s_fileSystem.TryReadUsnJournal(volumeHandle, buffer, journalId, startUsn, forceJournalVersion2, isJournalUnprivileged);
|
||||
return OsFileSystem.TryReadUsnJournal(volumeHandle, buffer, journalId, startUsn, forceJournalVersion2, isJournalUnprivileged);
|
||||
}
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.TryQueryUsnJournal(SafeFileHandle)"/>
|
||||
public static QueryUsnJournalResult TryQueryUsnJournal(SafeFileHandle volumeHandle)
|
||||
{
|
||||
return s_fileSystem.TryQueryUsnJournal(volumeHandle);
|
||||
return OsFileSystem.TryQueryUsnJournal(volumeHandle);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.TryWriteUsnCloseRecordByHandle(SafeFileHandle)"/>
|
||||
|
@ -960,7 +875,7 @@ namespace BuildXL.Native.IO
|
|||
{
|
||||
using (Counters?.StartStopwatch(StorageCounters.WriteUsnCloseRecordByHandleDuration))
|
||||
{
|
||||
return s_fileSystem.TryWriteUsnCloseRecordByHandle(fileHandle);
|
||||
return OsFileSystem.TryWriteUsnCloseRecordByHandle(fileHandle);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -971,61 +886,61 @@ namespace BuildXL.Native.IO
|
|||
/// <see cref="IFileSystem.ListVolumeGuidPathsAndSerials"/>
|
||||
public static List<Tuple<VolumeGuidPath, ulong>> ListVolumeGuidPathsAndSerials()
|
||||
{
|
||||
return s_fileSystem.ListVolumeGuidPathsAndSerials();
|
||||
return OsFileSystem.ListVolumeGuidPathsAndSerials();
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.GetVolumeFileSystemByHandle(SafeFileHandle)"/>
|
||||
public static FileSystemType GetVolumeFileSystemByHandle(SafeFileHandle fileHandle)
|
||||
{
|
||||
return s_fileSystem.GetVolumeFileSystemByHandle(fileHandle);
|
||||
return OsFileSystem.GetVolumeFileSystemByHandle(fileHandle);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.GetShortVolumeSerialNumberByHandle(SafeFileHandle)"/>
|
||||
public static unsafe uint GetShortVolumeSerialNumberByHandle(SafeFileHandle fileHandle)
|
||||
{
|
||||
return s_fileSystem.GetShortVolumeSerialNumberByHandle(fileHandle);
|
||||
return OsFileSystem.GetShortVolumeSerialNumberByHandle(fileHandle);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.GetVolumeFileSystemByHandle(SafeFileHandle)"/>
|
||||
public static ulong GetVolumeSerialNumberByHandle(SafeFileHandle fileHandle)
|
||||
{
|
||||
return s_fileSystem.GetVolumeSerialNumberByHandle(fileHandle);
|
||||
return OsFileSystem.GetVolumeSerialNumberByHandle(fileHandle);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.TryGetFileIdAndVolumeIdByHandle(SafeFileHandle)"/>
|
||||
public static unsafe FileIdAndVolumeId? TryGetFileIdAndVolumeIdByHandle(SafeFileHandle fileHandle)
|
||||
{
|
||||
return s_fileSystem.TryGetFileIdAndVolumeIdByHandle(fileHandle);
|
||||
return OsFileSystem.TryGetFileIdAndVolumeIdByHandle(fileHandle);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.IsVolumeMapped(string)"/>
|
||||
public static bool IsVolumeMapped(string volume) => s_fileSystem.IsVolumeMapped(volume);
|
||||
public static bool IsVolumeMapped(string volume) => OsFileSystem.IsVolumeMapped(volume);
|
||||
|
||||
#endregion
|
||||
|
||||
#region File identity and version
|
||||
|
||||
/// <see cref="IFileSystem.TryGetFileIdentityByHandle(SafeFileHandle)"/>
|
||||
public static unsafe FileIdAndVolumeId? TryGetFileIdentityByHandle(SafeFileHandle fileHandle) => s_fileSystem.TryGetFileIdentityByHandle(fileHandle);
|
||||
public static unsafe FileIdAndVolumeId? TryGetFileIdentityByHandle(SafeFileHandle fileHandle) => OsFileSystem.TryGetFileIdentityByHandle(fileHandle);
|
||||
|
||||
/// <see cref="IFileSystem.TryGetVersionedFileIdentityByHandle(SafeFileHandle)"/>
|
||||
public static unsafe (FileIdAndVolumeId, Usn)? TryGetVersionedFileIdentityByHandle(SafeFileHandle fileHandle) => s_fileSystem.TryGetVersionedFileIdentityByHandle(fileHandle);
|
||||
public static unsafe (FileIdAndVolumeId, Usn)? TryGetVersionedFileIdentityByHandle(SafeFileHandle fileHandle) => OsFileSystem.TryGetVersionedFileIdentityByHandle(fileHandle);
|
||||
|
||||
/// <see cref="IFileSystem.TryEstablishVersionedFileIdentityByHandle(SafeFileHandle,bool)"/>
|
||||
public static unsafe (FileIdAndVolumeId, Usn)? TryEstablishVersionedFileIdentityByHandle(SafeFileHandle fileHandle, bool flushPageCache)
|
||||
=> s_fileSystem.TryEstablishVersionedFileIdentityByHandle(fileHandle, flushPageCache);
|
||||
=> OsFileSystem.TryEstablishVersionedFileIdentityByHandle(fileHandle, flushPageCache);
|
||||
|
||||
/// <see cref="IFileSystem.CheckIfVolumeSupportsPreciseFileVersionByHandle(SafeFileHandle)"/>
|
||||
public static bool CheckIfVolumeSupportsPreciseFileVersionByHandle(SafeFileHandle fileHandle) => s_fileSystem.CheckIfVolumeSupportsPreciseFileVersionByHandle(fileHandle);
|
||||
public static bool CheckIfVolumeSupportsPreciseFileVersionByHandle(SafeFileHandle fileHandle) => OsFileSystem.CheckIfVolumeSupportsPreciseFileVersionByHandle(fileHandle);
|
||||
|
||||
/// <see cref="IFileSystem.IsPreciseFileVersionSupportedByEnlistmentVolume"/>
|
||||
public static bool IsPreciseFileVersionSupportedByEnlistmentVolume
|
||||
{
|
||||
get => s_fileSystem.IsPreciseFileVersionSupportedByEnlistmentVolume;
|
||||
get => OsFileSystem.IsPreciseFileVersionSupportedByEnlistmentVolume;
|
||||
|
||||
set
|
||||
{
|
||||
s_fileSystem.IsPreciseFileVersionSupportedByEnlistmentVolume = value;
|
||||
OsFileSystem.IsPreciseFileVersionSupportedByEnlistmentVolume = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1035,65 +950,55 @@ namespace BuildXL.Native.IO
|
|||
/// <see cref="IFileSystem.MaxDirectoryPathLength"/>
|
||||
public static int MaxDirectoryPathLength()
|
||||
{
|
||||
return s_fileSystem.MaxDirectoryPathLength();
|
||||
return OsFileSystem.MaxDirectoryPathLength();
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.TryProbePathExistence(string, bool, out bool)"/>
|
||||
public static Possible<PathExistence, NativeFailure> TryProbePathExistence(string path, bool followSymlink)
|
||||
{
|
||||
return s_fileSystem.TryProbePathExistence(path, followSymlink, out _);
|
||||
return OsFileSystem.TryProbePathExistence(path, followSymlink, out _);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.TryProbePathExistence(string, bool, out bool)"/>
|
||||
public static Possible<PathExistence, NativeFailure> TryProbePathExistence(string path, bool followSymlink, out bool isReparsePoint)
|
||||
{
|
||||
return s_fileSystem.TryProbePathExistence(path, followSymlink, out isReparsePoint);
|
||||
return OsFileSystem.TryProbePathExistence(path, followSymlink, out isReparsePoint);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.PathMatchPattern"/>
|
||||
public static bool PathMatchPattern(string path, string pattern)
|
||||
{
|
||||
return s_fileSystem.PathMatchPattern(path, pattern);
|
||||
return OsFileSystem.PathMatchPattern(path, pattern);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.IsPendingDelete(SafeFileHandle)"/>
|
||||
public static unsafe bool IsPendingDelete(SafeFileHandle fileHandle)
|
||||
{
|
||||
return s_fileSystem.IsPendingDelete(fileHandle);
|
||||
return OsFileSystem.IsPendingDelete(fileHandle);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.GetFinalPathNameByHandle(SafeFileHandle, bool)"/>
|
||||
public static string GetFinalPathNameByHandle(SafeFileHandle handle, bool volumeGuidPath = false)
|
||||
{
|
||||
return s_fileSystem.GetFinalPathNameByHandle(handle, volumeGuidPath);
|
||||
return OsFileSystem.GetFinalPathNameByHandle(handle, volumeGuidPath);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.TryGetFinalPathNameByPath(string, out string, out int, bool)"/>
|
||||
public static bool TryGetFinalPathNameByPath(string path, out string finalPath, out int nativeErrorCode, bool volumeGuidPath = false)
|
||||
{
|
||||
return s_fileSystem.TryGetFinalPathNameByPath(path, out finalPath, out nativeErrorCode, volumeGuidPath);
|
||||
return OsFileSystem.TryGetFinalPathNameByPath(path, out finalPath, out nativeErrorCode, volumeGuidPath);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.FlushPageCacheToFilesystem(SafeFileHandle)"/>
|
||||
public static unsafe NtStatus FlushPageCacheToFilesystem(SafeFileHandle handle)
|
||||
{
|
||||
return s_fileSystem.FlushPageCacheToFilesystem(handle);
|
||||
return OsFileSystem.FlushPageCacheToFilesystem(handle);
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.CheckIfVolumeSupportsCopyOnWriteByHandle(SafeFileHandle)"/>
|
||||
public static bool CheckIfVolumeSupportsCopyOnWriteByHandle(SafeFileHandle fileHandle) => s_fileSystem.CheckIfVolumeSupportsCopyOnWriteByHandle(fileHandle);
|
||||
|
||||
/// <see cref="IFileSystem.IsCopyOnWriteSupportedByEnlistmentVolume"/>
|
||||
public static bool IsCopyOnWriteSupportedByEnlistmentVolume
|
||||
{
|
||||
get => s_fileSystem.IsCopyOnWriteSupportedByEnlistmentVolume;
|
||||
set => s_fileSystem.IsCopyOnWriteSupportedByEnlistmentVolume = value;
|
||||
}
|
||||
|
||||
/// <see cref="IFileSystem.IsCopyOnWriteSupportedByEnlistmentVolume"/>
|
||||
/// <see cref="IFileSystem.IsInKernelCopyingSupportedByHostSystem"/>
|
||||
public static bool IsInKernelCopyingSupportedByHostSystem
|
||||
{
|
||||
get => s_fileSystem.IsInKernelCopyingSupportedByHostSystem;
|
||||
get => OsFileSystem.IsInKernelCopyingSupportedByHostSystem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1138,11 +1043,11 @@ namespace BuildXL.Native.IO
|
|||
/// </remarks>
|
||||
public static Possible<string> ResolveSymlinkTarget(string symlinkPath, string targetPath = null)
|
||||
{
|
||||
Contract.Requires(s_fileSystem.IsPathRooted(symlinkPath));
|
||||
Contract.Requires(OsFileSystem.IsPathRooted(symlinkPath));
|
||||
|
||||
if (targetPath == null)
|
||||
{
|
||||
var maybeTarget = s_fileSystem.TryGetReparsePointTarget(null, symlinkPath);
|
||||
var maybeTarget = OsFileSystem.TryGetReparsePointTarget(null, symlinkPath);
|
||||
if (!maybeTarget.Succeeded)
|
||||
{
|
||||
return maybeTarget.Failure;
|
||||
|
@ -1151,14 +1056,14 @@ namespace BuildXL.Native.IO
|
|||
targetPath = maybeTarget.Result;
|
||||
}
|
||||
|
||||
if (s_fileSystem.IsPathRooted(targetPath))
|
||||
if (OsFileSystem.IsPathRooted(targetPath))
|
||||
{
|
||||
// If symlink target is an absolute path, then simply returns that path.
|
||||
return targetPath;
|
||||
}
|
||||
|
||||
// Symlink target is a relative path.
|
||||
var maybeResolvedRelative = s_fileSystem.TryResolveReparsePointRelativeTarget(symlinkPath, targetPath);
|
||||
var maybeResolvedRelative = OsFileSystem.TryResolveReparsePointRelativeTarget(symlinkPath, targetPath);
|
||||
|
||||
if (!maybeResolvedRelative.Succeeded)
|
||||
{
|
||||
|
|
|
@ -641,18 +641,6 @@ namespace BuildXL.Native.IO
|
|||
/// </remarks>
|
||||
NtStatus FlushPageCacheToFilesystem(SafeFileHandle handle);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a file system volume supports copy on write.
|
||||
/// </summary>
|
||||
/// <param name="fileHandle">File handle.</param>
|
||||
/// <returns>True iff the file system volume supports copy on write.</returns>
|
||||
bool CheckIfVolumeSupportsCopyOnWriteByHandle(SafeFileHandle fileHandle);
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating if the enlistment volume supports copy on write.
|
||||
/// </summary>
|
||||
bool IsCopyOnWriteSupportedByEnlistmentVolume { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating if the operating system supports in-kernel file copying.
|
||||
/// </summary>
|
||||
|
|
|
@ -143,15 +143,6 @@ namespace BuildXL.Native.IO
|
|||
/// <param name="replaceExisting">whether to replace an existing file at the destination</param>
|
||||
Task MoveFileAsync(string source, string destination, bool replaceExisting);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy on write clone of files if supported by the underlying OS.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method must be implemented if <see cref="IFileSystem.IsCopyOnWriteSupportedByEnlistmentVolume"/> returns true.
|
||||
/// </remarks>
|
||||
/// <exception cref="NativeWin32Exception">Throw native exception upon failure.</exception>
|
||||
Possible<Unit> CloneFile(string source, string destination, bool followSymlink);
|
||||
|
||||
/// <summary>
|
||||
/// Copy a file using in-kernel file descriptors to avoid user mode read/write buffer overheads.
|
||||
/// </summary>
|
||||
|
|
|
@ -50,8 +50,6 @@ namespace BuildXL.Native.IO.Unix
|
|||
|
||||
private Lazy<bool> m_supportPreciseFileVersion = default;
|
||||
|
||||
private Lazy<bool> m_supportCopyOnWrite = default;
|
||||
|
||||
private readonly ConcurrentDictionary<string, Regex> m_patternRegexes;
|
||||
|
||||
/// <summary>
|
||||
|
@ -60,7 +58,6 @@ namespace BuildXL.Native.IO.Unix
|
|||
public FileSystemUnix()
|
||||
{
|
||||
m_supportPreciseFileVersion = new Lazy<bool>(() => SupportPreciseFileVersion());
|
||||
m_supportCopyOnWrite = new Lazy<bool>(() => SupportCopyOnWrite());
|
||||
var matchEverythingRegex = TranslatePattern("*");
|
||||
m_patternRegexes = new ConcurrentDictionary<string, Regex>
|
||||
{
|
||||
|
@ -1138,47 +1135,9 @@ namespace BuildXL.Native.IO.Unix
|
|||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsCopyOnWriteSupportedByEnlistmentVolume
|
||||
{
|
||||
get => m_supportCopyOnWrite.Value;
|
||||
set
|
||||
{
|
||||
m_supportCopyOnWrite = new Lazy<bool>(() => value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsInKernelCopyingSupportedByHostSystem => !Interop.Dispatch.IsMacOS;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool CheckIfVolumeSupportsCopyOnWriteByHandle(SafeFileHandle fileHandle)
|
||||
{
|
||||
try
|
||||
{
|
||||
return GetVolumeFileSystemByHandle(fileHandle) == FileSystemType.APFS;
|
||||
}
|
||||
catch (NativeWin32Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool SupportCopyOnWrite()
|
||||
{
|
||||
// Use temp file name as an approximation whether file system supports copy-on-write.
|
||||
string path = FileUtilities.GetTempFileName();
|
||||
bool result = false;
|
||||
|
||||
using (var fileStream = CreateFileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete, FileOptions.None, false))
|
||||
{
|
||||
result = CheckIfVolumeSupportsCopyOnWriteByHandle(fileStream.SafeFileHandle);
|
||||
}
|
||||
|
||||
File.Delete(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int TryGetFilePermission(string path, bool followSymlink = false, bool throwOnFailure = true)
|
||||
{
|
||||
var statBuffer = new StatBuffer();
|
||||
|
|
|
@ -1021,8 +1021,6 @@ namespace BuildXL.Native.IO.Windows
|
|||
|
||||
private readonly Lazy<bool> m_supportUnprivilegedCreateSymbolicLinkFlag = default;
|
||||
|
||||
private Lazy<bool> m_supportCopyOnWrite;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the OS supports SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE flag for creating symlink.
|
||||
/// </summary>
|
||||
|
@ -1051,7 +1049,6 @@ namespace BuildXL.Native.IO.Windows
|
|||
{
|
||||
m_loggingContext = loggingContext;
|
||||
m_supportUnprivilegedCreateSymbolicLinkFlag = new Lazy<bool>(CheckSupportUnprivilegedCreateSymbolicLinkFlag);
|
||||
m_supportCopyOnWrite = new Lazy<bool>(SupportCopyOnWrite);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -4075,60 +4072,9 @@ namespace BuildXL.Native.IO.Windows
|
|||
/// <inheritdoc />
|
||||
public bool CheckIfVolumeSupportsPreciseFileVersionByHandle(SafeFileHandle fileHandle) => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsCopyOnWriteSupportedByEnlistmentVolume
|
||||
{
|
||||
get => m_supportCopyOnWrite.Value;
|
||||
set => m_supportCopyOnWrite = new Lazy<bool>(() => value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsInKernelCopyingSupportedByHostSystem => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool CheckIfVolumeSupportsCopyOnWriteByHandle(SafeFileHandle fileHandle)
|
||||
{
|
||||
#if NETCOREAPP
|
||||
try
|
||||
{
|
||||
return GetVolumeFileSystemByHandle(fileHandle) == FileSystemType.ReFS;
|
||||
}
|
||||
catch (NativeWin32Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
private bool SupportCopyOnWrite()
|
||||
{
|
||||
#if NETCOREAPP
|
||||
bool disableCopyOnWrite = string.Equals(Environment.GetEnvironmentVariable("DisableCopyOnWriteWin"), "1", StringComparison.Ordinal);
|
||||
|
||||
if (disableCopyOnWrite)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string workingDir = Environment.CurrentDirectory;
|
||||
OpenFileResult directoryOpenResult = TryOpenDirectory(
|
||||
workingDir,
|
||||
FileShare.ReadWrite | FileShare.Delete,
|
||||
out SafeFileHandle directoryHandle);
|
||||
|
||||
if (directoryOpenResult.Succeeded)
|
||||
{
|
||||
using (directoryHandle)
|
||||
{
|
||||
return CheckIfVolumeSupportsCopyOnWriteByHandle(directoryHandle);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsPathRooted(string path)
|
||||
{
|
||||
|
|
|
@ -19,9 +19,6 @@ using BuildXL.Native.Tracing;
|
|||
using BuildXL.Utilities.Core;
|
||||
using BuildXL.Utilities.Instrumentation.Common;
|
||||
using BuildXL.Utilities.Core.Tasks;
|
||||
#if NETCOREAPP
|
||||
using Microsoft.CopyOnWrite;
|
||||
#endif
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using static BuildXL.Utilities.Core.FormattableStringEx;
|
||||
|
||||
|
@ -1329,28 +1326,6 @@ namespace BuildXL.Native.IO.Windows
|
|||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Possible<Unit> CloneFile(string source, string destination, bool followSymlink)
|
||||
{
|
||||
#if NETCOREAPP
|
||||
try
|
||||
{
|
||||
// NoFileIntegrityCheck: Cache does not use Windows file integrity.
|
||||
// PathIsFullyResolved: No need for CoW library to do Path.GetFullPath() again, full paths are provided from PathTable.
|
||||
ICopyOnWriteFilesystem cow = CopyOnWriteFilesystemFactory.GetInstance();
|
||||
cow.CloneFile(source, destination, CloneFlags.NoFileIntegrityCheck | CloneFlags.PathIsFullyResolved);
|
||||
}
|
||||
catch (NotSupportedException ex)
|
||||
{
|
||||
return new Failure<string>(ex.Message);
|
||||
}
|
||||
|
||||
return Unit.Void;
|
||||
#else
|
||||
throw new NotImplementedException();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Possible<Unit> InKernelFileCopy(string source, string destination, bool followSymlink) => throw new NotImplementedException();
|
||||
|
||||
|
|
|
@ -1059,11 +1059,11 @@ namespace Test.BuildXL.Storage
|
|||
XAssert.AreEqual(
|
||||
OperatingSystemHelper.IsUnixOS ? FileSystemType.APFS : FileSystemType.ReFS,
|
||||
GetFileSystemType(file));
|
||||
XAssert.IsTrue(FileUtilities.IsCopyOnWriteSupportedByEnlistmentVolume);
|
||||
XAssert.IsTrue(FileUtilitiesExtensions.IsCopyOnWriteSupportedByEnlistmentVolume);
|
||||
|
||||
var clonedFile = GetFullPath(nameof(TestCopyOnWrite) + "_cloned");
|
||||
|
||||
var possiblyCopyOnWrite = FileUtilities.TryCreateCopyOnWrite(file, clonedFile, followSymlink: false);
|
||||
var possiblyCopyOnWrite = FileUtilitiesExtensions.TryCreateCopyOnWrite(file, clonedFile, followSymlink: false);
|
||||
XAssert.IsTrue(possiblyCopyOnWrite.Succeeded);
|
||||
|
||||
var fileTimestamp = FileUtilities.GetFileTimestamps(file);
|
||||
|
@ -1100,14 +1100,14 @@ namespace Test.BuildXL.Storage
|
|||
XAssert.AreEqual(
|
||||
OperatingSystemHelper.IsUnixOS ? FileSystemType.APFS : FileSystemType.ReFS,
|
||||
GetFileSystemType(file));
|
||||
XAssert.IsTrue(FileUtilities.IsCopyOnWriteSupportedByEnlistmentVolume);
|
||||
XAssert.IsTrue(FileUtilitiesExtensions.IsCopyOnWriteSupportedByEnlistmentVolume);
|
||||
|
||||
var symlink = GetFullPath(nameof(TestCopyOnWriteWithSymlink) + "_symlink");
|
||||
XAssert.PossiblySucceeded(FileUtilities.TryCreateSymbolicLink(symlink, file, isTargetFile: true));
|
||||
|
||||
var clonedFile = GetFullPath(nameof(TestCopyOnWriteWithSymlink) + "_cloned");
|
||||
|
||||
var possiblyCopyOnWrite = FileUtilities.TryCreateCopyOnWrite(symlink, clonedFile, followSymlink: followSymlink);
|
||||
var possiblyCopyOnWrite = FileUtilitiesExtensions.TryCreateCopyOnWrite(symlink, clonedFile, followSymlink: followSymlink);
|
||||
XAssert.IsTrue(possiblyCopyOnWrite.Succeeded);
|
||||
|
||||
var verifiedTimestamp = followSymlink
|
||||
|
@ -1411,7 +1411,7 @@ namespace Test.BuildXL.Storage
|
|||
{
|
||||
using FileStream fileStream = FileUtilities.CreateFileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete);
|
||||
|
||||
return FileUtilities.CheckIfVolumeSupportsCopyOnWriteByHandle(fileStream.SafeFileHandle);
|
||||
return FileUtilitiesExtensions.CheckIfVolumeSupportsCopyOnWriteByHandle(fileStream.SafeFileHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace Storage {
|
|||
importFrom("BuildXL.Cache.MemoizationStore").Interfaces.dll,
|
||||
importFrom("BuildXL.Utilities").dll,
|
||||
importFrom("BuildXL.Utilities").Native.dll,
|
||||
importFrom("BuildXL.Utilities").Native.Extensions.dll,
|
||||
importFrom("BuildXL.Utilities").Storage.dll,
|
||||
importFrom("BuildXL.Utilities").Utilities.Core.dll,
|
||||
...importFrom("BuildXL.Utilities").Native.securityDlls,
|
||||
|
|
Загрузка…
Ссылка в новой задаче