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