protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) { this.CloseOwnStream(); if (null != this.md5HashStream) { this.md5HashStream.Dispose(); this.md5HashStream = null; } } }
private void CloseOwnedOutputStream() { if (null != this.md5HashStream) { this.md5HashStream.Dispose(); this.md5HashStream = null; } if (this.ownsStream) { if (null != this.outputStream) { this.outputStream.Close(); this.outputStream = null; } } }
private void CloseOwnedOutputStream() { if (null != this.md5HashStream) { this.md5HashStream.Dispose(); this.md5HashStream = null; } if (this.ownsStream) { if (null != this.outputStream) { #if DOTNET5_4 this.outputStream.Dispose(); #else this.outputStream.Close(); #endif this.outputStream = null; } } }
private async Task HandleOutputStreamAsync() { this.hasWork = false; await Task.Run(async() => { // Only do calculation related to transfer window when the file contains multiple chunks. if (!this.EnableOneChunkFileOptimization) { // We do check point consistancy validation in reader, and directly use it in writer. if ((null != this.TransferJob.CheckPoint.TransferWindow) && this.TransferJob.CheckPoint.TransferWindow.Any()) { this.TransferJob.CheckPoint.TransferWindow.Sort(); this.expectOffset = this.TransferJob.CheckPoint.TransferWindow[0]; } else { this.expectOffset = this.TransferJob.CheckPoint.EntryTransferOffset; } } if (TransferLocationType.Stream == this.TransferJob.Destination.Type) { Stream streamInDestination = (this.TransferJob.Destination as StreamLocation).Stream; if (!streamInDestination.CanWrite) { throw new NotSupportedException(string.Format( CultureInfo.CurrentCulture, Resources.StreamMustSupportWriteException, "outputStream")); } if (!streamInDestination.CanSeek) { throw new NotSupportedException(string.Format( CultureInfo.CurrentCulture, Resources.StreamMustSupportSeekException, "outputStream")); } this.outputStream = streamInDestination; } else { string filePath = (this.TransferJob.Destination as FileLocation).FilePath; if (!this.Controller.IsForceOverwrite) { await this.Controller.CheckOverwriteAsync( LongPathFile.Exists(filePath), this.TransferJob.Source.Instance, filePath); } this.Controller.CheckCancellation(); try { FileMode fileMode = 0 == this.expectOffset ? FileMode.OpenOrCreate : FileMode.Open; #if DOTNET5_4 string longFilePath = filePath; if (Interop.CrossPlatformHelpers.IsWindows) { longFilePath = LongPath.ToUncPath(longFilePath); } // Attempt to open the file first so that we throw an exception before getting into the async work this.outputStream = new FileStream( longFilePath, fileMode, FileAccess.ReadWrite, FileShare.None); #else this.outputStream = LongPathFile.Open( filePath, fileMode, FileAccess.ReadWrite, FileShare.None); #endif this.ownsStream = true; } catch (Exception ex) { string exceptionMessage = string.Format( CultureInfo.CurrentCulture, Resources.FailedToOpenFileException, filePath, ex.Message); throw new TransferException( TransferErrorCode.OpenFileFailed, exceptionMessage, ex); } } this.outputStream.SetLength(this.SharedTransferData.TotalLength); this.md5HashStream = new MD5HashStream( this.outputStream, this.expectOffset, !this.SharedTransferData.DisableContentMD5Validation); if (this.md5HashStream.FinishedSeparateMd5Calculator) { this.state = State.Write; } else { this.state = State.CalculateMD5; } this.PreProcessed = true; // Switch state internal for one chunk small file. if (this.EnableOneChunkFileOptimization && State.Write == this.state && ((this.SharedTransferData.TotalLength == this.expectOffset) || this.SharedTransferData.AvailableData.ContainsKey(this.expectOffset))) { this.isStateSwitchedInternal = true; await this.WriteChunkDataAsync().ConfigureAwait(false); } else { this.hasWork = true; } }); }
private async Task HandleOutputStreamAsync() { this.hasWork = false; await Task.Run(() => { if (TransferLocationType.Stream == this.TransferJob.Destination.TransferLocationType) { Stream streamInDestination = this.TransferJob.Destination.Stream; if (!streamInDestination.CanWrite) { throw new NotSupportedException(string.Format( CultureInfo.CurrentCulture, Resources.StreamMustSupportWriteException, "outputStream")); } if (!streamInDestination.CanSeek) { throw new NotSupportedException(string.Format( CultureInfo.CurrentCulture, Resources.StreamMustSupportSeekException, "outputStream")); } this.outputStream = this.TransferJob.Destination.Stream; } else { this.Controller.CheckOverwrite( File.Exists(this.TransferJob.Destination.FilePath), this.SharedTransferData.SourceLocation, this.TransferJob.Destination.FilePath); this.Controller.UpdateProgressAddBytesTransferred(0); this.Controller.CheckCancellation(); // We do check point consistancy validation in reader, and directly use it in writer. if ((null != this.TransferJob.CheckPoint.TransferWindow) && (this.TransferJob.CheckPoint.TransferWindow.Any())) { this.TransferJob.CheckPoint.TransferWindow.Sort(); this.expectOffset = this.TransferJob.CheckPoint.TransferWindow[0]; } else { this.expectOffset = this.TransferJob.CheckPoint.EntryTransferOffset; } try { FileMode fileMode = 0 == this.expectOffset ? FileMode.OpenOrCreate : FileMode.Open; // Attempt to open the file first so that we throw an exception before getting into the async work this.outputStream = new FileStream( this.TransferJob.Destination.FilePath, fileMode, FileAccess.ReadWrite, FileShare.None); this.ownsStream = true; } catch (Exception ex) { string exceptionMessage = string.Format( CultureInfo.CurrentCulture, Resources.FailedToOpenFileException, this.TransferJob.Destination.FilePath, ex.Message); throw new TransferException( TransferErrorCode.OpenFileFailed, exceptionMessage, ex); } } this.outputStream.SetLength(this.SharedTransferData.TotalLength); this.Controller.UpdateProgressAddBytesTransferred(0); this.md5HashStream = new MD5HashStream( this.outputStream, this.expectOffset, !this.SharedTransferData.DisableContentMD5Validation); if (this.md5HashStream.FinishedSeparateMd5Calculator) { this.state = State.Write; } else { this.state = State.CalculateMD5; } this.PreProcessed = true; this.hasWork = true; }); }
private async Task OpenInputStreamAsync() { Debug.Assert( State.OpenInputStream == this.state, "OpenInputStreamAsync called, but state is not OpenInputStream."); if (Interlocked.CompareExchange(ref workToken, 0, 1) == 0) { return; } await Task.Yield(); this.NotifyStarting(); this.Controller.CheckCancellation(); if (this.transferJob.Source.Type == TransferLocationType.Stream) { StreamLocation streamLocation = this.transferJob.Source as StreamLocation; this.inputStream = streamLocation.Stream; this.ownsStream = false; if (!this.inputStream.CanRead) { throw new NotSupportedException(string.Format( CultureInfo.CurrentCulture, Resources.StreamMustSupportReadException, "inputStream")); } } else { FileLocation fileLocation = this.transferJob.Source as FileLocation; Debug.Assert( null != fileLocation, "Initializing StreamedReader instance, but source is neither a stream nor a file"); try { if (fileLocation.RelativePath != null && fileLocation.RelativePath.Length > Constants.MaxRelativePathLength) { string errorMessage = string.Format( CultureInfo.CurrentCulture, Resources.RelativePathTooLong, fileLocation.RelativePath); throw new TransferException(TransferErrorCode.OpenFileFailed, errorMessage); } this.filePath = fileLocation.FilePath.ToLongPath(); #if DOTNET5_4 // Attempt to open the file first so that we throw an exception before getting into the async work this.inputStream = new FileStream( filePath, FileMode.Open, FileAccess.Read, FileShare.Read); #else this.inputStream = LongPathFile.Open( this.filePath, FileMode.Open, FileAccess.Read, FileShare.Read); #endif this.ownsStream = true; } catch (Exception ex) { if ((ex is NotSupportedException) || (ex is IOException) || (ex is UnauthorizedAccessException) || (ex is SecurityException) || (ex is ArgumentException && !(ex is ArgumentNullException))) { string exceptionMessage = string.Format( CultureInfo.CurrentCulture, Resources.FailedToOpenFileException, fileLocation.FilePath, ex.Message); throw new TransferException( TransferErrorCode.OpenFileFailed, exceptionMessage, ex); } else { throw; } } } try { this.SharedTransferData.TotalLength = this.inputStream.Length; } catch (NotSupportedException) { this.SharedTransferData.TotalLength = -1; } // Only do calculation related to transfer window when the file contains multiple chunks. if (!this.EnableOneChunkFileOptimization) { var checkpoint = this.transferJob.CheckPoint; checkpoint.TransferWindow.Sort(); this.readLength = checkpoint.EntryTransferOffset; if (checkpoint.TransferWindow.Any()) { // The size of last block can be smaller than BlockSize. this.readLength -= Math.Min(checkpoint.EntryTransferOffset - checkpoint.TransferWindow.Last(), this.SharedTransferData.BlockSize); this.readLength -= (checkpoint.TransferWindow.Count - 1) * this.SharedTransferData.BlockSize; } if (this.readLength < 0) { throw new InvalidOperationException(Resources.RestartableInfoCorruptedException); } else if ((checkpoint.EntryTransferOffset > 0) && (!this.inputStream.CanSeek)) { throw new NotSupportedException(string.Format( CultureInfo.CurrentCulture, Resources.StreamMustSupportSeekException, "inputStream")); } this.lastTransferWindow = new Queue <long>(this.transferJob.CheckPoint.TransferWindow); } this.md5HashStream = new MD5HashStream( this.inputStream, this.transferJob.CheckPoint.EntryTransferOffset, true); this.PreProcessed = true; if (this.readLength != this.SharedTransferData.TotalLength) { // Change the state to 'ReadStream' before awaiting MD5 calculation task to not block the reader. this.state = State.ReadStream; this.workToken = 1; } else { Interlocked.Exchange(ref this.readCompleted, 1); } if (!this.md5HashStream.FinishedSeparateMd5Calculator) { await Task.Run(() => { this.md5HashStream.CalculateMd5(this.Scheduler.MemoryManager, this.Controller.CheckCancellation); }); } this.SetChunkFinish(); }
private async Task OpenInputStreamAsync() { Debug.Assert( State.OpenInputStream == this.state, "OpenInputStreamAsync called, but state is not OpenInputStream."); this.hasWork = false; await Task.Run(() => { this.NotifyStarting(); this.Controller.CheckCancellation(); if (this.transferJob.Source.Type == TransferLocationType.Stream) { StreamLocation streamLocation = this.transferJob.Source as StreamLocation; this.inputStream = streamLocation.Stream; this.ownsStream = false; if (!this.inputStream.CanRead) { throw new NotSupportedException(string.Format( CultureInfo.CurrentCulture, Resources.StreamMustSupportReadException, "inputStream")); } if (!this.inputStream.CanSeek) { throw new NotSupportedException(string.Format( CultureInfo.CurrentCulture, Resources.StreamMustSupportSeekException, "inputStream")); } } else { FileLocation fileLocation = this.transferJob.Source as FileLocation; Debug.Assert( null != fileLocation, "Initializing StreamedReader instance, but source is neither a stream nor a file"); try { if (fileLocation.RelativePath != null && fileLocation.RelativePath.Length > Constants.MaxRelativePathLength) { string errorMessage = string.Format( CultureInfo.CurrentCulture, Resources.RelativePathTooLong, fileLocation.RelativePath); throw new TransferException(TransferErrorCode.OpenFileFailed, errorMessage); } #if DOTNET5_4 string filePath = fileLocation.FilePath; if (Interop.CrossPlatformHelpers.IsWindows) { filePath = LongPath.ToUncPath(fileLocation.FilePath); } // Attempt to open the file first so that we throw an exception before getting into the async work this.inputStream = new FileStream( filePath, FileMode.Open, FileAccess.Read, FileShare.Read); #else this.inputStream = LongPathFile.Open( fileLocation.FilePath, FileMode.Open, FileAccess.Read, FileShare.Read); #endif this.ownsStream = true; } catch (Exception ex) { if ((ex is NotSupportedException) || (ex is IOException) || (ex is UnauthorizedAccessException) || (ex is SecurityException) || (ex is ArgumentException && !(ex is ArgumentNullException))) { string exceptionMessage = string.Format( CultureInfo.CurrentCulture, Resources.FailedToOpenFileException, fileLocation.FilePath, ex.Message); throw new TransferException( TransferErrorCode.OpenFileFailed, exceptionMessage, ex); } else { throw; } } } }); this.SharedTransferData.TotalLength = this.inputStream.Length; int count = (int)Math.Ceiling((double)(this.SharedTransferData.TotalLength - this.transferJob.CheckPoint.EntryTransferOffset) / this.SharedTransferData.BlockSize); if (null != this.transferJob.CheckPoint.TransferWindow) { count += this.transferJob.CheckPoint.TransferWindow.Count; } this.lastTransferWindow = new Queue <long>(this.transferJob.CheckPoint.TransferWindow); this.md5HashStream = new MD5HashStream( this.inputStream, this.transferJob.CheckPoint.EntryTransferOffset, true); this.PreProcessed = true; // This reader will come into 'Finish' state after all chunks are read and MD5 calculation completes. // So initialize the CountDownEvent to count (number of chunks to read) + 1 (md5 calculation). this.countdownEvent = new CountdownEvent(count + 1); if (0 != count) { // Change the state to 'ReadStream' before awaiting MD5 calculation task to not block the reader. this.state = State.ReadStream; this.hasWork = true; } if (!this.md5HashStream.FinishedSeparateMd5Calculator) { await Task.Run(() => { this.md5HashStream.CalculateMd5(this.Scheduler.MemoryManager, this.Controller.CheckCancellation); }); } this.SetChunkFinish(); }
private void CloseOwnedOutputStream() { if (null != this.md5HashStream) { this.md5HashStream.Dispose(); this.md5HashStream = null; } if (this.ownsStream) { if (null != this.outputStream) { this.outputStream.Close(); this.outputStream = null; } } }
private async Task HandleOutputStreamAsync() { this.hasWork = false; await Task.Run(() => { if (TransferLocationType.Stream == this.TransferJob.Destination.Type) { Stream streamInDestination = (this.TransferJob.Destination as StreamLocation).Stream; if (!streamInDestination.CanWrite) { throw new NotSupportedException(string.Format( CultureInfo.CurrentCulture, Resources.StreamMustSupportWriteException, "outputStream")); } if (!streamInDestination.CanSeek) { throw new NotSupportedException(string.Format( CultureInfo.CurrentCulture, Resources.StreamMustSupportSeekException, "outputStream")); } this.outputStream = streamInDestination; } else { string filePath = (this.TransferJob.Destination as FileLocation).FilePath; this.Controller.CheckOverwrite( File.Exists(filePath), this.SharedTransferData.SourceLocation, filePath); this.Controller.UpdateProgressAddBytesTransferred(0); this.Controller.CheckCancellation(); // We do check point consistancy validation in reader, and directly use it in writer. if ((null != this.TransferJob.CheckPoint.TransferWindow) && (this.TransferJob.CheckPoint.TransferWindow.Any())) { this.TransferJob.CheckPoint.TransferWindow.Sort(); this.expectOffset = this.TransferJob.CheckPoint.TransferWindow[0]; } else { this.expectOffset = this.TransferJob.CheckPoint.EntryTransferOffset; } try { FileMode fileMode = 0 == this.expectOffset ? FileMode.OpenOrCreate : FileMode.Open; // Attempt to open the file first so that we throw an exception before getting into the async work this.outputStream = new FileStream( filePath, fileMode, FileAccess.ReadWrite, FileShare.None); this.ownsStream = true; } catch (Exception ex) { string exceptionMessage = string.Format( CultureInfo.CurrentCulture, Resources.FailedToOpenFileException, filePath, ex.Message); throw new TransferException( TransferErrorCode.OpenFileFailed, exceptionMessage, ex); } } this.outputStream.SetLength(this.SharedTransferData.TotalLength); this.Controller.UpdateProgressAddBytesTransferred(0); this.md5HashStream = new MD5HashStream( this.outputStream, this.expectOffset, !this.SharedTransferData.DisableContentMD5Validation); if (this.md5HashStream.FinishedSeparateMd5Calculator) { this.state = State.Write; } else { this.state = State.CalculateMD5; } this.PreProcessed = true; this.hasWork = true; }); }
private async Task OpenInputStreamAsync() { Debug.Assert( State.OpenInputStream == this.state, "OpenInputStreamAsync called, but state is not OpenInputStream."); this.hasWork = false; await Task.Run(() => { this.NotifyStarting(); this.Controller.CheckCancellation(); if (this.transferJob.Source.Type == TransferLocationType.Stream) { StreamLocation streamLocation = this.transferJob.Source as StreamLocation; this.inputStream = streamLocation.Stream; this.ownsStream = false; if (!this.inputStream.CanRead) { throw new NotSupportedException(string.Format( CultureInfo.CurrentCulture, Resources.StreamMustSupportReadException, "inputStream")); } if (!this.inputStream.CanSeek) { throw new NotSupportedException(string.Format( CultureInfo.CurrentCulture, Resources.StreamMustSupportSeekException, "inputStream")); } } else { FileLocation fileLocation = this.transferJob.Source as FileLocation; Debug.Assert( null != fileLocation, "Initializing StreamedReader instance, but source is neither a stream nor a file"); this.SharedTransferData.SourceLocation = fileLocation.ToString(); try { // Attempt to open the file first so that we throw an exception before getting into the async work this.inputStream = new FileStream( fileLocation.FilePath, FileMode.Open, FileAccess.Read, FileShare.Read); this.ownsStream = true; } catch (Exception ex) { if ((ex is NotSupportedException) || (ex is IOException) || (ex is UnauthorizedAccessException) || (ex is SecurityException) || (ex is ArgumentException && !(ex is ArgumentNullException))) { string exceptionMessage = string.Format( CultureInfo.CurrentCulture, Resources.FailedToOpenFileException, fileLocation.FilePath, ex.Message); throw new TransferException( TransferErrorCode.OpenFileFailed, exceptionMessage, ex); } else { throw; } } } }); this.SharedTransferData.TotalLength = this.inputStream.Length; int count = (int)Math.Ceiling((double)(this.SharedTransferData.TotalLength - this.transferJob.CheckPoint.EntryTransferOffset) / this.Scheduler.TransferOptions.BlockSize); if (null != this.transferJob.CheckPoint.TransferWindow) { count += this.transferJob.CheckPoint.TransferWindow.Count; } this.lastTransferWindow = new Queue <long>(this.transferJob.CheckPoint.TransferWindow); this.md5HashStream = new MD5HashStream( this.inputStream, this.transferJob.CheckPoint.EntryTransferOffset, true); this.PreProcessed = true; if (!this.md5HashStream.FinishedSeparateMd5Calculator) { await Task.Run(() => { this.md5HashStream.CalculateMd5(this.Scheduler.MemoryManager, this.Controller.CheckCancellation); }); } if (0 == count) { this.countdownEvent = new CountdownEvent(1); this.SetChunkFinish(); } else { this.countdownEvent = new CountdownEvent(count); this.state = State.ReadStream; this.hasWork = true; } }
private async Task OpenInputStreamAsync() { Debug.Assert( State.OpenInputStream == this.state, "OpenInputStreamAsync called, but state is not OpenInputStream."); this.hasWork = false; await Task.Run(() => { this.NotifyStarting(); this.Controller.CheckCancellation(); if (this.transferJob.Source.Stream != null) { this.inputStream = this.transferJob.Source.Stream; this.ownsStream = false; if (!this.inputStream.CanRead) { throw new NotSupportedException(string.Format( CultureInfo.CurrentCulture, Resources.StreamMustSupportReadException, "inputStream")); } if (!this.inputStream.CanSeek) { throw new NotSupportedException(string.Format( CultureInfo.CurrentCulture, Resources.StreamMustSupportSeekException, "inputStream")); } } else { Debug.Assert( !string.IsNullOrEmpty(this.transferJob.Source.FilePath), "Initializing StreamedReader instance, but source is neither a stream nor a file"); this.SharedTransferData.SourceLocation = this.transferJob.Source.FilePath; try { // Attempt to open the file first so that we throw an exception before getting into the async work this.inputStream = new FileStream( this.transferJob.Source.FilePath, FileMode.Open, FileAccess.Read, FileShare.Read); this.ownsStream = true; } catch (Exception ex) { if ((ex is NotSupportedException) || (ex is IOException) || (ex is UnauthorizedAccessException) || (ex is SecurityException) || (ex is ArgumentException && !(ex is ArgumentNullException))) { string exceptionMessage = string.Format( CultureInfo.CurrentCulture, Resources.FailedToOpenFileException, this.transferJob.Source.FilePath, ex.Message); throw new TransferException( TransferErrorCode.OpenFileFailed, exceptionMessage, ex); } else { throw; } } } }); this.SharedTransferData.TotalLength = this.inputStream.Length; int count = (int)Math.Ceiling((double)(this.SharedTransferData.TotalLength - this.transferJob.CheckPoint.EntryTransferOffset) / this.Scheduler.TransferOptions.BlockSize); if (null != this.transferJob.CheckPoint.TransferWindow) { count += this.transferJob.CheckPoint.TransferWindow.Count; } this.lastTransferWindow = new Queue<long>(this.transferJob.CheckPoint.TransferWindow); this.md5HashStream = new MD5HashStream( this.inputStream, this.transferJob.CheckPoint.EntryTransferOffset, true); this.PreProcessed = true; if (!this.md5HashStream.FinishedSeparateMd5Calculator) { await Task.Run(() => { this.md5HashStream.CalculateMd5(this.Scheduler.MemoryManager, this.Controller.CheckCancellation); }); } if (0 == count) { this.countdownEvent = new CountdownEvent(1); this.SetChunkFinish(); } else { this.countdownEvent = new CountdownEvent(count); this.state = State.ReadStream; this.hasWork = true; } }
protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) { this.CloseOwnStream(); if (null != this.md5HashStream) { this.md5HashStream.Dispose(); this.md5HashStream = null; } if (null != this.countdownEvent) { this.countdownEvent.Dispose(); } } }