/// <summary> /// Original copy code that performs single-threaded copies. /// Used for single-file copies and when parallelism is 1. /// </summary> private bool CopySingleThreaded( CopyFileWithState copyFile, out List <ITaskItem> destinationFilesSuccessfullyCopied) { bool success = true; destinationFilesSuccessfullyCopied = new List <ITaskItem>(DestinationFiles.Length); // Set of files we actually copied and the location from which they were originally copied. The purpose // of this collection is to let us skip copying duplicate files. We will only copy the file if it // either has never been copied to this destination before (key doesn't exist) or if we have copied it but // from a different location (value is different.) // { dest -> source } var filesActuallyCopied = new Dictionary <string, string>( DestinationFiles.Length, // Set length to common case of 1:1 source->dest. StringComparer.OrdinalIgnoreCase); // Now that we have a list of destinationFolder files, copy from source to destinationFolder. for (int i = 0; i < SourceFiles.Length && !_cancellationTokenSource.IsCancellationRequested; ++i) { bool copyComplete = false; string destPath = DestinationFiles[i].ItemSpec; MSBuildEventSource.Log.CopyUpToDateStart(destPath); if (filesActuallyCopied.TryGetValue(destPath, out string originalSource)) { if (String.Equals(originalSource, SourceFiles[i].ItemSpec, StringComparison.OrdinalIgnoreCase)) { // Already copied from this location, don't copy again. copyComplete = true; } } if (!copyComplete) { if (DoCopyIfNecessary(new FileState(SourceFiles[i].ItemSpec), new FileState(DestinationFiles[i].ItemSpec), copyFile)) { filesActuallyCopied[destPath] = SourceFiles[i].ItemSpec; copyComplete = true; } else { success = false; } } else { MSBuildEventSource.Log.CopyUpToDateStop(destPath, true); } if (copyComplete) { SourceFiles[i].CopyMetadataTo(DestinationFiles[i]); destinationFilesSuccessfullyCopied.Add(DestinationFiles[i]); } } return(success); }
internal bool Execute(CopyFileWithState copyFile) { if ((this.sourceFiles == null) || (this.sourceFiles.Length == 0)) { this.destinationFiles = new TaskItem[0]; this.copiedFiles = new TaskItem[0]; return(true); } if (!this.ValidateInputs() || !this.InitializeDestinationFiles()) { return(false); } bool flag = true; List <ITaskItem> list = new List <ITaskItem>(); Dictionary <string, string> dictionary = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); for (int i = 0; i < this.sourceFiles.Length; i++) { string str; bool flag2 = false; if (dictionary.TryGetValue(this.destinationFiles[i].ItemSpec, out str) && string.Equals(str, this.sourceFiles[i].ItemSpec, StringComparison.OrdinalIgnoreCase)) { flag2 = true; } if (!flag2) { if (this.DoCopyIfNecessary(new Microsoft.Build.Tasks.FileState(this.sourceFiles[i].ItemSpec), new Microsoft.Build.Tasks.FileState(this.destinationFiles[i].ItemSpec), copyFile)) { dictionary[this.destinationFiles[i].ItemSpec] = this.sourceFiles[i].ItemSpec; flag2 = true; } else { flag = false; } } if (flag2) { this.sourceFiles[i].CopyMetadataTo(this.destinationFiles[i]); list.Add(this.destinationFiles[i]); } } this.copiedFiles = list.ToArray(); return(flag); }
private bool DoCopyIfNecessary(Microsoft.Build.Tasks.FileState sourceFileState, Microsoft.Build.Tasks.FileState destinationFileState, CopyFileWithState copyFile) { bool flag = true; try { if (this.skipUnchangedFiles && IsMatchingSizeAndTimeStamp(sourceFileState, destinationFileState)) { base.Log.LogMessageFromResources(MessageImportance.Low, "Copy.DidNotCopyBecauseOfFileMatch", new object[] { sourceFileState.Name, destinationFileState.Name, "SkipUnchangedFiles", "true" }); return flag; } if (string.Compare(sourceFileState.Name, destinationFileState.Name, StringComparison.OrdinalIgnoreCase) != 0) { flag = this.DoCopyWithRetries(sourceFileState, destinationFileState, copyFile); } } catch (PathTooLongException exception) { base.Log.LogErrorWithCodeFromResources("Copy.Error", new object[] { sourceFileState.Name, destinationFileState.Name, exception.Message }); flag = false; } catch (IOException exception2) { if (this.PathsAreIdentical(sourceFileState.Name, destinationFileState.Name)) { return flag; } if (Microsoft.Build.Shared.ExceptionHandling.NotExpectedException(exception2)) { throw; } base.Log.LogErrorWithCodeFromResources("Copy.Error", new object[] { sourceFileState.Name, destinationFileState.Name, exception2.Message }); flag = false; } catch (Exception exception3) { if (Microsoft.Build.Shared.ExceptionHandling.NotExpectedException(exception3)) { throw; } base.Log.LogErrorWithCodeFromResources("Copy.Error", new object[] { sourceFileState.Name, destinationFileState.Name, exception3.Message }); flag = false; } return flag; }
/// <summary> /// Copy the files. /// </summary> /// <param name="copyFile">Delegate used to copy the files.</param> /// <param name="parallelism"> /// Thread parallelism allowed during copies. 1 uses the original algorithm, >1 uses newer algorithm. /// </param> /// <param name="staticEvaluation">Whether we are in static mode.</param> internal bool Execute ( CopyFileWithState copyFile, int parallelism, bool staticEvaluation ) { // If there are no source files then just return success. if (SourceFiles == null || SourceFiles.Length == 0) { DestinationFiles = Array.Empty <ITaskItem>(); CopiedFiles = Array.Empty <ITaskItem>(); return(true); } if (!(ValidateInputs() && InitializeDestinationFiles())) { return(false); } // Environment variable stomps on user-requested value if it's set. if (Environment.GetEnvironmentVariable(AlwaysOverwriteReadOnlyFilesEnvVar) != null) { OverwriteReadOnlyFiles = true; } // Track successfully copied subset. List <ITaskItem> destinationFilesSuccessfullyCopied; // Use single-threaded code path when requested or when there is only copy to make // (no need to create all the parallel infrastructure for that case). bool success = parallelism == 1 || DestinationFiles.Length == 1 ? CopySingleThreaded(copyFile, staticEvaluation, out destinationFilesSuccessfullyCopied) : CopyParallel(copyFile, parallelism, staticEvaluation, out destinationFilesSuccessfullyCopied); // copiedFiles contains only the copies that were successful. CopiedFiles = destinationFilesSuccessfullyCopied.ToArray(); return(success && !_cancellationTokenSource.IsCancellationRequested); }
/// <summary> /// Copy one file with the appropriate number of retries if it fails. /// </summary> private bool DoCopyWithRetries(FileState sourceFileState, FileState destinationFileState, CopyFileWithState copyFile) { int retries = 0; while (!_cancellationTokenSource.IsCancellationRequested) { try { bool?result = copyFile(sourceFileState, destinationFileState); if (result.HasValue) { return(result.Value); } } catch (OperationCanceledException) { break; } catch (Exception e) when(ExceptionHandling.IsIoRelatedException(e)) { if (e is ArgumentException || // Invalid chars e is NotSupportedException || // Colon in the middle of the path e is PathTooLongException) { // No use retrying these cases throw; } if (e is UnauthorizedAccessException || e is IOException) // Not clear why we can get one and not the other { int code = Marshal.GetHRForException(e); LogDiagnostic("Got {0} copying {1} to {2} and HR is {3}", e.ToString(), sourceFileState.Name, destinationFileState.Name, code); if (code == NativeMethods.ERROR_ACCESS_DENIED) { // ERROR_ACCESS_DENIED can either mean there's an ACL preventing us, or the file has the readonly bit set. // In either case, that's likely not a race, and retrying won't help. // Retrying is mainly for ERROR_SHARING_VIOLATION, where someone else is using the file right now. // However, there is a limited set of circumstances where a copy failure will show up as access denied due // to a failure to reset the readonly bit properly, in which case retrying will succeed. This seems to be // a pretty edge scenario, but since some of our internal builds appear to be hitting it, provide a secret // environment variable to allow overriding the default behavior and forcing retries in this circumstance as well. if (!s_alwaysRetryCopy) { throw; } else { LogDiagnostic("Retrying on ERROR_ACCESS_DENIED because MSBUILDALWAYSRETRY = 1"); } } } if (e is IOException && DestinationFolder != null && FileSystems.Default.FileExists(DestinationFolder.ItemSpec)) { // We failed to create the DestinationFolder because it's an existing file. No sense retrying. // We don't check for this case upstream because it'd be another hit to the filesystem. throw; } if (e is IOException) { // if this was just because the source and destination files are the // same file, that's not a failure. // Note -- we check this exceptional case here, not before the copy, for perf. if (PathsAreIdentical(sourceFileState.Name, destinationFileState.Name)) { return(true); } } if (retries < Retries) { retries++; Log.LogWarningWithCodeFromResources("Copy.Retrying", sourceFileState.Name, destinationFileState.Name, retries, RetryDelayMilliseconds, e.Message, GetLockedFileMessage(destinationFileState.Name)); // if we have to retry for some reason, wipe the state -- it may not be correct anymore. destinationFileState.Reset(); Thread.Sleep(RetryDelayMilliseconds); continue; } else if (Retries > 0) { // Exception message is logged in caller Log.LogErrorWithCodeFromResources("Copy.ExceededRetries", sourceFileState.Name, destinationFileState.Name, Retries, GetLockedFileMessage(destinationFileState.Name)); throw; } else { throw; } } if (retries < Retries) { retries++; Log.LogWarningWithCodeFromResources("Copy.Retrying", sourceFileState.Name, destinationFileState.Name, retries, RetryDelayMilliseconds, String.Empty /* no details */, GetLockedFileMessage(destinationFileState.Name)); // if we have to retry for some reason, wipe the state -- it may not be correct anymore. destinationFileState.Reset(); Thread.Sleep(RetryDelayMilliseconds); } else if (Retries > 0) { Log.LogErrorWithCodeFromResources("Copy.ExceededRetries", sourceFileState.Name, destinationFileState.Name, Retries, GetLockedFileMessage(destinationFileState.Name)); return(false); } else { return(false); } } // Canceling return(false); }
/// <summary> /// Copy source to destination, unless SkipUnchangedFiles is true and they are equivalent. /// </summary> /// <returns>True if the file was copied or, on SkipUnchangedFiles, the file was equivalent.</returns> private bool DoCopyIfNecessary(FileState sourceFileState, FileState destinationFileState, CopyFileWithState copyFile) { bool success = true; try { if (SkipUnchangedFiles && IsMatchingSizeAndTimeStamp(sourceFileState, destinationFileState)) { // If we got here, then the file's time and size match AND // the user set the SkipUnchangedFiles flag which means we // should skip matching files. Log.LogMessageFromResources( MessageImportance.Low, "Copy.DidNotCopyBecauseOfFileMatch", sourceFileState.Name, destinationFileState.Name, "SkipUnchangedFiles", "true" ); } // We only do the cheap check for identicalness here, we try the more expensive check // of comparing the fullpaths of source and destination to see if they are identical, // in the exception handler lower down. else if (0 != String.Compare( sourceFileState.Name, destinationFileState.Name, StringComparison.OrdinalIgnoreCase)) { success = DoCopyWithRetries(sourceFileState, destinationFileState, copyFile); } } catch (OperationCanceledException) { success = false; } catch (PathTooLongException e) { Log.LogErrorWithCodeFromResources("Copy.Error", sourceFileState.Name, destinationFileState.Name, e.Message); success = false; } catch (Exception e) when(ExceptionHandling.IsIoRelatedException(e)) { Log.LogErrorWithCodeFromResources("Copy.Error", sourceFileState.Name, destinationFileState.Name, e.Message); success = false; } return(success); }
/// <summary> /// Parallelize I/O with the same semantics as the single-threaded copy method above. /// ResolveAssemblyReferences tends to generate longer and longer lists of files to send /// to CopyTask as we get further and further down the dependency graph. /// The OS can handle a lot of parallel I/O so let's minimize wall clock time to get /// it all done. /// </summary> private bool CopyParallel( CopyFileWithState copyFile, int parallelism, out List <ITaskItem> destinationFilesSuccessfullyCopied) { bool success = true; // We must supply the same semantics as the single-threaded version above: // // - For copy operations in the list that have the same destination, we must // provide for in-order copy attempts that allow re-copying different files // and avoiding copies for later files that match SkipUnchangedFiles semantics. // We must also add a destination file copy item for each attempt. // - The order of entries in destinationFilesSuccessfullyCopied must match // the order of entries passed in, along with copied metadata. // - Metadata must not be copied to destination item if the copy operation failed. // // We split the work into different Tasks: // // - Entries with unique destination file paths each get their own parallel operation. // - Each subset of copies into the same destination get their own Task to run // the single-threaded logic in order. // // At the end we reassemble the result list in the same order as was passed in. // Map: Destination path -> indexes in SourceFiles/DestinationItems array indices (ordered low->high). var partitionsByDestination = new Dictionary <string, List <int> >( DestinationFiles.Length, // Set length to common case of 1:1 source->dest. StringComparer.OrdinalIgnoreCase); for (int i = 0; i < SourceFiles.Length && !_cancellationTokenSource.IsCancellationRequested; ++i) { ITaskItem destItem = DestinationFiles[i]; string destPath = destItem.ItemSpec; if (!partitionsByDestination.TryGetValue(destPath, out List <int> sourceIndices)) { // Use 1 for list length - common case is for no destination overlap. sourceIndices = new List <int>(1); partitionsByDestination[destPath] = sourceIndices; } sourceIndices.Add(i); } // Lockless flags updated from each thread - each needs to be a processor word for atomicity. var successFlags = new IntPtr[DestinationFiles.Length]; var actionBlockOptions = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = parallelism, CancellationToken = _cancellationTokenSource.Token }; var partitionCopyActionBlock = new ActionBlock <List <int> >( async(List <int> partition) => { // Break from synchronous thread context of caller to get onto thread pool thread. await System.Threading.Tasks.Task.Yield(); for (int partitionIndex = 0; partitionIndex < partition.Count && !_cancellationTokenSource.IsCancellationRequested; partitionIndex++) { int fileIndex = partition[partitionIndex]; ITaskItem sourceItem = SourceFiles[fileIndex]; ITaskItem destItem = DestinationFiles[fileIndex]; string sourcePath = sourceItem.ItemSpec; // Check if we just copied from this location to the destination, don't copy again. bool copyComplete = partitionIndex > 0 && String.Equals( sourcePath, SourceFiles[partition[partitionIndex - 1]].ItemSpec, StringComparison.OrdinalIgnoreCase); if (!copyComplete) { if (DoCopyIfNecessary( new FileState(sourceItem.ItemSpec), new FileState(destItem.ItemSpec), copyFile)) { copyComplete = true; } else { // Thread race to set outer variable but they race to set the same (false) value. success = false; } } if (copyComplete) { sourceItem.CopyMetadataTo(destItem); successFlags[fileIndex] = (IntPtr)1; } } }, actionBlockOptions); foreach (List <int> partition in partitionsByDestination.Values) { bool partitionAccepted = partitionCopyActionBlock.Post(partition); if (!partitionAccepted) { // Retail assert... ErrorUtilities.VerifyThrow(false, "Failed posting a file copy to an ActionBlock. Should not happen with block at max int capacity."); } } partitionCopyActionBlock.Complete(); partitionCopyActionBlock.Completion.GetAwaiter().GetResult(); // Assemble an in-order list of destination items that succeeded. destinationFilesSuccessfullyCopied = new List <ITaskItem>(DestinationFiles.Length); for (int i = 0; i < successFlags.Length; i++) { if (successFlags[i] != (IntPtr)0) { destinationFilesSuccessfullyCopied.Add(DestinationFiles[i]); } } return(success); }
/// <summary> /// Copy one file with the appropriate number of retries if it fails. /// </summary> private bool DoCopyWithRetries(FileState sourceFileState, FileState destinationFileState, CopyFileWithState copyFile) { bool? result = null; int retries = 0; while (true && !_canceling) { try { result = copyFile(sourceFileState, destinationFileState); if (result.HasValue) { return result.Value; } } catch (Exception e) when (ExceptionHandling.IsIoRelatedException(e)) { if (e is ArgumentException || // Invalid chars e is NotSupportedException || // Colon in the middle of the path e is PathTooLongException) { // No use retrying these cases throw; } if (e is UnauthorizedAccessException || e is IOException) // Not clear why we can get one and not the other { int code = Marshal.GetHRForException(e); LogDiagnostic("Got {0} copying {1} to {2} and HR is {3}", e.ToString(), sourceFileState.Name, destinationFileState.Name, code); if (code == Microsoft.Build.Tasks.NativeMethods.ERROR_ACCESS_DENIED) { // ERROR_ACCESS_DENIED can either mean there's an ACL preventing us, or the file has the readonly bit set. // In either case, that's likely not a race, and retrying won't help. // Retrying is mainly for ERROR_SHARING_VIOLATION, where someone else is using the file right now. // However, there is a limited set of circumstances where a copy failure will show up as access denied due // to a failure to reset the readonly bit properly, in which case retrying will succeed. This seems to be // a pretty edge scenario, but since some of our internal builds appear to be hitting it, provide a secret // environment variable to allow overriding the default behavior and forcing retries in this circumstance as well. if (!s_alwaysRetryCopy) { throw; } else { LogDiagnostic("Retrying on ERROR_ACCESS_DENIED because MSBUILDALWAYSRETRY = 1"); } } } if (e is IOException && DestinationFolder != null && File.Exists(DestinationFolder.ItemSpec)) { // We failed to create the DestinationFolder because it's an existing file. No sense retrying. // We don't check for this case upstream because it'd be another hit to the filesystem. throw; } if (e is IOException) { // if this was just because the source and destination files are the // same file, that's not a failure. // Note -- we check this exceptional case here, not before the copy, for perf. if (PathsAreIdentical(sourceFileState.Name, destinationFileState.Name)) { return true; } } if (retries < Retries) { retries++; Log.LogWarningWithCodeFromResources("Copy.Retrying", sourceFileState.Name, destinationFileState.Name, retries, RetryDelayMilliseconds, e.Message); // if we have to retry for some reason, wipe the state -- it may not be correct anymore. destinationFileState.Reset(); Thread.Sleep(RetryDelayMilliseconds); continue; } else if (Retries > 0) { // Exception message is logged in caller Log.LogErrorWithCodeFromResources("Copy.ExceededRetries", sourceFileState.Name, destinationFileState.Name, Retries); throw; } else { throw; } } if (retries < Retries) { retries++; Log.LogWarningWithCodeFromResources("Copy.Retrying", sourceFileState.Name, destinationFileState.Name, retries, RetryDelayMilliseconds, String.Empty /* no details */); // if we have to retry for some reason, wipe the state -- it may not be correct anymore. destinationFileState.Reset(); Thread.Sleep(RetryDelayMilliseconds); } else if (Retries > 0) { Log.LogErrorWithCodeFromResources("Copy.ExceededRetries", sourceFileState.Name, destinationFileState.Name, Retries); return false; } else { return false; } } // Canceling return false; }
/// <summary> /// Copy source to destination, unless SkipUnchangedFiles is true and they are equivalent. /// </summary> /// <param name="sourceFile"></param> /// <param name="destinationFile"></param> /// <param name="copyFile"></param> /// <returns></returns> private bool DoCopyIfNecessary(FileState sourceFileState, FileState destinationFileState, CopyFileWithState copyFile) { bool success = true; try { if (_skipUnchangedFiles && IsMatchingSizeAndTimeStamp(sourceFileState, destinationFileState)) { // If we got here, then the file's time and size match AND // the user set the SkipUnchangedFiles flag which means we // should skip matching files. Log.LogMessageFromResources ( MessageImportance.Low, "Copy.DidNotCopyBecauseOfFileMatch", sourceFileState.Name, destinationFileState.Name, "SkipUnchangedFiles", "true" ); } // We only do the cheap check for identicalness here, we try the more expensive check // of comparing the fullpaths of source and destination to see if they are identical, // in the exception handler lower down. else if (0 != String.Compare(sourceFileState.Name, destinationFileState.Name, StringComparison.OrdinalIgnoreCase)) { success = DoCopyWithRetries(sourceFileState, destinationFileState, copyFile); } } catch (PathTooLongException e) { Log.LogErrorWithCodeFromResources("Copy.Error", sourceFileState.Name, destinationFileState.Name, e.Message); success = false; } catch (Exception e) when (ExceptionHandling.IsIoRelatedException(e)) { Log.LogErrorWithCodeFromResources("Copy.Error", sourceFileState.Name, destinationFileState.Name, e.Message); success = false; } return success; }
/// <summary> /// Copy the files. /// </summary> /// <param name="copyFile">Delegate used to copy the files.</param> /// <returns></returns> internal bool Execute ( CopyFileWithState copyFile ) { // If there are no source files then just return success. if (_sourceFiles == null || _sourceFiles.Length == 0) { _destinationFiles = new TaskItem[0]; _copiedFiles = new TaskItem[0]; return true; } if (!(ValidateInputs() && InitializeDestinationFiles())) { return false; } bool success = true; // Environment variable stomps on user-requested value if it's set. if (Environment.GetEnvironmentVariable("MSBUILDALWAYSOVERWRITEREADONLYFILES") != null) { _overwriteReadOnlyFiles = true; } // Build up the sucessfully copied subset var destinationFilesSuccessfullyCopied = new List<ITaskItem>(); // Set of files we actually copied and the location from which they were originally copied. The purpose // of this collection is to let us skip copying duplicate files. We will only copy the file if it // either has never been copied to this destination before (key doesn't exist) or if we have copied it but // from a different location (value is different.) // { dest -> source } Dictionary<string, string> filesActuallyCopied = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); // Now that we have a list of destinationFolder files, copy from source to destinationFolder. for (int i = 0; i < _sourceFiles.Length && !_canceling; ++i) { bool copyComplete = false; string originalSource; if (filesActuallyCopied.TryGetValue(_destinationFiles[i].ItemSpec, out originalSource)) { if (String.Equals(originalSource, _sourceFiles[i].ItemSpec, StringComparison.OrdinalIgnoreCase)) { // Already copied from this location, don't copy again. copyComplete = true; } } if (!copyComplete) { if (DoCopyIfNecessary(new FileState(_sourceFiles[i].ItemSpec), new FileState(_destinationFiles[i].ItemSpec), copyFile)) { filesActuallyCopied[_destinationFiles[i].ItemSpec] = _sourceFiles[i].ItemSpec; copyComplete = true; } else { success = false; } } if (copyComplete) { _sourceFiles[i].CopyMetadataTo(_destinationFiles[i]); destinationFilesSuccessfullyCopied.Add(_destinationFiles[i]); } } // copiedFiles contains only the copies that were successful. _copiedFiles = (ITaskItem[])destinationFilesSuccessfullyCopied.ToArray(); return success && !_canceling; }
private bool DoCopyIfNecessary(Microsoft.Build.Tasks.FileState sourceFileState, Microsoft.Build.Tasks.FileState destinationFileState, CopyFileWithState copyFile) { bool flag = true; try { if (this.skipUnchangedFiles && IsMatchingSizeAndTimeStamp(sourceFileState, destinationFileState)) { base.Log.LogMessageFromResources(MessageImportance.Low, "Copy.DidNotCopyBecauseOfFileMatch", new object[] { sourceFileState.Name, destinationFileState.Name, "SkipUnchangedFiles", "true" }); return(flag); } if (string.Compare(sourceFileState.Name, destinationFileState.Name, StringComparison.OrdinalIgnoreCase) != 0) { flag = this.DoCopyWithRetries(sourceFileState, destinationFileState, copyFile); } } catch (PathTooLongException exception) { base.Log.LogErrorWithCodeFromResources("Copy.Error", new object[] { sourceFileState.Name, destinationFileState.Name, exception.Message }); flag = false; } catch (IOException exception2) { if (this.PathsAreIdentical(sourceFileState.Name, destinationFileState.Name)) { return(flag); } if (Microsoft.Build.Shared.ExceptionHandling.NotExpectedException(exception2)) { throw; } base.Log.LogErrorWithCodeFromResources("Copy.Error", new object[] { sourceFileState.Name, destinationFileState.Name, exception2.Message }); flag = false; } catch (Exception exception3) { if (Microsoft.Build.Shared.ExceptionHandling.NotExpectedException(exception3)) { throw; } base.Log.LogErrorWithCodeFromResources("Copy.Error", new object[] { sourceFileState.Name, destinationFileState.Name, exception3.Message }); flag = false; } return(flag); }
private bool DoCopyWithRetries(Microsoft.Build.Tasks.FileState sourceFileState, Microsoft.Build.Tasks.FileState destinationFileState, CopyFileWithState copyFile) { bool flag = false; int num = 0; Label_0004: try { flag = copyFile(sourceFileState, destinationFileState); } catch (Exception exception) { if (Microsoft.Build.Shared.ExceptionHandling.NotExpectedException(exception)) { throw; } if (num >= this.Retries) { if (this.Retries > 0) { base.Log.LogErrorWithCodeFromResources("Copy.ExceededRetries", new object[] { sourceFileState.Name, destinationFileState.Name, this.Retries }); throw; } throw; } num++; base.Log.LogWarningWithCodeFromResources("Copy.Retrying", new object[] { sourceFileState.Name, destinationFileState.Name, num, this.RetryDelayMilliseconds, exception.Message }); Thread.Sleep(this.RetryDelayMilliseconds); goto Label_0004; } if (flag) { return(true); } if (num < this.Retries) { num++; base.Log.LogWarningWithCodeFromResources("Copy.Retrying", new object[] { sourceFileState.Name, destinationFileState.Name, num, this.RetryDelayMilliseconds, string.Empty }); Thread.Sleep(this.RetryDelayMilliseconds); goto Label_0004; } if (this.Retries > 0) { base.Log.LogErrorWithCodeFromResources("Copy.ExceededRetries", new object[] { sourceFileState.Name, destinationFileState.Name, this.Retries }); return(false); } return(false); }
/// <summary> /// Copy the files. /// </summary> /// <param name="copyFile">Delegate used to copy the files.</param> /// <returns></returns> internal bool Execute ( CopyFileWithState copyFile ) { // If there are no source files then just return success. if (_sourceFiles == null || _sourceFiles.Length == 0) { _destinationFiles = Array.Empty <TaskItem>(); _copiedFiles = Array.Empty <TaskItem>(); return(true); } if (!(ValidateInputs() && InitializeDestinationFiles())) { return(false); } bool success = true; // Environment variable stomps on user-requested value if it's set. if (Environment.GetEnvironmentVariable("MSBUILDALWAYSOVERWRITEREADONLYFILES") != null) { _overwriteReadOnlyFiles = true; } // Build up the sucessfully copied subset var destinationFilesSuccessfullyCopied = new List <ITaskItem>(); // Set of files we actually copied and the location from which they were originally copied. The purpose // of this collection is to let us skip copying duplicate files. We will only copy the file if it // either has never been copied to this destination before (key doesn't exist) or if we have copied it but // from a different location (value is different.) // { dest -> source } Dictionary <string, string> filesActuallyCopied = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); // Now that we have a list of destinationFolder files, copy from source to destinationFolder. for (int i = 0; i < _sourceFiles.Length && !_canceling; ++i) { bool copyComplete = false; string originalSource; if (filesActuallyCopied.TryGetValue(_destinationFiles[i].ItemSpec, out originalSource)) { if (String.Equals(originalSource, _sourceFiles[i].ItemSpec, StringComparison.OrdinalIgnoreCase)) { // Already copied from this location, don't copy again. copyComplete = true; } } if (!copyComplete) { if (DoCopyIfNecessary(new FileState(_sourceFiles[i].ItemSpec), new FileState(_destinationFiles[i].ItemSpec), copyFile)) { filesActuallyCopied[_destinationFiles[i].ItemSpec] = _sourceFiles[i].ItemSpec; copyComplete = true; } else { success = false; } } if (copyComplete) { _sourceFiles[i].CopyMetadataTo(_destinationFiles[i]); destinationFilesSuccessfullyCopied.Add(_destinationFiles[i]); } } // copiedFiles contains only the copies that were successful. _copiedFiles = (ITaskItem[])destinationFilesSuccessfullyCopied.ToArray(); return(success && !_canceling); }
internal bool Execute(CopyFileWithState copyFile) { if ((this.sourceFiles == null) || (this.sourceFiles.Length == 0)) { this.destinationFiles = new TaskItem[0]; this.copiedFiles = new TaskItem[0]; return true; } if (!this.ValidateInputs() || !this.InitializeDestinationFiles()) { return false; } bool flag = true; List<ITaskItem> list = new List<ITaskItem>(); Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); for (int i = 0; i < this.sourceFiles.Length; i++) { string str; bool flag2 = false; if (dictionary.TryGetValue(this.destinationFiles[i].ItemSpec, out str) && string.Equals(str, this.sourceFiles[i].ItemSpec, StringComparison.OrdinalIgnoreCase)) { flag2 = true; } if (!flag2) { if (this.DoCopyIfNecessary(new Microsoft.Build.Tasks.FileState(this.sourceFiles[i].ItemSpec), new Microsoft.Build.Tasks.FileState(this.destinationFiles[i].ItemSpec), copyFile)) { dictionary[this.destinationFiles[i].ItemSpec] = this.sourceFiles[i].ItemSpec; flag2 = true; } else { flag = false; } } if (flag2) { this.sourceFiles[i].CopyMetadataTo(this.destinationFiles[i]); list.Add(this.destinationFiles[i]); } } this.copiedFiles = list.ToArray(); return flag; }
private bool DoCopyWithRetries(Microsoft.Build.Tasks.FileState sourceFileState, Microsoft.Build.Tasks.FileState destinationFileState, CopyFileWithState copyFile) { bool flag = false; int num = 0; Label_0004: try { flag = copyFile(sourceFileState, destinationFileState); } catch (Exception exception) { if (Microsoft.Build.Shared.ExceptionHandling.NotExpectedException(exception)) { throw; } if (num >= this.Retries) { if (this.Retries > 0) { base.Log.LogErrorWithCodeFromResources("Copy.ExceededRetries", new object[] { sourceFileState.Name, destinationFileState.Name, this.Retries }); throw; } throw; } num++; base.Log.LogWarningWithCodeFromResources("Copy.Retrying", new object[] { sourceFileState.Name, destinationFileState.Name, num, this.RetryDelayMilliseconds, exception.Message }); Thread.Sleep(this.RetryDelayMilliseconds); goto Label_0004; } if (flag) { return true; } if (num < this.Retries) { num++; base.Log.LogWarningWithCodeFromResources("Copy.Retrying", new object[] { sourceFileState.Name, destinationFileState.Name, num, this.RetryDelayMilliseconds, string.Empty }); Thread.Sleep(this.RetryDelayMilliseconds); goto Label_0004; } if (this.Retries > 0) { base.Log.LogErrorWithCodeFromResources("Copy.ExceededRetries", new object[] { sourceFileState.Name, destinationFileState.Name, this.Retries }); return false; } return false; }