public override HashValue ComputeHash(long offset, long length) { MeteringStream stream; if (offset == 0 && length == -1 && !this.OperatingStream.CanSeek) { var retval = StandardFileHashingService.GetHashFromCache(this.OperatingNode, this.ServiceType.AlgorithmName); if (retval != null) { return(retval.Value); } stream = new MeteringStream(this.OperatingStream); return(new HashValue(this.hashAlgorithm.ComputeHash(stream), this.ServiceType.AlgorithmName, 0, Convert.ToInt32(stream.ReadMeter.Value))); } else { if (offset == 0 && length == this.OperatingNode.Length) { if (StandardFileHashingService.ConfigurationSection.Default.CanCacheHash(this.OperatingNode)) { string s; if ((s = Convert.ToString(this.OperatingNode.Attributes["extended:" + ServiceType.AlgorithmName])) != "") { return(new HashValue(TextConversion.FromHexString(s), this.ServiceType.AlgorithmName, 0, -1)); } } } if (!this.OperatingStream.CanSeek) { throw new NotSupportedException("ComputeHash_StreamCannotSeek"); } stream = new MeteringStream(new PartialStream(this.OperatingStream, offset, length)); return(new HashValue(this.hashAlgorithm.ComputeHash(stream), this.ServiceType.AlgorithmName, offset, Convert.ToInt64(stream.ReadMeter.Value))); } }
public override void DoRun() { IFile destinationTemp; Stream destinationTempStream; string sourceHash; try { lock (this) { SetTransferState(TransferState.Preparing); } Action <IFile> transferAttributes = delegate(IFile dest) { using (dest.Attributes.AquireUpdateContext()) { foreach (string s in this.serviceType.AttributesToTransfer) { dest.Attributes[s] = this.source.Attributes[s]; } } }; Stream sourceStream = null; for (var i = 0; i < 4; i++) { try { sourceStream = this.OperatingNode.GetContent().GetInputStream(FileMode.Open, FileShare.Read); break; } catch (NodeNotFoundException) { throw; } catch (Exception) { if (i == 3) { throw; } } ProcessTaskStateRequest(); } using (sourceStream) { var sourceHashingService = (IHashingService)this.OperatingNode.GetService(new StreamHashingServiceType(sourceStream, this.HashAlgorithmName)); // Compute the hash of the source file SetTransferState(TransferState.Comparing); ProcessTaskStateRequest(); sourceHash = sourceHashingService.ComputeHash().TextValue; // Try to open the destination file ProcessTaskStateRequest(); var destinationHashingService = (IHashingService)this.TargetNode.GetService(new FileHashingServiceType(this.HashAlgorithmName)); string destinationHash; try { destinationHash = destinationHashingService.ComputeHash().TextValue; } catch (DirectoryNodeNotFoundException) { this.TargetNode.ParentDirectory.Create(true); try { destinationHash = destinationHashingService.ComputeHash().TextValue; } catch (NodeNotFoundException) { destinationHash = null; } } catch (NodeNotFoundException) { destinationHash = null; } ProcessTaskStateRequest(); // Source and destination are identical if (sourceHash == destinationHash) { SetTransferState(TransferState.Transferring); this.progress.RaiseValueChanged(0, GetBytesToTransfer()); SetTransferState(TransferState.Tidying); // Transfer attributes try { transferAttributes((IFile)this.TargetNode); } catch (FileNotFoundException) { } // Done SetTransferState(TransferState.Finished); ProcessTaskStateRequest(); return; } // Get a temp file for the destination based on the source's hash destinationTemp = ((ITempIdentityFileService)this.destination.GetService(new TempIdentityFileServiceType(sourceHash))).GetTempFile(); // Get the stream for the destination temp file try { if (!destinationTemp.ParentDirectory.Exists) { destinationTemp.ParentDirectory.Create(true); } } catch (IOException) { } using (destinationTempStream = destinationTemp.GetContent().OpenStream(FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) { Action finishUp = delegate { SetTransferState(TransferState.Tidying); destinationTempStream.Close(); for (int i = 0; i < 4; i++) { try { // Save hash value StandardFileHashingService.SaveHashToCache((IFile)destinationTemp, this.HashAlgorithmName, sourceHash, (IFile)this.TargetNode); try { // Transfer attributes transferAttributes(destinationTemp); } catch (FileNotFoundException e) { Console.WriteLine(e); } // Move destination temp to destination destinationTemp.MoveTo(this.TargetNode, true); break; } catch (Exception) { if (i == 3) { throw; } } ProcessTaskStateRequest(); } // Done SetTransferState(TransferState.Finished); ProcessTaskStateRequest(); }; // Get the hash for the destination temp file var destinationTempHashingService = (IHashingService)destinationTemp.GetService(new StreamHashingServiceType(destinationTempStream)); // If the destination temp and the source aren't the same // then complete the destination temp string destinationTempHash; if (destinationTempStream.Length >= sourceStream.Length) { // Destination is longer than source but starts source (unlikely) destinationTempHash = destinationTempHashingService.ComputeHash(0, sourceStream.Length).TextValue; if (destinationTempHash == sourceHash) { if (destinationTempStream.Length != sourceStream.Length) { destinationTempStream.SetLength(sourceStream.Length); } finishUp(); return; } destinationTempStream.SetLength(0); } if (destinationTempStream.Length > 0) { destinationTempHash = destinationTempHashingService.ComputeHash().TextValue; // Destination shorter than the source but is a partial copy of source sourceHash = sourceHashingService.ComputeHash(0, destinationTempStream.Length).TextValue; if (sourceHash == destinationTempHash) { this.offset = destinationTempStream.Length; } else { this.offset = 0; destinationTempStream.SetLength(0); } } else { this.offset = 0; } this.progress.RaiseValueChanged(0, this.offset); // Transfer over the remaining part needed (or everything if offset is 0) this.offset = destinationTempStream.Length; Stream sourcePartialStream = new PartialStream(sourceStream, destinationTempStream.Length); Stream destinationTempPartialStream = new PartialStream(destinationTempStream, destinationTempStream.Length); this.copier = new StreamCopier(new BufferedStream(sourcePartialStream, this.serviceType.BufferSize), destinationTempPartialStream, false, false, this.serviceType.ChunkSize); this.copier.TaskStateChanged += delegate(object sender, TaskEventArgs eventArgs) { if (eventArgs.TaskState == TaskState.Running || eventArgs.TaskState == TaskState.Paused || eventArgs.TaskState == TaskState.Stopped) { SetTaskState(eventArgs.TaskState); } }; SetTransferState(TransferState.Transferring); ProcessTaskStateRequest(); this.copier.Run(); if (this.copier.TaskState == TaskState.Stopped) { throw new StopRequestedException(); } finishUp(); } } } catch (StopRequestedException) { } finally { if (this.TransferState != TransferState.Finished) { SetTransferState(TransferState.Stopped); } } }