/// <summary> /// Calculate content hash of content in a stream. /// </summary> public static async Task <ContentHash> CalculateHashAsync(this StreamWithLength stream, HashType hashType) { using (var hasher = HashInfoLookup.Find(hashType).CreateContentHasher()) { return(await hasher.GetContentHashAsync(stream)); } }
/// <inheritdoc /> public async Task <ContentHash> GetContentHashAsync(StreamWithLength content) { var stopwatch = Stopwatch.StartNew(); try { using (var hasherHandle = CreateToken()) { var hasher = hasherHandle.Hasher; IPoolHandle <byte[]> bufferHandle; if (hasher is IHashAlgorithmBufferPool bufferPool) { bufferHandle = bufferPool.GetBufferFromPool(); } else { bufferHandle = _bufferPool.Get(); } using (bufferHandle) { var buffer = bufferHandle.Value; if (hasher is IHashAlgorithmInputLength sizeHint) { sizeHint.SetInputLength(content.Length - content.Stream.Position); } int bytesJustRead; do { int totalBytesRead = 0; int bytesNeeded = buffer.Length - totalBytesRead; do { bytesJustRead = await content.Stream.ReadAsync(buffer, totalBytesRead, buffer.Length - totalBytesRead).ConfigureAwait(false); totalBytesRead += bytesJustRead; bytesNeeded -= bytesJustRead; } while (bytesNeeded > 0 && bytesJustRead != 0); hasher.TransformBlock(buffer, 0, totalBytesRead, null, 0); } while (bytesJustRead > 0); hasher.TransformFinalBlock(buffer, 0, 0); var hashBytes = hasher.Hash; return(new ContentHash(Info.HashType, hashBytes)); } } } finally { stopwatch.Stop(); Interlocked.Add(ref _ticks, stopwatch.Elapsed.Ticks); Interlocked.Increment(ref _calls); } }
/// <nodoc /> public async Task <DedupNode> HashContentAndGetDedupNodeAsync(StreamWithLength content) { var contentHashDedupNodeTuple = await GetContentHashInternalAsync(content); // filestream has length so this is okay? if (contentHashDedupNodeTuple.Item2 == null) { throw new InvalidOperationException($"{nameof(HashContentAndGetDedupNodeAsync)}: dedup node was not retrievable after hashing content - incompatible hash type."); } return((DedupNode)contentHashDedupNodeTuple.Item2); }
/// <summary> /// Calculate content hash of content in a stream. /// </summary> public static Task <ContentHash> CalculateHashAsync(this StreamWithLength stream, HashType hashType) { #if NET_COREAPP if (stream.Stream is FileStream fileStream) { return(Task.FromResult(fileStream.HashFile(hashType))); } #endif // NET_COREAPP var hasher = HashInfoLookup.GetContentHasher(hashType); return(hasher.GetContentHashAsync(stream)); }
/// <summary> /// GetContentHashInternalAsync - for internal use only. /// </summary> /// <param name="content">Content stream with length.</param> /// <returns>A tuple of content hash and dedup node.</returns> protected async Task <(ContentHash, DedupNode?)> GetContentHashInternalAsync(StreamWithLength content) { var stopwatch = Stopwatch.StartNew(); try { using var hasherHandle = CreateToken(); var hasher = hasherHandle.Hasher; IPoolHandle <byte[]> bufferHandle; if (hasher is IHashAlgorithmBufferPool bufferPool) { bufferHandle = bufferPool.GetBufferFromPool(); } else { bufferHandle = _bufferPool.Get(); } using (bufferHandle) { var buffer = bufferHandle.Value; if (hasher is IHashAlgorithmInputLength sizeHint) { sizeHint.SetInputLength(content.Length - content.Stream.Position); } int bytesJustRead; do { int totalBytesRead = 0; int bytesNeeded = buffer.Length - totalBytesRead; do { bytesJustRead = await content.Stream.ReadAsync(buffer, totalBytesRead, buffer.Length - totalBytesRead).ConfigureAwait(false); totalBytesRead += bytesJustRead; bytesNeeded -= bytesJustRead; } while (bytesNeeded > 0 && bytesJustRead != 0); hasher.TransformBlock(buffer, 0, totalBytesRead, null, 0); } while (bytesJustRead > 0); hasher.TransformFinalBlock(buffer, 0, 0); var hashBytes = hasher.Hash !; // Retrieve the DedupNode before losing the hasher token. switch (Info.HashType) { case HashType.Dedup64K: case HashType.Dedup1024K: var contentHasher = (DedupNodeOrChunkHashAlgorithm)hasher; return(new ContentHash(Info.HashType, hashBytes), contentHasher.GetNode()); case HashType.SHA1: case HashType.SHA256: case HashType.MD5: case HashType.Vso0: case HashType.DedupSingleChunk: case HashType.DedupNode: case HashType.Murmur: return(new ContentHash(Info.HashType, hashBytes), null); default: throw new NotImplementedException($"Unsupported hashtype: {Info.HashType} encountered when hashing content."); } } } finally { stopwatch.Stop(); Interlocked.Add(ref _ticks, stopwatch.Elapsed.Ticks); Interlocked.Increment(ref _calls); } }
/// <inheritdoc /> public HashingStream CreateWriteHashingStream(StreamWithLength stream, long parallelHashingFileSizeBoundary = -1) { return(CreateWriteHashingStream(stream.Length, stream, parallelHashingFileSizeBoundary)); }
/// <inheritdoc /> public async Task <ContentHash> GetContentHashAsync(StreamWithLength content) { var(contentHash, _) = await GetContentHashInternalAsync(content); return(contentHash); }
/// <summary> /// Calculate content hash of content in a stream. /// </summary> public static Task <ContentHash> CalculateHashAsync(this StreamWithLength stream, HashType hashType) { var hasher = HashInfoLookup.GetContentHasher(hashType); return(hasher.GetContentHashAsync(stream)); }
/// <summary> /// Casts <see cref="StreamWithLength"/> to <see cref="FileStream"/>. /// </summary> public static FileStream ToFileStream(this StreamWithLength streamWithLength) => (FileStream)streamWithLength.Stream;