예제 #1
0
        /// <inheritdoc />
        public async Task <CopyFileResult> CopyFileAsync(AbsolutePath path, AbsolutePath destinationPath, long contentSize, bool overwrite, CancellationToken cancellationToken)
        {
            // NOTE: Assumes both source and destination are local
            Contract.Assert(path.IsLocal);
            Contract.Assert(destinationPath.IsLocal);

            if (!FileUtilities.Exists(path.Path))
            {
                return(new CopyFileResult(CopyFileResult.ResultCode.FileNotFoundError, $"Source file {path} doesn't exist."));
            }

            if (FileUtilities.Exists(destinationPath.Path))
            {
                if (!overwrite)
                {
                    return(new CopyFileResult(
                               CopyFileResult.ResultCode.DestinationPathError,
                               $"Destination file {destinationPath} exists but overwrite not specified."));
                }
            }

            if (!await FileUtilities.CopyFileAsync(path.Path, destinationPath.Path))
            {
                return(new CopyFileResult(CopyFileResult.ResultCode.SourcePathError, $"Failed to copy {destinationPath} from {path}"));
            }

            return(CopyFileResult.SuccessWithSize(new System.IO.FileInfo(destinationPath.Path).Length));
        }
예제 #2
0
        /// <summary>
        /// Removes a corrupt file and attempts to save it to the appropriate logs directory for future debugging.
        /// WARNING: This should only be called if it is ok to delete the corrupt file.
        /// </summary>
        /// <param name="corruptFile">
        /// The string path of the corrupt file to copy.
        /// </param>
        /// <param name="configuration">
        /// The BuildXL configuration being used to determine logs layout.
        /// </param>
        /// <param name="pathTable">
        /// PathTable for expanding the BuildXL logs path.
        /// </param>
        /// <param name="loggingContext">
        /// LoggingContext for verbose and warning messages.
        /// </param>
        /// <param name="removeFile">
        /// Whether or not the corrupt file should be removed.
        /// Conservatively defaults to false.
        /// </param>
        public static bool TryLogAndMaybeRemoveCorruptFile(string corruptFile, IConfiguration configuration, PathTable pathTable, LoggingContext loggingContext, bool removeFile = false)
        {
            if (!FileUtilities.FileExistsNoFollow(corruptFile))
            {
                // If file does not exist, then this method should return true.
                // If file does not exist, move file or copy file below will throw an exception.
                // The exception is logged in the catch clause, but the log is a warning log.
                // Customer may treat that warning as an error.
                return(true);
            }

            // Build the destination path
            var destFolder       = configuration.Logging.EngineCacheCorruptFilesLogDirectory.ToString(pathTable);
            var possibleFileName = FileUtilities.GetFileName(corruptFile);
            var fileName         = possibleFileName.Succeeded ? possibleFileName.Result : Path.GetFileName(corruptFile);

            var destination = Path.Combine(destFolder, fileName);

            Logger.Log.MovingCorruptFile(loggingContext, corruptFile, destination);

            try
            {
                FileUtilities.CreateDirectory(destFolder);

                if (removeFile)
                {
                    FileUtilities.MoveFileAsync(corruptFile, destination).GetAwaiter().GetResult();
                }
                else
                {
                    FileUtilities.CopyFileAsync(corruptFile, destination).GetAwaiter().GetResult();
                }

                return(true);
            }
            catch (BuildXLException moveException)
            {
                Logger.Log.FailedToMoveCorruptFile(loggingContext, corruptFile, destination, moveException.ToStringDemystified());
            }

            // If moving the file to logs for debugging failed, still attempt to delete the file since it's corrupt
            if (removeFile)
            {
                try
                {
                    FileUtilities.DeleteFile(corruptFile, waitUntilDeletionFinished: true);
                }
                catch (Exception deleteException)
                {
                    Logger.Log.FailedToDeleteCorruptFile(loggingContext, corruptFile, deleteException.ToStringDemystified());
                }
            }

            return(false);
        }
예제 #3
0
        /// <summary>
        /// Removes a corrupt file and attempts to save it to the appropriate logs directory for future debugging.
        /// WARNING: This should only be called if it is ok to delete the corrupt file.
        /// </summary>
        /// <param name="corruptFile">
        /// The string path of the corrupt file to copy.
        /// </param>
        /// <param name="configuration">
        /// The BuildXL configuration being used to determine logs layout.
        /// </param>
        /// <param name="pathTable">
        /// PathTable for expanding the BuildXL logs path.
        /// </param>
        /// <param name="loggingContext">
        /// LoggingContext for verbose and warning messages.
        /// </param>
        /// <param name="removeFile">
        /// Whether or not the corrupt file should be removed.
        /// Conservatively defaults to false.
        /// </param>
        public static bool TryLogAndMaybeRemoveCorruptFile(string corruptFile, IConfiguration configuration, PathTable pathTable, LoggingContext loggingContext, bool removeFile = false)
        {
            // Build the destination path
            var destFolder       = configuration.Logging.EngineCacheCorruptFilesLogDirectory.ToString(pathTable);
            var possibleFileName = FileUtilities.GetFileName(corruptFile);
            var fileName         = possibleFileName.Succeeded ? possibleFileName.Result : Path.GetFileName(corruptFile);

            var destination = Path.Combine(destFolder, fileName);

            Logger.Log.MovingCorruptFile(loggingContext, corruptFile, destination);

            try
            {
                FileUtilities.CreateDirectory(destFolder);

                if (removeFile)
                {
                    FileUtilities.MoveFileAsync(corruptFile, destination).GetAwaiter().GetResult();
                }
                else
                {
                    FileUtilities.CopyFileAsync(corruptFile, destination).GetAwaiter().GetResult();
                }

                return(true);
            }
            catch (Exception moveException)
            {
                Logger.Log.FailedToMoveCorruptFile(loggingContext, corruptFile, destination, moveException.ToStringDemystified());
            }

            // If moving the file to logs for debugging failed, still attempt to delete the file since it's corrupt
            if (removeFile)
            {
                try
                {
                    FileUtilities.DeleteFile(corruptFile, waitUntilDeletionFinished: true);
                }
                catch (Exception deleteException)
                {
                    Logger.Log.FailedToDeleteCorruptFile(loggingContext, corruptFile, deleteException.ToStringDemystified());
                }
            }

            return(false);
        }
예제 #4
0
        private Task <bool> CopyFileInternalAsync(string source, string destination)
        {
            if (FileUtilities.IsCopyOnWriteSupportedByEnlistmentVolume)
            {
                return(Task.Run(async() =>
                {
                    var possiblyCreateCopyOnWrite = FileUtilities.TryCreateCopyOnWrite(source, destination, followSymlink: false);

                    if (!possiblyCreateCopyOnWrite.Succeeded)
                    {
                        return await FileUtilities.CopyFileAsync(source, destination);
                    }

                    return possiblyCreateCopyOnWrite.Succeeded;
                }));
            }

            return(FileUtilities.CopyFileAsync(source, destination));
        }