#region /* ----------------------------------------------------------------------- * * * Copyright 2011-2012 GRNET S.A. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and * documentation are those of the authors and should not be * interpreted as representing official policies, either expressed * or implied, of GRNET S.A. * * ----------------------------------------------------------------------- */ #endregion using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.Contracts; using System.Linq; using System.Reflection; using System.Security.Cryptography; using System.Text; using System.IO; using System.Text.RegularExpressions; using System.Threading.Tasks; using Pithos.Network; using log4net; namespace Pithos.Core.Agents { static class BlockExtensions { private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); public static int Read(this FileInfo fileInfo,byte[] buffer,long offset,int count) { if (offset < 0) throw new ArgumentOutOfRangeException("offset", offset, "The file offset can't be negative"); Contract.EndContractBlock(); //Open the stream only long enough to read a block using (var stream = fileInfo.OpenRead()) { stream.Seek(offset, SeekOrigin.Begin); return stream.Read(buffer, 0, count); } } public static string CalculateHash(this FileSystemInfo info,int blockSize,string algorithm) { if (info==null) throw new ArgumentNullException("info"); if (String.IsNullOrWhiteSpace(info.FullName)) throw new ArgumentException("info"); if (blockSize<=0) throw new ArgumentOutOfRangeException("blockSize",blockSize,"blockSize must be greater than 0"); if (String.IsNullOrWhiteSpace(algorithm)) throw new ArgumentNullException("algorithm"); Contract.EndContractBlock(); info.Refresh(); //The hash for directories is an empty string if (info is DirectoryInfo) return String.Empty; //The hash for non-existent files is an empty string if (!info.Exists) return String.Empty; return Signature.CalculateTreeHash(info.FullName, blockSize, algorithm).TopHash.ToHashString(); } /// ///Calculates a simple hash for an entire file /// /// The file to hash /// The hash algorithm to use /// A hash value for the entire file. An empty string if the file does not exist. public static string ComputeShortHash(this FileInfo info, HashAlgorithm hasher,IStatusNotification notification) { if(info == null) throw new ArgumentNullException("info"); if(hasher== null) throw new ArgumentNullException("hasher"); Contract.EndContractBlock(); info.Refresh(); if (!info.Exists) return String.Empty; if (Log.IsDebugEnabled) Log.DebugFormat("Short Hashing [{0}] ",info.FullName); var progress = new StatusNotification(""); using (var stream = new FileStream(info.FullName,FileMode.Open, FileAccess.Read, FileShare.Read,65536)) { var buffer = new byte[65536]; int counter=0; int bytesRead; do { bytesRead = stream.Read(buffer, 0, 32768); if (bytesRead > 0) { hasher.TransformBlock(buffer, 0, bytesRead, null, 0); } counter++; if (counter % 100 == 0) { progress.Title = String.Format("Hashing {0:p} of {1}", stream.Position*1.0/stream.Length, info.Name); notification.Notify(progress); } } while (bytesRead > 0); hasher.TransformFinalBlock(buffer, 0, 0); var hash = hasher.Hash; progress.Title = String.Format("Hashed {0} ", info.Name); notification.Notify(progress); var hashString = hash.ToHashString(); return hashString; } } public static string ComputeShortHash(this FileInfo info,IStatusNotification notification) { if(info == null) throw new ArgumentNullException("info"); Contract.EndContractBlock(); using (var hasher=HashAlgorithm.Create("md5")) { return ComputeShortHash(info,hasher,notification); } } } }