/// <summary> /// Initializes a new instance of the FileWriteStreamBase class for a file. /// </summary> /// <param name="file">File reference to write to.</param> /// <param name="fileSize">Size of the file.</param> /// <param name="createNew">Use <c>true</c> if the file is newly created, <c>false</c> otherwise.</param> /// <param name="accessCondition">An <see cref="AccessCondition"/> object that represents the access conditions for the file. If <c>null</c>, no condition is used.</param> /// <param name="options">An <see cref="FileRequestOptions"/> object that specifies additional options for the request.</param> /// <param name="operationContext">An <see cref="OperationContext"/> object for tracking the current operation.</param> protected FileWriteStreamBase(CloudFile file, long fileSize, bool createNew, AccessCondition accessCondition, FileRequestOptions options, OperationContext operationContext) : base() { this.internalBuffer = new MultiBufferMemoryStream(file.ServiceClient.BufferManager); this.currentOffset = 0; this.accessCondition = accessCondition; this.options = options; this.operationContext = operationContext; this.noPendingWritesEvent = new CounterEventAsync(); this.fileChecksum = new ChecksumWrapper(this.options.ChecksumOptions.StoreContentMD5.Value, this.options.ChecksumOptions.StoreContentCRC64.Value); this.rangeChecksum = new ChecksumWrapper(this.options.ChecksumOptions.UseTransactionalMD5.Value, this.options.ChecksumOptions.UseTransactionalCRC64.Value); #if !(NETCORE || WINDOWS_RT) this.parallelOperationSemaphoreAsync = new AsyncSemaphoreAsync(options.ParallelOperationThreadCount.Value); #else this.parallelOperationSemaphore = new AsyncSemaphore(options.ParallelOperationThreadCount.Value); #endif this.lastException = null; this.committed = false; this.disposed = false; this.currentFileOffset = 0; this.file = file; this.fileSize = fileSize; this.streamWriteSizeInBytes = file.StreamWriteSizeInBytes; this.newFile = createNew; }
/// <summary> /// Releases the file resources used by the Stream. /// </summary> /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param> protected override void Dispose(bool disposing) { if (disposing) { if (this.fileChecksum != null) { this.fileChecksum.Dispose(); this.fileChecksum = null; } if (this.rangeChecksum != null) { this.rangeChecksum.Dispose(); this.rangeChecksum = null; } if (this.internalBuffer != null) { this.internalBuffer.Dispose(); this.internalBuffer = null; } } base.Dispose(disposing); }
/// <summary> /// Initializes a new instance of the <see cref="FileReadStreamBase"/> class. /// </summary> /// <param name="file">File reference to read from</param> /// <param name="accessCondition">An <see cref="AccessCondition"/> object that represents the access conditions for the file. If <c>null</c>, no condition is used.</param> /// <param name="options">An <see cref="FileRequestOptions"/> object that specifies additional options for the request.</param> /// <param name="operationContext">An <see cref="OperationContext"/> object for tracking the current operation.</param> protected FileReadStreamBase(CloudFile file, AccessCondition accessCondition, FileRequestOptions options, OperationContext operationContext) { if (options.ChecksumOptions.UseTransactionalMD5.Value) { CommonUtility.AssertInBounds("StreamMinimumReadSizeInBytes", file.StreamMinimumReadSizeInBytes, 1, Constants.MaxRangeGetContentMD5Size); } if (options.ChecksumOptions.UseTransactionalCRC64.Value) { CommonUtility.AssertInBounds("StreamMinimumReadSizeInBytes", file.StreamMinimumReadSizeInBytes, 1, Constants.MaxRangeGetContentCRC64Size); } this.file = file; this.fileProperties = new FileProperties(file.Properties); this.currentOffset = 0; this.streamMinimumReadSizeInBytes = this.file.StreamMinimumReadSizeInBytes; this.internalBuffer = new MultiBufferMemoryStream(file.ServiceClient.BufferManager); this.accessCondition = accessCondition; this.options = options; this.operationContext = operationContext; this.fileChecksum = new ChecksumWrapper( calcMd5: !(this.options.ChecksumOptions.DisableContentMD5Validation.Value || string.IsNullOrEmpty(this.fileProperties.ContentChecksum.MD5)), calcCrc64: !(this.options.ChecksumOptions.DisableContentCRC64Validation.Value || string.IsNullOrEmpty(this.fileProperties.ContentChecksum.CRC64)) ); this.lastException = null; }
/// <summary> /// Sets the position within the current stream. /// </summary> /// <param name="offset">A byte offset relative to the origin parameter.</param> /// <param name="origin">A value of type <c>SeekOrigin</c> indicating the reference /// point used to obtain the new position.</param> /// <returns>The new position within the current stream.</returns> /// <remarks>Seeking in a FileReadStream disables checksum validation.</remarks> public override long Seek(long offset, SeekOrigin origin) { if (this.lastException != null) { throw this.lastException; } long newOffset; switch (origin) { case SeekOrigin.Begin: newOffset = offset; break; case SeekOrigin.Current: newOffset = this.currentOffset + offset; break; case SeekOrigin.End: newOffset = this.Length + offset; break; default: CommonUtility.ArgumentOutOfRange("origin", origin); throw new ArgumentOutOfRangeException("origin"); } CommonUtility.AssertInBounds("offset", newOffset, 0, this.Length); if (newOffset != this.currentOffset) { long bufferOffset = this.internalBuffer.Position + (newOffset - this.currentOffset); if ((bufferOffset >= 0) && (bufferOffset < this.internalBuffer.Length)) { this.internalBuffer.Position = bufferOffset; } else { this.internalBuffer.SetLength(0); } this.fileChecksum = null; this.currentOffset = newOffset; } return(this.currentOffset); }
/// <summary> /// Updates the blob checksum with newly downloaded content. /// </summary> /// <param name="buffer">The buffer to read the data from.</param> /// <param name="offset">The byte offset in buffer at which to begin reading data.</param> /// <param name="count">The maximum number of bytes to read.</param> protected void VerifyBlobChecksum(byte[] buffer, int offset, int count) { if ((this.blobChecksum != null) && (this.lastException == null) && (count > 0)) { this.blobChecksum.UpdateHash(buffer, offset, count); bool disposeBlobChecksum = false; if ((this.currentOffset == this.Length) && !string.IsNullOrEmpty(this.blobProperties.ContentChecksum.MD5) && this.blobChecksum.MD5 != default(MD5Wrapper)) { string computedMD5 = this.blobChecksum.MD5.ComputeHash(); if (!computedMD5.Equals(this.blobProperties.ContentChecksum.MD5)) { this.lastException = new IOException(string.Format( CultureInfo.InvariantCulture, SR.BlobDataCorrupted, this.blobProperties.ContentChecksum.MD5, computedMD5)); } } if ((this.currentOffset == this.Length) && !string.IsNullOrEmpty(this.blobProperties.ContentChecksum.CRC64) && this.blobChecksum.CRC64 != default(Crc64Wrapper)) { string computedCRC64 = this.blobChecksum.CRC64.ComputeHash(); if (!computedCRC64.Equals(this.blobProperties.ContentChecksum.CRC64)) { this.lastException = new IOException(string.Format( CultureInfo.InvariantCulture, SR.BlobDataCorrupted, this.blobProperties.ContentChecksum.CRC64, computedCRC64)); } } if (disposeBlobChecksum) { this.blobChecksum.Dispose(); this.blobChecksum = null; } } }
/// <summary> /// Initializes a new instance of the BlobWriteStreamBase class. /// </summary> /// <param name="serviceClient">The service client.</param> /// <param name="accessCondition">An <see cref="AccessCondition"/> object that represents the condition that must be met in order for the request to proceed. If <c>null</c>, no condition is used.</param> /// <param name="options">A <see cref="BlobRequestOptions"/> object that specifies additional options for the request.</param> /// <param name="operationContext">An <see cref="OperationContext"/> object that represents the context for the current operation.</param> private BlobWriteStreamBase(CloudBlobClient serviceClient, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext) : base() { this.internalBuffer = new MultiBufferMemoryStream(serviceClient.BufferManager); this.accessCondition = accessCondition; this.currentOffset = 0; this.options = options; this.operationContext = operationContext; this.noPendingWritesEvent = new CounterEventAsync(); this.blobChecksum = new ChecksumWrapper(this.options.ChecksumOptions.StoreContentMD5.Value, this.options.ChecksumOptions.StoreContentCRC64.Value); this.blockChecksum = new ChecksumWrapper(this.options.ChecksumOptions.UseTransactionalMD5.Value, this.options.ChecksumOptions.UseTransactionalCRC64.Value); #if WINDOWS_DESKTOP this.parallelOperationSemaphoreAsync = new AsyncSemaphoreAsync(options.ParallelOperationThreadCount.Value); #else this.parallelOperationSemaphore = new AsyncSemaphore(options.ParallelOperationThreadCount.Value); #endif this.lastException = null; this.committed = false; this.disposed = false; }