/// <summary> /// Hashes a requested number of subsegments within a file segment. /// </summary> /// <param name="memoryMappedFile">File, mapped to memory for very efficient access, to hash subsegments of</param> /// <param name="segmentStart">Position in file of the segment for which you want to hash subsegments</param> /// <param name="segmentLength">Length in file of the segment for which you want to hash subsegments</param> /// <param name="subsegmentCount">Number of subsegments to hash</param> /// <param name="hashAlgorithmName">Name of the hash algorithm to use</param> /// <returns>Colletion of <paramref name="subsegmentCount"/> hash segments</returns> public SegmentHash[] GetSubsegmentHashes( MemoryMappedFile memoryMappedFile, long segmentStart, long segmentLength, byte subsegmentCount, HashAlgorithmName hashAlgorithmName) { Contract.Requires(memoryMappedFile != null); Contract.Requires(segmentStart >= 0); Contract.Requires(segmentLength >= 0); Contract.Requires(subsegmentCount >= 1); Contract.Ensures(Contract.Result <SegmentHash[]>() != null); Contract.Ensures(Contract.Result <SegmentHash[]>().Length == subsegmentCount); Contract.Ensures(Contract.Result <SegmentHash[]>().All(h => h != null && !string.IsNullOrEmpty(h.Hash))); GetSegmentationParameters(segmentLength, subsegmentCount, out var standardSubsegmentLength, out var subsegmentLengths); using (var hasher = CryptoConfig.CreateFromName(hashAlgorithmName.Name) as HashAlgorithm) { var subsegmentHashes = new SegmentHash[subsegmentCount]; for (var i = 0; i < subsegmentLengths.Count(); ++i) { var start = segmentStart + i * standardSubsegmentLength; var length = subsegmentLengths[i]; subsegmentHashes[i] = GetSegmentHash(memoryMappedFile, hasher, start, length); } return(subsegmentHashes); } }
/// <summary> /// Finds the first segment in a file where it differs from a given reference set of segment hashes, and then /// drills down into that segment, pulling subsegment hashes for further comparison. /// </summary> /// <param name="referenceSegmentHashes">Segment hashes to compare the given file segments to</param> /// <param name="file">File to check against the <paramref name="referenceSegmentHashes"/></param> /// <param name="segmentStart">Position in file of the segment that is described by <paramref name="referenceSegmentHashes"/></param> /// <param name="segmentLength">Length in file of the segment that is described by <paramref name="referenceSegmentHashes"/></param> /// <param name="subsegmentCount">Number of subsegment hashes to break the first differing segment into</param> /// <param name="hashAlgorithmName">Hash algorithm name used for comparing data</param> /// <param name="diffSubsegmentHashes">Will be populated with the collection of <paramref name="subsegmentCount"/> hashes from the first differing segment or <c>null</c> if no difference is found.</param> /// <returns><c>true</c> if a difference is found, else <c>false</c></returns> public bool TryGetSubsegmentHashesOfFirstDiff( SegmentHash[] referenceSegmentHashes, FileInfo file, long segmentStart, long segmentLength, byte subsegmentCount, HashAlgorithmName hashAlgorithmName, out SegmentHash[] diffSubsegmentHashes) { Contract.Requires(referenceSegmentHashes != null && referenceSegmentHashes.Length > 0); Contract.Ensures(referenceSegmentHashes.All(h => h != null && !string.IsNullOrEmpty(h.Hash))); Contract.Requires(file != null); Contract.Requires(file.Exists); Contract.Requires(segmentStart >= 0); Contract.Requires(segmentLength >= 0); Contract.Requires(subsegmentCount >= 1); Contract.Ensures(Contract.ValueAtReturn(out diffSubsegmentHashes) != null); Contract.Ensures(Contract.ValueAtReturn(out diffSubsegmentHashes).Length == subsegmentCount); Contract.Ensures(Contract.ValueAtReturn(out diffSubsegmentHashes).All(h => h != null && !string.IsNullOrEmpty(h.Hash))); GetSegmentationParameters(segmentLength, subsegmentCount, out var standardSubsegmentLength, out var subsegmentLengths); using (var hasher = CryptoConfig.CreateFromName(hashAlgorithmName.Name) as HashAlgorithm) using (var memoryMappedFile = MemoryMappedFile.CreateFromFile(file.FullName)) { for (var i = 0; i < subsegmentLengths.Count(); ++i) { var start = segmentStart + i * standardSubsegmentLength; var length = subsegmentLengths[i]; SegmentHash subsegmentHash = GetSegmentHash(memoryMappedFile, hasher, start, length); if (subsegmentHash.Hash != referenceSegmentHashes[i].Hash) { diffSubsegmentHashes = this.GetSubsegmentHashes( memoryMappedFile, subsegmentHash.Start, subsegmentHash.Length, subsegmentCount, hashAlgorithmName); return(true); } } } diffSubsegmentHashes = null; return(false); }
private static SegmentHash GetSegmentHash(MemoryMappedFile memoryMappedFile, HashAlgorithm hasher, long start, long length) { Contract.Requires(memoryMappedFile != null); Contract.Requires(hasher != null); Contract.Requires(start >= 0); Contract.Requires(length >= 0); var segmentHash = new SegmentHash { Start = start, Length = length }; using (var segmentStream = memoryMappedFile.CreateViewStream(start, length, MemoryMappedFileAccess.Read)) { segmentHash.Hash = Convert.ToBase64String(hasher.ComputeHash(segmentStream)); } return(segmentHash); }