Changes to hash calculation.
authorpkanavos <pkanavos@gmail.com>
Wed, 29 Aug 2012 14:56:40 +0000 (17:56 +0300)
committerpkanavos <pkanavos@gmail.com>
Wed, 29 Aug 2012 14:57:00 +0000 (17:57 +0300)
SyncSingleItem not yet tested

trunk/Pithos.Client.WPF/Properties/AssemblyInfo.cs
trunk/Pithos.Core.Test/MockStatusKeeper.cs
trunk/Pithos.Core/Agents/BlockExtensions.cs
trunk/Pithos.Core/Agents/PollAgent.cs
trunk/Pithos.Core/Agents/StateTuple.cs
trunk/Pithos.Core/Agents/StatusAgent.cs
trunk/Pithos.Core/Agents/Uploader.cs
trunk/Pithos.Core/FileState.cs
trunk/Pithos.Core/IStatusKeeper.cs
trunk/Pithos.Interfaces/FileInfoExtensions.cs
trunk/Pithos.Network/Signature.cs

index 87003e9..8298ca6 100644 (file)
@@ -1,97 +1,97 @@
-#region
-/* -----------------------------------------------------------------------
- * <copyright file="AssemblyInfo.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.Reflection;
-using System.Resources;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Windows;
-
-// General Information about an assembly is controlled through the following 
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyCompany("GRNET")]
-[assembly: AssemblyCopyright("Copyright © GRNet 2011-2012")]
-[assembly: AssemblyProduct("Pithos+ Client for Windows")]
-[assembly: AssemblyTitle("Pithos+ Client for Windows")]
-[assembly: AssemblyDescription("Pithos+ Client for Windows")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-
-// Setting ComVisible to false makes the types in this assembly not visible 
-// to COM components.  If you need to access a type in this assembly from 
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-//In order to begin building localizable applications, set 
-//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
-//inside a <PropertyGroup>.  For example, if you are using US english
-//in your source files, set the <UICulture> to en-US.  Then uncomment
-//the NeutralResourceLanguage attribute below.  Update the "en-US" in
-//the line below to match the UICulture setting in the project file.
-
-//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
-
-
-[assembly: ThemeInfo(
-    ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
-    //(used if a resource is not found in the page, 
-    // or application resource dictionaries)
-    ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
-    //(used if a resource is not found in the page, 
-    // app, or any theme specific resource dictionaries)
-)]
-
-
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version 
-//      Build Number
-//      Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers 
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyInformationalVersion("2012-07-06")]
-[assembly: AssemblyVersion("0.8.20710.14")]
+#region\r
+/* -----------------------------------------------------------------------\r
+ * <copyright file="AssemblyInfo.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.Reflection;\r
+using System.Resources;\r
+using System.Runtime.CompilerServices;\r
+using System.Runtime.InteropServices;\r
+using System.Windows;\r
+\r
+// General Information about an assembly is controlled through the following \r
+// set of attributes. Change these attribute values to modify the information\r
+// associated with an assembly.\r
+[assembly: AssemblyCompany("GRNET")]\r
+[assembly: AssemblyCopyright("Copyright © GRNet 2011-2012")]\r
+[assembly: AssemblyProduct("Pithos+ Client for Windows")]\r
+[assembly: AssemblyTitle("Pithos+ Client for Windows")]\r
+[assembly: AssemblyDescription("Pithos+ Client for Windows")]\r
+[assembly: AssemblyConfiguration("")]\r
+[assembly: AssemblyTrademark("")]\r
+[assembly: AssemblyCulture("")]\r
+\r
+\r
+// Setting ComVisible to false makes the types in this assembly not visible \r
+// to COM components.  If you need to access a type in this assembly from \r
+// COM, set the ComVisible attribute to true on that type.\r
+[assembly: ComVisible(false)]\r
+\r
+//In order to begin building localizable applications, set \r
+//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file\r
+//inside a <PropertyGroup>.  For example, if you are using US english\r
+//in your source files, set the <UICulture> to en-US.  Then uncomment\r
+//the NeutralResourceLanguage attribute below.  Update the "en-US" in\r
+//the line below to match the UICulture setting in the project file.\r
+\r
+//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]\r
+\r
+\r
+[assembly: ThemeInfo(\r
+    ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located\r
+    //(used if a resource is not found in the page, \r
+    // or application resource dictionaries)\r
+    ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located\r
+    //(used if a resource is not found in the page, \r
+    // app, or any theme specific resource dictionaries)\r
+)]\r
+\r
+\r
+// Version information for an assembly consists of the following four values:\r
+//\r
+//      Major Version\r
+//      Minor Version \r
+//      Build Number\r
+//      Revision\r
+//\r
+// You can specify all the values or you can default the Build and Revision Numbers \r
+// by using the '*' as shown below:\r
+// [assembly: AssemblyVersion("1.0.*")]\r
+[assembly: AssemblyInformationalVersion("2012-07-06")]\r
+[assembly: AssemblyVersion("0.8.20829.0")]\r
index 73a4efa..9db184d 100644 (file)
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Diagnostics.Contracts;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Pithos.Interfaces;
-using Pithos.Network;
-
-namespace Pithos.Core.Test
-{
-    public class MockStatusChecker : IStatusChecker, IStatusKeeper
-    {
-        public IPithosSettings Settings { get; set; }
-
-        private readonly string[] _states = { "Normal", "Modified", "Conflict", "Synch" };
-
-        readonly ConcurrentDictionary<string, FileOverlayStatus> _overlayCache = new ConcurrentDictionary<string, FileOverlayStatus>();
-        readonly ConcurrentDictionary<string, FileStatus> _statusCache = new ConcurrentDictionary<string, FileStatus>();
-        readonly ConcurrentDictionary<string, string> _checksums = new ConcurrentDictionary<string, string>();
-
-        public FileOverlayStatus GetFileOverlayStatus(string path)
-        {
-            
-            if (!_overlayCache.ContainsKey(path))
-                return FileOverlayStatus.Unversioned;
-
-            var pithosPath = Settings.PithosPath;
-            if (path.StartsWith(pithosPath, true, null))
-            {
-                var status = _overlayCache[path];
-                return status;
-            }
-            return FileOverlayStatus.Unversioned;
-        }
-
-        public void ProcessExistingFiles(IEnumerable<FileInfo> paths)
-        {
-
-            var newFiles = (from file in paths
-                            where !_overlayCache.ContainsKey(file.FullName)
-                            select new
-                            {
-                                FilePath = file.FullName.ToLower(),
-                                OverlayStatus = FileOverlayStatus.Unversioned,
-                                FileStatus = FileStatus.Created,
-                                Checksum = Signature.CalculateMD5(file)
-                            });
-            var files = new ConcurrentBag<string>();
-            foreach (var state in newFiles)
-            {            
-                _overlayCache[state.FilePath] = state.OverlayStatus;
-                _statusCache[state.FilePath] = state.FileStatus;
-                _checksums[state.FilePath] = state.Checksum;
-                files.Add(state.FilePath);
-            }            
-            
-        }
-
-        public void Stop()
-        {
-            throw new NotImplementedException();
-        }
-
-        public void SetFileState(string path, FileStatus fileStatus, FileOverlayStatus overlayStatus, string localFileMissingFromServer)
-        {
-            if (String.IsNullOrWhiteSpace(path))
-                throw new ArgumentNullException("path", "path can't be empty");
-            SetFileStatus(path, fileStatus);
-            SetFileOverlayStatus(path, overlayStatus);
-        }
-
-        public void StoreInfo(string path, ObjectInfo objectInfo)
-        {
-            if (String.IsNullOrWhiteSpace(path))
-                throw new ArgumentNullException("path", "path can't be empty");
-            if (objectInfo == null)
-                throw new ArgumentNullException("objectInfo", "objectInfo can't be empty");
-
-            _statusCache[path] = FileStatus.Unchanged;
-            _overlayCache[path] = FileOverlayStatus.Normal;
-            _checksums[path] = objectInfo.X_Object_Hash;
-
-
-        }
-
-        public T GetStatus<T>(string path, Func<FileState, T> getter, T defaultValue)
-        {
-            throw new NotImplementedException();
-        }
-
-        public void SetStatus(string path, Action<FileState> setter)
-        {
-            throw new NotImplementedException();
-        }
-
-        ConcurrentDictionary<string, NetworkOperation> _networkState = new ConcurrentDictionary<string, NetworkOperation>();
-
-
-        public void SetNetworkState(string path, NetworkOperation operation)
-        {
-            _networkState[path.ToLower()] = operation;
-            //Removing may fail so we store the "None" value anyway
-            if (operation == NetworkOperation.None)
-            {
-                NetworkOperation oldOperation;
-                _networkState.TryRemove(path, out oldOperation);
-            }
-        }
-
-        public NetworkOperation GetNetworkState(string path)
-        {
-            NetworkOperation operation;
-            if (_networkState.TryGetValue(path, out operation))
-                return operation;
-            return NetworkOperation.None;
-        }
-
-        public void StartProcessing(CancellationToken token)
-        {
-            
-        }
-
-        public string BlockHash { get; set; }
-
-        public int BlockSize { get; set; }
-
-        public IStatusNotification StatusNotification { get; set; }
-
-        public void ChangeRoots(string oldPath, string newPath)
-        {
-            throw new NotImplementedException();
-        }
-
-        public FileState GetStateByFilePath(string path)
-        {
-            throw new NotImplementedException();
-        }
-
-        public void ClearFolderStatus(string path)
-        {
-            throw new NotImplementedException();
-        }
-
-        public IEnumerable<FileState> GetChildren(FileState fileState)
-        {
-            throw new NotImplementedException();
-        }
-
-        public void EnsureFileState(string path)
-        {
-            throw new NotImplementedException();
-        }
-
-
-        private PithosStatus _pithosStatus = PithosStatus.InSynch;
-        public void SetPithosStatus(PithosStatus status)
-        {
-            _pithosStatus = status;
-        }
-
-        public PithosStatus GetPithosStatus()
-        {
-            return _pithosStatus;
-        }
-
-        public Task SetFileOverlayStatus(string path, FileOverlayStatus overlayStatus, string etag = null)
-        {
-            _overlayCache[path] = overlayStatus;
-            return Task.Factory.StartNew(()=>{});
-        }
-
-        public void RemoveFileOverlayStatus(string path)
-        {
-            FileOverlayStatus value;
-            _overlayCache.TryRemove(path, out value);
-        }
-
-        public void RenameFileOverlayStatus(string oldPath, string newPath)
-        {
-            var status = _overlayCache[oldPath];
-            _overlayCache[newPath] = status;
-            FileOverlayStatus value;
-            _overlayCache.TryRemove(oldPath, out value);
-        }
-
-        public void UpdateFileChecksum(string path, string etag, string checksum)
-        {
-            _checksums[path] = checksum;
-        }
-
-        public void SetFileStatus(string path, FileStatus status)
-        {
-            _statusCache[path] = status;
-        }
-
-        public FileStatus GetFileStatus(string path)
-        {
-            if (!_statusCache.ContainsKey(path))
-                return FileStatus.Missing;
-            return _statusCache[path];
-        }
-
-        public void ClearFileStatus(string path)
-        {
-            FileStatus value;
-            _statusCache.TryRemove(path,out value);
-        }
-
-
-        public void CleanupStaleStates(AccountInfo accountInfo, List<ObjectInfo> objectInfos)
-        {
-            //throw new NotImplementedException();
-        }
-
-
-        public void CleanupOrphanStates()
-        {
-            throw new NotImplementedException();
-        }
-
-        public void UpdateLastMD5(FileInfo path, string etag)
-        {
-            throw new NotImplementedException();
-        }
-    }
-}
+using System;\r
+using System.Collections.Concurrent;\r
+using System.Collections.Generic;\r
+using System.Diagnostics.Contracts;\r
+using System.IO;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+using Pithos.Interfaces;\r
+using Pithos.Network;\r
+\r
+namespace Pithos.Core.Test\r
+{\r
+    public class MockStatusChecker : IStatusChecker, IStatusKeeper\r
+    {\r
+        public IPithosSettings Settings { get; set; }\r
+\r
+        private readonly string[] _states = { "Normal", "Modified", "Conflict", "Synch" };\r
+\r
+        readonly ConcurrentDictionary<string, FileOverlayStatus> _overlayCache = new ConcurrentDictionary<string, FileOverlayStatus>();\r
+        readonly ConcurrentDictionary<string, FileStatus> _statusCache = new ConcurrentDictionary<string, FileStatus>();\r
+        readonly ConcurrentDictionary<string, string> _checksums = new ConcurrentDictionary<string, string>();\r
+\r
+        public FileOverlayStatus GetFileOverlayStatus(string path)\r
+        {\r
+            \r
+            if (!_overlayCache.ContainsKey(path))\r
+                return FileOverlayStatus.Unversioned;\r
+\r
+            var pithosPath = Settings.PithosPath;\r
+            if (path.StartsWith(pithosPath, true, null))\r
+            {\r
+                var status = _overlayCache[path];\r
+                return status;\r
+            }\r
+            return FileOverlayStatus.Unversioned;\r
+        }\r
+\r
+        public void ProcessExistingFiles(IEnumerable<FileInfo> paths)\r
+        {\r
+\r
+            var newFiles = (from file in paths\r
+                            where !_overlayCache.ContainsKey(file.FullName)\r
+                            select new\r
+                            {\r
+                                FilePath = file.FullName.ToLower(),\r
+                                OverlayStatus = FileOverlayStatus.Unversioned,\r
+                                FileStatus = FileStatus.Created,\r
+                                Checksum = Signature.CalculateMD5(file)\r
+                            });\r
+            var files = new ConcurrentBag<string>();\r
+            foreach (var state in newFiles)\r
+            {            \r
+                _overlayCache[state.FilePath] = state.OverlayStatus;\r
+                _statusCache[state.FilePath] = state.FileStatus;\r
+                _checksums[state.FilePath] = state.Checksum;\r
+                files.Add(state.FilePath);\r
+            }            \r
+            \r
+        }\r
+\r
+        public void Stop()\r
+        {\r
+            throw new NotImplementedException();\r
+        }\r
+\r
+        public void SetFileState(string path, FileStatus fileStatus, FileOverlayStatus overlayStatus, string localFileMissingFromServer)\r
+        {\r
+            if (String.IsNullOrWhiteSpace(path))\r
+                throw new ArgumentNullException("path", "path can't be empty");\r
+            SetFileStatus(path, fileStatus);\r
+            SetFileOverlayStatus(path, overlayStatus);\r
+        }\r
+\r
+        public void StoreInfo(string path, ObjectInfo objectInfo)\r
+        {\r
+            if (String.IsNullOrWhiteSpace(path))\r
+                throw new ArgumentNullException("path", "path can't be empty");\r
+            if (objectInfo == null)\r
+                throw new ArgumentNullException("objectInfo", "objectInfo can't be empty");\r
+\r
+            _statusCache[path] = FileStatus.Unchanged;\r
+            _overlayCache[path] = FileOverlayStatus.Normal;\r
+            _checksums[path] = objectInfo.X_Object_Hash;\r
+\r
+\r
+        }\r
+\r
+        public T GetStatus<T>(string path, Func<FileState, T> getter, T defaultValue)\r
+        {\r
+            throw new NotImplementedException();\r
+        }\r
+\r
+        public void SetStatus(string path, Action<FileState> setter)\r
+        {\r
+            throw new NotImplementedException();\r
+        }\r
+\r
+        ConcurrentDictionary<string, NetworkOperation> _networkState = new ConcurrentDictionary<string, NetworkOperation>();\r
+\r
+\r
+        public void SetNetworkState(string path, NetworkOperation operation)\r
+        {\r
+            _networkState[path.ToLower()] = operation;\r
+            //Removing may fail so we store the "None" value anyway\r
+            if (operation == NetworkOperation.None)\r
+            {\r
+                NetworkOperation oldOperation;\r
+                _networkState.TryRemove(path, out oldOperation);\r
+            }\r
+        }\r
+\r
+        public NetworkOperation GetNetworkState(string path)\r
+        {\r
+            NetworkOperation operation;\r
+            if (_networkState.TryGetValue(path, out operation))\r
+                return operation;\r
+            return NetworkOperation.None;\r
+        }\r
+\r
+        public void StartProcessing(CancellationToken token)\r
+        {\r
+            \r
+        }\r
+\r
+        public string BlockHash { get; set; }\r
+\r
+        public int BlockSize { get; set; }\r
+\r
+        public IStatusNotification StatusNotification { get; set; }\r
+\r
+        public void ChangeRoots(string oldPath, string newPath)\r
+        {\r
+            throw new NotImplementedException();\r
+        }\r
+\r
+        public FileState GetStateByFilePath(string path)\r
+        {\r
+            throw new NotImplementedException();\r
+        }\r
+\r
+        public void ClearFolderStatus(string path)\r
+        {\r
+            throw new NotImplementedException();\r
+        }\r
+\r
+        public IEnumerable<FileState> GetChildren(FileState fileState)\r
+        {\r
+            throw new NotImplementedException();\r
+        }\r
+\r
+        public void EnsureFileState(string path)\r
+        {\r
+            throw new NotImplementedException();\r
+        }\r
+\r
+\r
+        private PithosStatus _pithosStatus = PithosStatus.InSynch;\r
+        public void SetPithosStatus(PithosStatus status)\r
+        {\r
+            _pithosStatus = status;\r
+        }\r
+\r
+        public PithosStatus GetPithosStatus()\r
+        {\r
+            return _pithosStatus;\r
+        }\r
+\r
+        public Task SetFileOverlayStatus(string path, FileOverlayStatus overlayStatus, string etag = null)\r
+        {\r
+            _overlayCache[path] = overlayStatus;\r
+            return Task.Factory.StartNew(()=>{});\r
+        }\r
+\r
+        public void RemoveFileOverlayStatus(string path)\r
+        {\r
+            FileOverlayStatus value;\r
+            _overlayCache.TryRemove(path, out value);\r
+        }\r
+\r
+        public void RenameFileOverlayStatus(string oldPath, string newPath)\r
+        {\r
+            var status = _overlayCache[oldPath];\r
+            _overlayCache[newPath] = status;\r
+            FileOverlayStatus value;\r
+            _overlayCache.TryRemove(oldPath, out value);\r
+        }\r
+\r
+        public void UpdateFileChecksum(string path, string etag, string checksum)\r
+        {\r
+            _checksums[path] = checksum;\r
+        }\r
+\r
+        public void UpdateFileTreeHash(string path, TreeHash treeHash)\r
+        {\r
+            throw new NotImplementedException();\r
+        }\r
+\r
+        public void SetFileStatus(string path, FileStatus status)\r
+        {\r
+            _statusCache[path] = status;\r
+        }\r
+\r
+        public FileStatus GetFileStatus(string path)\r
+        {\r
+            if (!_statusCache.ContainsKey(path))\r
+                return FileStatus.Missing;\r
+            return _statusCache[path];\r
+        }\r
+\r
+        public void ClearFileStatus(string path)\r
+        {\r
+            FileStatus value;\r
+            _statusCache.TryRemove(path,out value);\r
+        }\r
+\r
+\r
+        public void CleanupStaleStates(AccountInfo accountInfo, List<ObjectInfo> objectInfos)\r
+        {\r
+            //throw new NotImplementedException();\r
+        }\r
+\r
+\r
+        public void CleanupOrphanStates()\r
+        {\r
+            throw new NotImplementedException();\r
+        }\r
+\r
+        public void UpdateLastMD5(FileInfo path, string etag)\r
+        {\r
+            throw new NotImplementedException();\r
+        }\r
+    }\r
+}\r
index 0dd94ec..5cd73c6 100644 (file)
-#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;
-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;
-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,CancellationToken token,IProgress<double> progress )
-        {
-            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();
-           if (info.FullName.Split('/').Contains(".pithos.cache"))
-               throw new ArgumentException(String.Format("Trying to hash file from the cache folder: [{0}]", info.FullName));
-
-           //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,token,progress).TopHash.ToHashString();
-
-        }
-
-       /// <summary>
-       ///Calculates a simple hash for an entire file
-       /// </summary>
-       /// <param name="info">The file to hash</param>
-       /// <param name="hasher">The hash algorithm to use</param>
-       /// <returns>A hash value for the entire file. An empty string if the file does not exist.</returns>
-       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 (info.FullName.Split('/').Contains(".pithos.cache"))
-               throw new ArgumentException(String.Format("Trying to hash file from the cache folder: [{0}]", info.FullName));
-
-           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,Signature.BufferSize))
-           {
-               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 async Task<string> ComputeShortHash(this FileInfo info, MD5BlockCalculator calculator,IStatusNotification notification)
-       {
-           if(info == null)
-               throw new ArgumentNullException("info");
-           if(calculator== null)
-               throw new ArgumentNullException("calculator");
-           Contract.EndContractBlock();
-           info.Refresh();
-           if (!info.Exists)
-               return String.Empty;
-
-           if (info.FullName.Split('/').Contains(".pithos.cache"))
-               throw new ArgumentException(String.Format("Trying to hash file from the cache folder: [{0}]", info.FullName));
-
-           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,Signature.BufferSize))
-           {
-               int counter=0;
-               int bytesRead;
-               do
-               {
-                   var buffer = new byte[65536];
-                   bytesRead = stream.Read(buffer, 0, 32768);
-                   if (bytesRead > 0)
-                   {
-                       calculator.PostBlock(counter,buffer,bytesRead);
-                   }
-                   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);
-
-               var hashString = await calculator.GetHash();
-               
-
-               progress.Title = String.Format("Hashed {0} ", info.Name);
-               notification.Notify(progress);
-
-
-               return hashString;
-           }
-       }
-
-        public static string ComputeShortHash(this FileInfo info,IStatusNotification notification)
-       {
-           if(info == null)
-               throw new ArgumentNullException("info");
-            Contract.EndContractBlock();
-            if (info.FullName.Split('/').Contains(".pithos.cache"))
-                throw new ArgumentException(String.Format("Trying to hash file from the cache folder: [{0}]", info.FullName));
-
-           using (var hasher=HashAlgorithm.Create("md5"))
-           {               
-               return ComputeShortHash(info,hasher,notification);
-           }
-       }
-
-    }
-}
+#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
+       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
index 385bb8f..1e39baf 100644 (file)
@@ -933,7 +933,7 @@ namespace Pithos.Core.Agents
                 if (tuplesByPath.TryGetValue(state.FilePath, out hashTuple))\r
                 {\r
                     hashTuple.FileState = state;\r
-                    UpdateMD5(hashTuple);\r
+                    UpdateHashes(hashTuple);\r
                 }\r
                 else\r
                 {\r
@@ -959,7 +959,7 @@ namespace Pithos.Core.Agents
             //for files that don't have state\r
             foreach (var tuple in tuplesByPath.Values.Where(t => t.FileState == null))\r
             {\r
-                UpdateMD5(tuple);\r
+                UpdateHashes(tuple);\r
             }\r
 \r
             var tuplesByID = tuplesByPath.Values\r
@@ -997,31 +997,69 @@ namespace Pithos.Core.Agents
             return tuplesByPath.Values;\r
         }\r
 \r
-        private void  UpdateMD5(StateTuple hashTuple)\r
+        \r
+        /// <summary>\r
+        /// Update the tuple with the file's hashes, avoiding calculation if the file is unchanged\r
+        /// </summary>\r
+        /// <param name="hashTuple"></param>\r
+        /// <remarks>\r
+        /// The function first checks the file's size and last write date to see if there are any changes. If there are none,\r
+        /// the file's stored hashes are used.\r
+        /// Otherwise, MD5 is calculated first to ensure there are no changes. If MD5 is different, the Merkle hash is calculated\r
+        /// </remarks>\r
+        private void  UpdateHashes(StateTuple hashTuple)\r
         {\r
             \r
             try\r
             {\r
-                var hash = Signature.MD5_EMPTY;\r
+                var state = hashTuple.NullSafe(s => s.FileState);\r
+                var storedHash = state.NullSafe(s => s.Checksum);\r
+                var storedHashes = state.NullSafe(s => s.Hashes);\r
+                var storedMD5 = state.NullSafe(s => s.LastMD5);\r
+                var storedDate = state.NullSafe(s => s.LastWriteDate) ?? DateTime.MinValue;\r
+                var storedLength = state.NullSafe(s => s.LastLength);\r
+\r
+                var md5Hash = Signature.MD5_EMPTY;\r
+                var topHash = storedHash ?? Signature.MERKLE_EMPTY;\r
+                \r
+                var merkle=TreeHash.Empty;\r
                 if (hashTuple.FileInfo is FileInfo)\r
                 {\r
-                    var file = hashTuple.FileInfo as FileInfo;\r
-                    var stateDate = hashTuple.NullSafe(h => h.FileState).NullSafe(s => s.LastWriteDate) ??\r
-                                    DateTime.MinValue;\r
-                    if (file.LastWriteTime - stateDate < TimeSpan.FromSeconds(1) &&\r
-                        hashTuple.FileState.LastLength == file.Length)\r
-                    {\r
-                        hash = hashTuple.FileState.LastMD5;\r
-                    }\r
-                    else\r
-                    {\r
-                        //Modified, must calculate hash\r
-                        hash = file.ComputeShortHash(StatusNotification);\r
-                        StatusKeeper.UpdateLastMD5(file, hash);\r
-                    }\r
+                    var file = hashTuple.FileInfo.WithProperCapitalization() as FileInfo;\r
+                    //Attributes unchanged?\r
+\r
+                    var unchangedAttributes = file.LastWriteTime - storedDate < TimeSpan.FromSeconds(1) \r
+                        && storedLength == file.Length;\r
+                    \r
+                    //Attributes appear unchanged but the file length doesn't match the stored hash\r
+                    var nonEmptyMismatch = unchangedAttributes && \r
+                        (file.Length == 0 ^ storedHash== Signature.MERKLE_EMPTY);\r
+\r
+                    //Missing hashes for NON-EMPTY hash\r
+                    var missingHashes = storedHash != Signature.MERKLE_EMPTY &&\r
+                        String.IsNullOrWhiteSpace(storedHashes);\r
+\r
+                    //Unchanged attributes but changed MD5 \r
+                    //Short-circuiting ensures MD5 is computed only if the attributes are changed\r
+                    var md5Mismatch = (!unchangedAttributes &&\r
+                                       file.ComputeShortHash(StatusNotification) != storedMD5);\r
+\r
+\r
+                    //If the attributes are unchanged but the Merkle doesn't match the size,\r
+                    //or the attributes and the MD5 hash have changed, \r
+                    //or the hashes are missing but the tophash is NOT empty, we need to recalculate\r
+                    //\r
+                    //Otherwise we load the hashes from state\r
+                    merkle = (nonEmptyMismatch || md5Mismatch || missingHashes)\r
+                                 ? RecalculateTreehash(file)\r
+                                 : TreeHash.Parse(hashTuple.FileState.Hashes);\r
+\r
+\r
+                    md5Hash = merkle.MD5;\r
                 }\r
-                hashTuple.C = hash;\r
-                hashTuple.MD5 = hash;\r
+                hashTuple.MD5 = md5Hash;\r
+                //Setting Merkle also updates C\r
+                hashTuple.Merkle = merkle;\r
             }\r
             catch (IOException)\r
             {\r
@@ -1030,6 +1068,21 @@ namespace Pithos.Core.Agents
         }\r
 \r
         /// <summary>\r
+        /// Recalculate a file's treehash and md5 and update the database\r
+        /// </summary>\r
+        /// <param name="file"></param>\r
+        /// <returns></returns>\r
+        private TreeHash RecalculateTreehash(FileInfo file)\r
+        {\r
+            var progress = new Progress<double>(d =>StatusNotification.Notify(\r
+                                                    new StatusNotification(String.Format("Hashing {0} of {1}", d, file.Name))));\r
+            var merkle = Signature.CalculateTreeHash(file, StatusKeeper.BlockSize, \r
+                StatusKeeper.BlockHash,CancellationToken, progress);\r
+            StatusKeeper.UpdateFileTreeHash(file.FullName, merkle);\r
+            return merkle;\r
+        }\r
+\r
+        /// <summary>\r
         /// Returns the latest LastModified date from the list of objects, but only if it is before\r
         /// than the threshold value\r
         /// </summary>\r
index 4ffb9b5..4d83869 100644 (file)
@@ -11,18 +11,36 @@ namespace Pithos.Core.Agents
     {\r
         public string FilePath { get; private set; }\r
 \r
-        public string MD5 { get; set; }\r
+        public string MD5\r
+        {\r
+            get\r
+            {\r
+                Debug.Assert(EmptyOrLength(_md5, 32));\r
+                return _md5;\r
+            }\r
+            set\r
+            {\r
+                if (!EmptyOrLength(value, 32))\r
+                    throw new ArgumentException("A proper MD5 hash value should have 32 characters");\r
+                _md5 = value;\r
+            }\r
+        }\r
+\r
+        private bool EmptyOrLength(string value, int length)\r
+        {\r
+            return String.IsNullOrWhiteSpace(value) || value.Length == length;\r
+        }\r
 \r
         public string L\r
         {\r
             get\r
             {\r
                 //For the change to Merkle Hash, we need to return the final Merkle Hash\r
-                //var hash = FileState.NullSafe(f => f.Checksum);\r
-                var hash = FileState.NullSafe(f => f.ETag);\r
+                var hash = FileState.NullSafe(f => f.Checksum);\r
+                //var hash = FileState.NullSafe(f => f.ETag);\r
                 \r
                 //Ensure the hash size matches SHA256\r
-                //Debug.Assert(hash==null||hash.Length==64);\r
+                Debug.Assert(EmptyOrLength(hash, 64));\r
                 \r
                 return String.IsNullOrWhiteSpace(hash) ? null : hash;\r
             }\r
@@ -33,14 +51,12 @@ namespace Pithos.Core.Agents
         {\r
             get\r
             {\r
-                Debug.Assert(_c==null||_c.Length==64);\r
+                Debug.Assert(EmptyOrLength(_c, 64));\r
                 return _c;\r
             }\r
             set {\r
-/*\r
-                if (value!=null && value.Length!=64)\r
-                    throw new Invali\r
-*/\r
+                if (!EmptyOrLength(value, 64))\r
+                    throw new ArgumentException("A proper hash value should have 64 characters");\r
                 _c = String.IsNullOrWhiteSpace(value) ? null : value;\r
             }\r
         }\r
@@ -49,13 +65,18 @@ namespace Pithos.Core.Agents
         {\r
             get\r
             {\r
-                var etag = ObjectInfo.NullSafe(o => o.ETag);\r
-                return String.IsNullOrWhiteSpace(etag) ? null : etag;\r
+                //The Server hash will be the X-Object-Hash, not the ETag\r
+                var hash= ObjectInfo.NullSafe(o => o.X_Object_Hash);\r
+\r
+                Debug.Assert(EmptyOrLength(hash, 64));\r
+                \r
+                return String.IsNullOrWhiteSpace(hash) ? null : hash;\r
             }\r
         }\r
 \r
         private FileSystemInfo _fileInfo;\r
         private TreeHash _merkle;\r
+        private string _md5;\r
 \r
         public FileSystemInfo FileInfo\r
         {\r
@@ -78,7 +99,7 @@ namespace Pithos.Core.Agents
             }\r
             set {\r
                 _merkle = value;\r
-                C = _merkle.MD5;\r
+                C = _merkle.TopHash.ToHashString();\r
             }\r
         }\r
 \r
@@ -99,9 +120,9 @@ namespace Pithos.Core.Agents
 \r
         public bool HashesValid()\r
         {\r
-            return ( (C==null || C.Length == 32) \r
-                  && (L==null || L.Length == 32) \r
-                  && (S==null || S.Length == 32)\r
+            return (EmptyOrLength(C, 64)\r
+                  && EmptyOrLength(L, 64)\r
+                  && EmptyOrLength(S, 64)\r
                 );\r
         }\r
     }\r
index 63f1b3b..90d950d 100644 (file)
@@ -178,9 +178,9 @@ namespace Pithos.Core.Agents
             const string createVersionCmd = "create table Version(Id integer,Version TEXT);\n" +\r
                                             "INSERT INTO VERSION (Id,Version) VALUES(1,'0.0.0.0');";\r
             const string createFileStateCmd =\r
-                "CREATE TABLE FileState (Id UNIQUEIDENTIFIER not null, ObjectID TEXT COLLATE NOCASE, FilePath TEXT unique COLLATE NOCASE, OverlayStatus INTEGER, FileStatus INTEGER, ConflictReason TEXT, Checksum TEXT COLLATE NOCASE, ETag TEXT not null COLLATE NOCASE, LastMD5 TEXT not null COLLATE NOCASE, LastWriteDate DATETIME, LastLength INTEGER, Version INTEGER, VersionTimeStamp DATETIME, IsShared INTEGER, SharedBy TEXT, ShareWrite INTEGER, IsFolder INTEGER, Modified DATETIME, primary key (Id),unique (FilePath))";\r
+                "CREATE TABLE FileState (Id UNIQUEIDENTIFIER not null, ObjectID TEXT COLLATE NOCASE, FilePath TEXT unique COLLATE NOCASE, OverlayStatus INTEGER, FileStatus INTEGER, ConflictReason TEXT, Checksum TEXT COLLATE NOCASE, ETag TEXT not null COLLATE NOCASE, LastMD5 TEXT not null COLLATE NOCASE,LastWriteDate DATETIME, LastLength INTEGER, Version INTEGER, VersionTimeStamp DATETIME, IsShared INTEGER, SharedBy TEXT, ShareWrite INTEGER, IsFolder INTEGER, Modified DATETIME,Hashes TEXT null COLLATE NOCASE, primary key (Id),unique (FilePath))";\r
             const string upgradeText = "PRAGMA writable_schema = 1;\n" +\r
-                                   "UPDATE SQLITE_MASTER SET SQL = 'CREATE TABLE FileState (Id UNIQUEIDENTIFIER not null, ObjectID TEXT COLLATE NOCASE, FilePath TEXT unique COLLATE NOCASE, OverlayStatus INTEGER, FileStatus INTEGER, ConflictReason TEXT, Checksum TEXT COLLATE NOCASE, ETag TEXT not null COLLATE NOCASE, LastMD5 TEXT not null COLLATE NOCASE, LastWriteDate DATETIME, LastLength INTEGER, Version INTEGER, VersionTimeStamp DATETIME, IsShared INTEGER, SharedBy TEXT, ShareWrite INTEGER, IsFolder INTEGER, Modified DATETIME, primary key (Id),unique (FilePath))' WHERE NAME = 'FileState';\n" +\r
+                                   "UPDATE SQLITE_MASTER SET SQL = 'CREATE TABLE FileState (Id UNIQUEIDENTIFIER not null, ObjectID TEXT COLLATE NOCASE, FilePath TEXT unique COLLATE NOCASE, OverlayStatus INTEGER, FileStatus INTEGER, ConflictReason TEXT, Checksum TEXT COLLATE NOCASE, ETag TEXT not null COLLATE NOCASE, LastMD5 TEXT not null COLLATE NOCASE,LastWriteDate DATETIME, LastLength INTEGER, Version INTEGER, VersionTimeStamp DATETIME, IsShared INTEGER, SharedBy TEXT, ShareWrite INTEGER, IsFolder INTEGER, Modified DATETIME, Hashes TEXT null COLLATE NOCASE, primary key (Id),unique (FilePath))' WHERE NAME = 'FileState';\n" +\r
                                    "PRAGMA writable_schema = 0;\n" +\r
                                    "VACUUM;";\r
 \r
@@ -947,6 +947,21 @@ namespace Pithos.Core.Agents
             }\r
         }\r
 \r
+\r
+        \r
+        public void UpdateFileTreeHash(string path, TreeHash treeHash)\r
+        {\r
+            if (String.IsNullOrWhiteSpace(path))\r
+                throw new ArgumentNullException("path");\r
+            if (!Path.IsPathRooted(path))\r
+                throw new ArgumentException("The path must be rooted", "path");            \r
+            if (treeHash==null)\r
+                throw new ArgumentNullException("treeHash");\r
+            Contract.EndContractBlock();\r
+\r
+            _persistenceAgent.Post(() => FileState.UpdateFileTreeHash(path, treeHash));\r
+        }\r
+\r
         public void UpdateFileChecksum(string path, string etag, string checksum)\r
         {\r
             if (String.IsNullOrWhiteSpace(path))\r
index 9cbfe2e..b62ffb1 100644 (file)
@@ -56,7 +56,7 @@ namespace Pithos.Core.Agents
                     TreeHash localTreeHash;\r
                     using (StatusNotification.GetNotifier("Merkle Hashing for Upload {0}", "Merkle Hashed for Upload {0}", fileInfo.Name))\r
                     {\r
-                        localTreeHash = Signature.CalculateTreeHashAsync(fileInfo.FullName,\r
+                        localTreeHash = Signature.CalculateTreeHashAsync(fileInfo,\r
                                                                          action.AccountInfo.BlockSize,\r
                                                                          action.AccountInfo.BlockHash, Settings.HashingParallelism,cancellationToken,progress);\r
                     }\r
index 780a537..edfa1ff 100644 (file)
-#region
-/* -----------------------------------------------------------------------
- * <copyright file="FileState.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.Diagnostics.Contracts;
-using System.IO;
-using System.Reflection;
-using System.Threading.Tasks;
-using Castle.ActiveRecord;
-using Castle.ActiveRecord.Framework;
-using Castle.ActiveRecord.Queries;
-using NHibernate.Criterion;
-using Pithos.Core.Agents;
-using Pithos.Interfaces;
-using Pithos.Network;
-using log4net;
-
-namespace Pithos.Core
-{
-    using System;
-    using System.Collections.Generic;    
-
-    /// <summary>
-    /// TODO: Update summary.
-    /// </summary>
-    [ActiveRecord]
-    public class FileState : ActiveRecordLinqBase<FileState>
-    {
-        private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
-
-
-        private IList<FileTag> _tags = new List<FileTag>();
-
-        [PrimaryKey(PrimaryKeyType.Guid)]
-        public Guid Id { get; set; }
-
-        
-        //[Property(Unique = true, UniqueKey = "IX_FileState_ObjectID")]
-        [Property]
-        public string ObjectID { get; set; }
-
-        [Property(Unique = true, UniqueKey = "IX_FileState_FilePath")]
-        public string FilePath { get; set; }
-
-        [Property]
-        public FileOverlayStatus OverlayStatus { get; set; }
-
-        [Property]
-        public FileStatus FileStatus { get; set; }
-
-        [Property]
-        public string ConflictReason { get; set; }
-
-        private string _checksum;
-
-        /// <summary>
-        /// The tophash value of the file, calculated by using a Merkle hash with the SHA256 algorithm
-        /// </summary>
-        /// <remarks>
-        /// The SHA256 algorithm is substantially more expenive than other algorithms.
-        /// Recalculating the Checksum should be avoided whenever possible.
-        /// </remarks>
-        [Property]
-        public string Checksum
-        {
-            get
-            {
-                return _checksum;
-            }
-            set
-            {
-                _checksum = value;
-            }
-        }
-        
-        /// <summary>
-        /// An easy to calcualte hash over the entire file, used to detect file changes
-        /// </summary>
-        /// <remarks>The algorithm used to calculate this hash should be cheap</remarks>
-        [Property(NotNull = true, Default = "")]
-        public string ETag { get; set; }
-
-        [Property(NotNull = true, Default = "")]
-        public string LastMD5 { get; set; }
-
-        [Property]
-        public DateTime? LastWriteDate { get; set; }
-
-        [Property]
-        public long? LastLength { get; set; }
-        
-        [Property]
-        public long? Version { get; set; }
-
-        [Property]
-        public DateTime? VersionTimeStamp { get; set; }
-
-
-        [Property]
-        public bool IsShared { get; set; }
-
-        [Property]
-        public string SharedBy { get; set; }
-
-        [Property]
-        public bool ShareWrite { get; set; }
-
-        [Property]
-        public bool IsFolder{ get; set; }
-
-        [HasMany(Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Lazy = true, Inverse = true)]
-        public IList<FileTag> Tags
-        {
-            get { return _tags; }
-            set { _tags = value; }
-        }
-
-        [Property]
-        public DateTime Modified { get; set; }
-
-
-        public FileSystemInfo GetFileSystemInfo()
-        {
-            if (String.IsNullOrWhiteSpace(FilePath))
-                throw new InvalidOperationException();
-            Contract.EndContractBlock();
-
-            return Directory.Exists(FilePath) ?
-                (FileSystemInfo)new DirectoryInfo(FilePath)
-                : new FileInfo(FilePath);
-        }
-
-        public string GetRelativeUrl(AccountInfo accountInfo)
-        {
-            if (accountInfo==null)
-                throw new ArgumentNullException("accountInfo");
-            Contract.EndContractBlock();
-
-            var fsi=GetFileSystemInfo();
-            return fsi.AsRelativeUrlTo(accountInfo.AccountPath);
-        }
-        /*public static FileState FindByFilePath(string absolutePath)
-        {
-            if (string.IsNullOrWhiteSpace(absolutePath))
-                throw new ArgumentNullException("absolutePath");
-            Contract.EndContractBlock();
-            try
-            {
-
-                
-
-                return Queryable.FirstOrDefault(s => s.FilePath == absolutePath);
-            }
-            catch (Exception ex)
-            {
-                Log.Error(ex.ToString());
-                throw;
-            }
-
-
-        }*/
-
-       /* public static void DeleteByFilePath(string absolutePath)
-        {
-            if (string.IsNullOrWhiteSpace(absolutePath))
-                throw new ArgumentNullException("absolutePath");
-            Contract.EndContractBlock();
-
-            ExecuteWithRetry((session, instance) =>
-                        {
-                            const string hqlDelete = "delete FileState where FilePath = :path";
-                            var deletedEntities = session.CreateQuery(hqlDelete)
-                                .SetString("path", absolutePath)
-                                .ExecuteUpdate();
-                            return deletedEntities;
-                        }, null);
-
-        }*/
-
-/*
-        public static void StoreFileStatus(string absolutePath, FileStatus newStatus)
-        {
-            if (string.IsNullOrWhiteSpace(absolutePath))
-                throw new ArgumentNullException("absolutePath");
-            Contract.EndContractBlock();
-
-            ExecuteWithRetry((session, instance) =>
-                                 {
-                                     const string hqlUpdate =
-                                         "update FileState set FileStatus= :status where FilePath = :path ";
-                                     using (session.BeginTransaction())
-                                     {
-                                         var updatedEntities = session.CreateQuery(hqlUpdate)
-                                             .SetString("path", absolutePath)
-                                             .SetEnum("status", newStatus)
-                                             .ExecuteUpdate();
-                                         if (updatedEntities == 0)
-                                         {
-                                             var newState = new FileState
-                                                                {
-                                                                    FilePath = absolutePath,
-                                                                    Id = Guid.NewGuid(),
-                                                                    FileStatus = newStatus,
-                                                                    IsFolder = Directory.Exists(absolutePath)
-                                                                };
-                                             newState.CreateAndFlush();
-                                         }
-                                         return null;
-                                     }
-                                 }, null);
-
-        }
-*/
-
-        public static void StoreOverlayStatus(string absolutePath, FileOverlayStatus newStatus,string etag)
-        {
-            if (string.IsNullOrWhiteSpace(absolutePath))
-                throw new ArgumentNullException("absolutePath");
-            Contract.EndContractBlock();
-
-            ExecuteWithRetry((session, instance) =>
-                        {
-                            const string hqlUpdate =
-                                "update FileState set OverlayStatus= :status where FilePath = :path ";
-                            using (var tx=session.BeginTransaction())
-                            {
-                                var updatedEntities = session.CreateQuery(hqlUpdate)
-                                    .SetString("path", absolutePath)
-                                    .SetEnum("status", newStatus)
-                                    .ExecuteUpdate();
-                                if (updatedEntities == 0)
-                                {
-                                    var newState = new FileState
-                                                       {
-                                                           FilePath = absolutePath,
-                                                           Id = Guid.NewGuid(),
-                                                           OverlayStatus = newStatus,
-                                                           ETag = etag ?? String.Empty,
-                                                           LastMD5=String.Empty,
-                                                           IsFolder = Directory.Exists(absolutePath)
-                                                       };
-                                    newState.CreateAndFlush();
-                                }
-                                tx.Commit();
-                                return null;
-                            }
-                        }, null);
-
-        }
-
-/*
-        public static void UpdateStatus(string absolutePath, FileStatus fileStatus, FileOverlayStatus overlayStatus)
-        {
-            if (string.IsNullOrWhiteSpace(absolutePath))
-                throw new ArgumentNullException("absolutePath");
-            Contract.EndContractBlock();
-
-            ExecuteWithRetry((session, instance) =>
-                        {
-                            const string hqlUpdate =
-                                "update FileState set OverlayStatus= :overlayStatus, FileStatus= :fileStatus where FilePath = :path  ";
-                            var updatedEntities = session.CreateQuery(hqlUpdate)
-                                .SetString("path", absolutePath)
-                                .SetEnum("fileStatus", fileStatus)
-                                .SetEnum("overlayStatus", overlayStatus)
-                                .ExecuteUpdate();
-                            return updatedEntities;
-                        }, null);
-
-        }
-*/
-
-/*
-        public static void UpdateStatus(string absolutePath, FileStatus fileStatus)
-        {
-            if (string.IsNullOrWhiteSpace(absolutePath))
-                throw new ArgumentNullException("absolutePath");
-            Contract.EndContractBlock();
-
-            ExecuteWithRetry((session, instance) =>
-                        {
-                            const string hqlUpdate =
-                                "update FileState set FileStatus= :fileStatus where FilePath = :path  ";
-                            var updatedEntities = session.CreateQuery(hqlUpdate)
-                                .SetString("path", absolutePath)
-                                .SetEnum("fileStatus", fileStatus)
-                                .ExecuteUpdate();
-                            return updatedEntities;
-                        }, null);
-
-        }
-
-*/
-        public static void RenameState(string oldPath, string newPath)
-        {
-            if (string.IsNullOrWhiteSpace(oldPath))
-                throw new ArgumentNullException("oldPath");
-            Contract.EndContractBlock();
-
-            ExecuteWithRetry((session, instance) =>
-                        {
-                            const string hqlUpdate =
-                                "update FileState set FilePath= :newPath where FilePath = :oldPath ";
-                            var updatedEntities = session.CreateQuery(hqlUpdate)
-                                .SetString("oldPath", oldPath)
-                                .SetString("newPath", newPath)
-                                .ExecuteUpdate();
-                            return updatedEntities;
-                        }, null);
-
-        }
-
-     /*   public static void UpdateStatus(Guid id, FileStatus fileStatus)
-        {
-
-            ExecuteWithRetry((session, instance) =>
-            {
-                const string hqlUpdate =
-                    "update FileState set FileStatus= :fileStatus where Id = :id  ";
-                var updatedEntities = session.CreateQuery(hqlUpdate)
-                    .SetGuid("id", id)
-                    .SetEnum("fileStatus", fileStatus)
-                    .ExecuteUpdate();
-                return updatedEntities;
-            }, null);
-        }*/
-
-        public static void UpdateChecksum(string absolutePath, string etag, string checksum)
-        {
-            if (string.IsNullOrWhiteSpace(absolutePath))
-                throw new ArgumentNullException("absolutePath");
-            Contract.EndContractBlock();
-
-            ExecuteWithRetry((session, instance) =>
-                        {
-                            const string hqlUpdate = "update FileState set Checksum= :checksum,ETag=:etag where FilePath = :path ";
-                            var updatedEntities = session.CreateQuery(hqlUpdate)
-                                .SetString("path", absolutePath)
-                                .SetString("checksum", checksum)
-                                .SetString("etag", etag)
-                                .ExecuteUpdate();
-                            return updatedEntities;
-                        }, null);
-
-        }
-
-
-        public static void UpdateLastMD5(FileInfo file, string md5)
-        {
-            if (file==null)
-                throw new ArgumentNullException("file");
-            Contract.EndContractBlock();
-
-            ExecuteWithRetry((session, instance) =>
-                        {
-                            const string hqlUpdate = "update FileState set LastMD5=:md5, LastWriteDate=:date,LastLength=:length where FilePath = :path ";
-                            
-                            file.Refresh();
-                            if (!file.Exists)
-                                return 0;
-                            var fullName = file.WithProperCapitalization().FullName;
-
-                            using (var tx=session.BeginTransaction())
-                            {
-                                var updatedEntities = session.CreateQuery(hqlUpdate)
-                                    .SetDateTime("date", file.LastWriteTime)
-                                    .SetInt64("length", file.Length)
-                                    .SetString("md5", md5)
-                                    .SetString("path", fullName)
-                                    .ExecuteUpdate();
-                                if (updatedEntities == 0)
-                                {
-                                    var newState = new FileState
-                                                       {
-                                                           FilePath = fullName,
-                                                           Id = Guid.NewGuid(),
-                                                           OverlayStatus = FileOverlayStatus.Normal,
-                                                           FileStatus = FileStatus.Unchanged,
-                                                           IsFolder = false,
-                                                           LastLength = file.Length,
-                                                           LastWriteDate = file.LastWriteTime,
-                                                           LastMD5 = md5 ?? String.Empty,
-                                                           ETag = String.Empty
-                                                       };
-                                    newState.CreateAndFlush();
-                                }
-                                tx.Commit();
-                                return updatedEntities;
-                            }
-                        }, null);
-
-        }
-
-        public static void ChangeRootPath(string oldPath, string newPath)
-        {
-            if (String.IsNullOrWhiteSpace(oldPath))
-                throw new ArgumentNullException("oldPath");
-            if (!Path.IsPathRooted(oldPath))
-                throw new ArgumentException("oldPath must be an absolute path", "oldPath");
-            if (string.IsNullOrWhiteSpace(newPath))
-                throw new ArgumentNullException("newPath");
-            if (!Path.IsPathRooted(newPath))
-                throw new ArgumentException("newPath must be an absolute path", "newPath");
-            Contract.EndContractBlock();
-
-            //Ensure the paths end with the same character
-            if (!oldPath.EndsWith("\\"))
-                oldPath = oldPath + "\\";
-            if (!newPath.EndsWith("\\"))
-                newPath = newPath + "\\";
-
-                ExecuteWithRetry((session, instance) =>
-                            {
-                                const string hqlUpdate =
-                                    "update FileState set FilePath = replace(FilePath,:oldPath,:newPath) where FilePath like :oldPath || '%' ";
-                                var renames = session.CreateQuery(hqlUpdate)
-                                    .SetString("oldPath", oldPath)
-                                    .SetString("newPath", newPath)
-                                    .ExecuteUpdate();
-                                return renames;
-                            }, null);
-        }
-
-        public static FileState CreateFor(FileSystemInfo info,IStatusNotification notification)
-        {
-            if(info==null)
-                throw new ArgumentNullException("info");
-            Contract.EndContractBlock();
-            
-            if (info is DirectoryInfo)
-                return new FileState
-                {
-                    FilePath = info.FullName,
-                    OverlayStatus = FileOverlayStatus.Unversioned,
-                    FileStatus = FileStatus.Created,
-                    ETag=String.Empty,
-                    LastMD5=String.Empty,
-                    Id = Guid.NewGuid()
-                };
-
-            
-            var etag = ((FileInfo)info).ComputeShortHash(notification);
-            var fileState = new FileState
-                                {
-                                    FilePath = info.FullName,
-                                    OverlayStatus = FileOverlayStatus.Unversioned,
-                                    FileStatus = FileStatus.Created,               
-                                    ETag=etag,
-                                    LastMD5=String.Empty,
-                                    Id = Guid.NewGuid()
-                                };
-            return fileState;
-        }
-
-
-        private static void ExecuteWithRetry(NHibernateDelegate call, object state)
-        {
-            int retries = 3;
-            while (retries > 0)
-                try
-                {
-                    using (new SessionScope())
-                    {
-                        Execute(call, state);
-                        return;
-                    }
-                }
-                catch (ActiveRecordException )
-                {
-                    retries--;
-                    if (retries <= 0)
-                        throw;
-                }
-        }
-
-        /// <summary>
-        /// Mark Unversioned all FileState rows from the database whose path
-        /// starts with one of the removed paths
-        /// </summary>
-        /// <param name="removed"></param>
-        public static void UnversionPaths(List<string> removed)
-        {
-            if (removed == null)
-                return;
-            if (removed.Count == 0)
-                return;
-
-            //Create a disjunction (list of OR statements
-            var disjunction = new Disjunction();            
-            foreach (var path in removed)
-            {
-                //with the restriction FileState.FilePath like '@path%'
-                disjunction.Add(Restrictions.On<FileState>(s => s.FilePath)
-                    .IsLike(path, MatchMode.Start));
-            }
-
-            //Generate a query from the disjunction
-            var query=QueryOver.Of<FileState>().Where(disjunction);
-                        
-            ExecuteWithRetry((session,instance)=>
-                                 {
-                                     using (var tx=session.BeginTransaction())
-                                     {
-                                         var states = query.GetExecutableQueryOver(session).List();
-                                         foreach (var state in states)
-                                         {
-                                             state.FileStatus = FileStatus.Unversioned;
-                                             state.OverlayStatus = FileOverlayStatus.Unversioned;
-                                             state.Update();
-                                         }
-                                         tx.Commit();
-                                     }
-                                     return null;
-                                 },null);
-        }
-
-        public string ToDebugString()
-        {
-            return String.Format("[STATE] FilePath:[{0}] ObjectID:[{1}], ETAG: [{2}], LastMD5:[{3}]", FilePath, ObjectID,
-                                 ETag, LastMD5);
-        }
-    }
-
-    [ActiveRecord("Tags")]
-    public class FileTag : ActiveRecordLinqBase<FileTag>
-    {
-        [PrimaryKey]
-        public int Id { get; set; }
-
-        [Property]
-        public string Name { get; set; }
-
-        [Property]
-        public string Value { get; set; }
-
-        [BelongsTo("FileStateId")]
-        public FileState FileState { get; set; }
-
-    }
-   
-}
+#region\r
+/* -----------------------------------------------------------------------\r
+ * <copyright file="FileState.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.Diagnostics.Contracts;\r
+using System.IO;\r
+using System.Reflection;\r
+using System.Threading.Tasks;\r
+using Castle.ActiveRecord;\r
+using Castle.ActiveRecord.Framework;\r
+using Castle.ActiveRecord.Queries;\r
+using NHibernate.Criterion;\r
+using Pithos.Core.Agents;\r
+using Pithos.Interfaces;\r
+using Pithos.Network;\r
+using log4net;\r
+\r
+namespace Pithos.Core\r
+{\r
+    using System;\r
+    using System.Collections.Generic;    \r
+\r
+    /// <summary>\r
+    /// TODO: Update summary.\r
+    /// </summary>\r
+    [ActiveRecord]\r
+    public class FileState : ActiveRecordLinqBase<FileState>\r
+    {\r
+        private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);\r
+\r
+\r
+        private IList<FileTag> _tags = new List<FileTag>();\r
+\r
+        [PrimaryKey(PrimaryKeyType.Guid)]\r
+        public Guid Id { get; set; }\r
+\r
+        \r
+        //[Property(Unique = true, UniqueKey = "IX_FileState_ObjectID")]\r
+        [Property]\r
+        public string ObjectID { get; set; }\r
+\r
+        [Property(Unique = true, UniqueKey = "IX_FileState_FilePath")]\r
+        public string FilePath { get; set; }\r
+\r
+        [Property]\r
+        public FileOverlayStatus OverlayStatus { get; set; }\r
+\r
+        [Property]\r
+        public FileStatus FileStatus { get; set; }\r
+\r
+        [Property]\r
+        public string ConflictReason { get; set; }\r
+\r
+        private string _checksum;\r
+\r
+        /// <summary>\r
+        /// The tophash value of the file, calculated by using a Merkle hash with the SHA256 algorithm\r
+        /// </summary>\r
+        /// <remarks>\r
+        /// The SHA256 algorithm is substantially more expenive than other algorithms.\r
+        /// Recalculating the Checksum should be avoided whenever possible.\r
+        /// </remarks>\r
+        [Property]\r
+        public string Checksum\r
+        {\r
+            get\r
+            {\r
+                return _checksum;\r
+            }\r
+            set\r
+            {\r
+                _checksum = value;\r
+            }\r
+        }\r
+        \r
+        /// <summary>\r
+        /// An easy to calcualte hash over the entire file, used to detect file changes\r
+        /// </summary>\r
+        /// <remarks>The algorithm used to calculate this hash should be cheap</remarks>\r
+        [Property(NotNull = true, Default = "")]\r
+        public string ETag { get; set; }\r
+\r
+        [Property(NotNull = true, Default = "")]\r
+        public string LastMD5 { get; set; }\r
+\r
+        [Property]\r
+        public string Hashes { get; set; }\r
+\r
+        [Property]\r
+        public DateTime? LastWriteDate { get; set; }\r
+\r
+        [Property]\r
+        public long? LastLength { get; set; }\r
+        \r
+        [Property]\r
+        public long? Version { get; set; }\r
+\r
+        [Property]\r
+        public DateTime? VersionTimeStamp { get; set; }\r
+\r
+\r
+        [Property]\r
+        public bool IsShared { get; set; }\r
+\r
+        [Property]\r
+        public string SharedBy { get; set; }\r
+\r
+        [Property]\r
+        public bool ShareWrite { get; set; }\r
+\r
+        [Property]\r
+        public bool IsFolder{ get; set; }\r
+\r
+        [HasMany(Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Lazy = true, Inverse = true)]\r
+        public IList<FileTag> Tags\r
+        {\r
+            get { return _tags; }\r
+            set { _tags = value; }\r
+        }\r
+\r
+        [Property]\r
+        public DateTime Modified { get; set; }\r
+\r
+\r
+        public FileSystemInfo GetFileSystemInfo()\r
+        {\r
+            if (String.IsNullOrWhiteSpace(FilePath))\r
+                throw new InvalidOperationException();\r
+            Contract.EndContractBlock();\r
+\r
+            return Directory.Exists(FilePath) ?\r
+                (FileSystemInfo)new DirectoryInfo(FilePath)\r
+                : new FileInfo(FilePath);\r
+        }\r
+\r
+        public string GetRelativeUrl(AccountInfo accountInfo)\r
+        {\r
+            if (accountInfo==null)\r
+                throw new ArgumentNullException("accountInfo");\r
+            Contract.EndContractBlock();\r
+\r
+            var fsi=GetFileSystemInfo();\r
+            return fsi.AsRelativeUrlTo(accountInfo.AccountPath);\r
+        }\r
+        /*public static FileState FindByFilePath(string absolutePath)\r
+        {\r
+            if (string.IsNullOrWhiteSpace(absolutePath))\r
+                throw new ArgumentNullException("absolutePath");\r
+            Contract.EndContractBlock();\r
+            try\r
+            {\r
+\r
+                \r
+\r
+                return Queryable.FirstOrDefault(s => s.FilePath == absolutePath);\r
+            }\r
+            catch (Exception ex)\r
+            {\r
+                Log.Error(ex.ToString());\r
+                throw;\r
+            }\r
+\r
+\r
+        }*/\r
+\r
+       /* public static void DeleteByFilePath(string absolutePath)\r
+        {\r
+            if (string.IsNullOrWhiteSpace(absolutePath))\r
+                throw new ArgumentNullException("absolutePath");\r
+            Contract.EndContractBlock();\r
+\r
+            ExecuteWithRetry((session, instance) =>\r
+                        {\r
+                            const string hqlDelete = "delete FileState where FilePath = :path";\r
+                            var deletedEntities = session.CreateQuery(hqlDelete)\r
+                                .SetString("path", absolutePath)\r
+                                .ExecuteUpdate();\r
+                            return deletedEntities;\r
+                        }, null);\r
+\r
+        }*/\r
+\r
+/*\r
+        public static void StoreFileStatus(string absolutePath, FileStatus newStatus)\r
+        {\r
+            if (string.IsNullOrWhiteSpace(absolutePath))\r
+                throw new ArgumentNullException("absolutePath");\r
+            Contract.EndContractBlock();\r
+\r
+            ExecuteWithRetry((session, instance) =>\r
+                                 {\r
+                                     const string hqlUpdate =\r
+                                         "update FileState set FileStatus= :status where FilePath = :path ";\r
+                                     using (session.BeginTransaction())\r
+                                     {\r
+                                         var updatedEntities = session.CreateQuery(hqlUpdate)\r
+                                             .SetString("path", absolutePath)\r
+                                             .SetEnum("status", newStatus)\r
+                                             .ExecuteUpdate();\r
+                                         if (updatedEntities == 0)\r
+                                         {\r
+                                             var newState = new FileState\r
+                                                                {\r
+                                                                    FilePath = absolutePath,\r
+                                                                    Id = Guid.NewGuid(),\r
+                                                                    FileStatus = newStatus,\r
+                                                                    IsFolder = Directory.Exists(absolutePath)\r
+                                                                };\r
+                                             newState.CreateAndFlush();\r
+                                         }\r
+                                         return null;\r
+                                     }\r
+                                 }, null);\r
+\r
+        }\r
+*/\r
+\r
+        public static void StoreOverlayStatus(string absolutePath, FileOverlayStatus newStatus,string etag)\r
+        {\r
+            if (string.IsNullOrWhiteSpace(absolutePath))\r
+                throw new ArgumentNullException("absolutePath");\r
+            Contract.EndContractBlock();\r
+\r
+            ExecuteWithRetry((session, instance) =>\r
+                        {\r
+                            const string hqlUpdate =\r
+                                "update FileState set OverlayStatus= :status where FilePath = :path ";\r
+                            using (var tx=session.BeginTransaction())\r
+                            {\r
+                                var updatedEntities = session.CreateQuery(hqlUpdate)\r
+                                    .SetString("path", absolutePath)\r
+                                    .SetEnum("status", newStatus)\r
+                                    .ExecuteUpdate();\r
+                                if (updatedEntities == 0)\r
+                                {\r
+                                    var newState = new FileState\r
+                                                       {\r
+                                                           FilePath = absolutePath,\r
+                                                           Id = Guid.NewGuid(),\r
+                                                           OverlayStatus = newStatus,\r
+                                                           ETag = etag ?? String.Empty,\r
+                                                           LastMD5=String.Empty,\r
+                                                           IsFolder = Directory.Exists(absolutePath)\r
+                                                       };\r
+                                    newState.CreateAndFlush();\r
+                                }\r
+                                tx.Commit();\r
+                                return null;\r
+                            }\r
+                        }, null);\r
+\r
+        }\r
+\r
+/*\r
+        public static void UpdateStatus(string absolutePath, FileStatus fileStatus, FileOverlayStatus overlayStatus)\r
+        {\r
+            if (string.IsNullOrWhiteSpace(absolutePath))\r
+                throw new ArgumentNullException("absolutePath");\r
+            Contract.EndContractBlock();\r
+\r
+            ExecuteWithRetry((session, instance) =>\r
+                        {\r
+                            const string hqlUpdate =\r
+                                "update FileState set OverlayStatus= :overlayStatus, FileStatus= :fileStatus where FilePath = :path  ";\r
+                            var updatedEntities = session.CreateQuery(hqlUpdate)\r
+                                .SetString("path", absolutePath)\r
+                                .SetEnum("fileStatus", fileStatus)\r
+                                .SetEnum("overlayStatus", overlayStatus)\r
+                                .ExecuteUpdate();\r
+                            return updatedEntities;\r
+                        }, null);\r
+\r
+        }\r
+*/\r
+\r
+/*\r
+        public static void UpdateStatus(string absolutePath, FileStatus fileStatus)\r
+        {\r
+            if (string.IsNullOrWhiteSpace(absolutePath))\r
+                throw new ArgumentNullException("absolutePath");\r
+            Contract.EndContractBlock();\r
+\r
+            ExecuteWithRetry((session, instance) =>\r
+                        {\r
+                            const string hqlUpdate =\r
+                                "update FileState set FileStatus= :fileStatus where FilePath = :path  ";\r
+                            var updatedEntities = session.CreateQuery(hqlUpdate)\r
+                                .SetString("path", absolutePath)\r
+                                .SetEnum("fileStatus", fileStatus)\r
+                                .ExecuteUpdate();\r
+                            return updatedEntities;\r
+                        }, null);\r
+\r
+        }\r
+\r
+*/\r
+        public static void RenameState(string oldPath, string newPath)\r
+        {\r
+            if (string.IsNullOrWhiteSpace(oldPath))\r
+                throw new ArgumentNullException("oldPath");\r
+            Contract.EndContractBlock();\r
+\r
+            ExecuteWithRetry((session, instance) =>\r
+                        {\r
+                            const string hqlUpdate =\r
+                                "update FileState set FilePath= :newPath where FilePath = :oldPath ";\r
+                            var updatedEntities = session.CreateQuery(hqlUpdate)\r
+                                .SetString("oldPath", oldPath)\r
+                                .SetString("newPath", newPath)\r
+                                .ExecuteUpdate();\r
+                            return updatedEntities;\r
+                        }, null);\r
+\r
+        }\r
+\r
+     /*   public static void UpdateStatus(Guid id, FileStatus fileStatus)\r
+        {\r
+\r
+            ExecuteWithRetry((session, instance) =>\r
+            {\r
+                const string hqlUpdate =\r
+                    "update FileState set FileStatus= :fileStatus where Id = :id  ";\r
+                var updatedEntities = session.CreateQuery(hqlUpdate)\r
+                    .SetGuid("id", id)\r
+                    .SetEnum("fileStatus", fileStatus)\r
+                    .ExecuteUpdate();\r
+                return updatedEntities;\r
+            }, null);\r
+        }*/\r
+\r
+        public static void UpdateFileTreeHash(string absolutePath, TreeHash treeHash)\r
+        {\r
+            if (string.IsNullOrWhiteSpace(absolutePath))\r
+                throw new ArgumentNullException("absolutePath");\r
+            Contract.EndContractBlock();\r
+\r
+            ExecuteWithRetry((session, instance) =>\r
+            {\r
+                \r
+                var hashes=treeHash.ToJson();\r
+                const string hqlUpdate = "update FileState set Checksum= :checksum,ETag=:etag, Hashes=:hashes where FilePath = :path ";\r
+                var updatedEntities = session.CreateQuery(hqlUpdate)\r
+                    .SetString("path", absolutePath)\r
+                    .SetString("checksum", treeHash.TopHash.ToHashString())\r
+                    .SetString("etag", treeHash.MD5)\r
+                    .SetString("hashes",hashes)\r
+                    .ExecuteUpdate();\r
+                return updatedEntities;\r
+            }, null);\r
+        }\r
+\r
+        public static void UpdateChecksum(string absolutePath, string etag, string checksum)\r
+        {\r
+            if (string.IsNullOrWhiteSpace(absolutePath))\r
+                throw new ArgumentNullException("absolutePath");\r
+            Contract.EndContractBlock();\r
+\r
+            ExecuteWithRetry((session, instance) =>\r
+                        {\r
+                            const string hqlUpdate = "update FileState set Checksum= :checksum,ETag=:etag where FilePath = :path ";\r
+                            var updatedEntities = session.CreateQuery(hqlUpdate)\r
+                                .SetString("path", absolutePath)\r
+                                .SetString("checksum", checksum)\r
+                                .SetString("etag", etag)\r
+                                .ExecuteUpdate();\r
+                            return updatedEntities;\r
+                        }, null);\r
+\r
+        }\r
+\r
+\r
+        public static void UpdateLastMD5(FileInfo file, string md5)\r
+        {\r
+            if (file==null)\r
+                throw new ArgumentNullException("file");\r
+            Contract.EndContractBlock();\r
+\r
+            ExecuteWithRetry((session, instance) =>\r
+                        {\r
+                            const string hqlUpdate = "update FileState set LastMD5=:md5, LastWriteDate=:date,LastLength=:length where FilePath = :path ";\r
+                            \r
+                            file.Refresh();\r
+                            if (!file.Exists)\r
+                                return 0;\r
+                            var fullName = file.WithProperCapitalization().FullName;\r
+\r
+                            using (var tx=session.BeginTransaction())\r
+                            {\r
+                                var updatedEntities = session.CreateQuery(hqlUpdate)\r
+                                    .SetDateTime("date", file.LastWriteTime)\r
+                                    .SetInt64("length", file.Length)\r
+                                    .SetString("md5", md5)\r
+                                    .SetString("path", fullName)\r
+                                    .ExecuteUpdate();\r
+                                if (updatedEntities == 0)\r
+                                {\r
+                                    var newState = new FileState\r
+                                                       {\r
+                                                           FilePath = fullName,\r
+                                                           Id = Guid.NewGuid(),\r
+                                                           OverlayStatus = FileOverlayStatus.Normal,\r
+                                                           FileStatus = FileStatus.Unchanged,\r
+                                                           IsFolder = false,\r
+                                                           LastLength = file.Length,\r
+                                                           LastWriteDate = file.LastWriteTime,\r
+                                                           LastMD5 = md5 ?? String.Empty,\r
+                                                           ETag = String.Empty\r
+                                                       };\r
+                                    newState.CreateAndFlush();\r
+                                }\r
+                                tx.Commit();\r
+                                return updatedEntities;\r
+                            }\r
+                        }, null);\r
+\r
+        }\r
+\r
+        public static void ChangeRootPath(string oldPath, string newPath)\r
+        {\r
+            if (String.IsNullOrWhiteSpace(oldPath))\r
+                throw new ArgumentNullException("oldPath");\r
+            if (!Path.IsPathRooted(oldPath))\r
+                throw new ArgumentException("oldPath must be an absolute path", "oldPath");\r
+            if (string.IsNullOrWhiteSpace(newPath))\r
+                throw new ArgumentNullException("newPath");\r
+            if (!Path.IsPathRooted(newPath))\r
+                throw new ArgumentException("newPath must be an absolute path", "newPath");\r
+            Contract.EndContractBlock();\r
+\r
+            //Ensure the paths end with the same character\r
+            if (!oldPath.EndsWith("\\"))\r
+                oldPath = oldPath + "\\";\r
+            if (!newPath.EndsWith("\\"))\r
+                newPath = newPath + "\\";\r
+\r
+                ExecuteWithRetry((session, instance) =>\r
+                            {\r
+                                const string hqlUpdate =\r
+                                    "update FileState set FilePath = replace(FilePath,:oldPath,:newPath) where FilePath like :oldPath || '%' ";\r
+                                var renames = session.CreateQuery(hqlUpdate)\r
+                                    .SetString("oldPath", oldPath)\r
+                                    .SetString("newPath", newPath)\r
+                                    .ExecuteUpdate();\r
+                                return renames;\r
+                            }, null);\r
+        }\r
+\r
+        public static FileState CreateFor(FileSystemInfo info,IStatusNotification notification)\r
+        {\r
+            if(info==null)\r
+                throw new ArgumentNullException("info");\r
+            Contract.EndContractBlock();\r
+            \r
+            if (info is DirectoryInfo)\r
+                return new FileState\r
+                {\r
+                    FilePath = info.FullName,\r
+                    OverlayStatus = FileOverlayStatus.Unversioned,\r
+                    FileStatus = FileStatus.Created,\r
+                    ETag=String.Empty,\r
+                    LastMD5=String.Empty,\r
+                    Id = Guid.NewGuid()\r
+                };\r
+\r
+            \r
+            var etag = ((FileInfo)info).ComputeShortHash(notification);\r
+            var fileState = new FileState\r
+                                {\r
+                                    FilePath = info.FullName,\r
+                                    OverlayStatus = FileOverlayStatus.Unversioned,\r
+                                    FileStatus = FileStatus.Created,               \r
+                                    ETag=etag,\r
+                                    LastMD5=String.Empty,\r
+                                    Id = Guid.NewGuid()\r
+                                };\r
+            return fileState;\r
+        }\r
+\r
+\r
+        private static void ExecuteWithRetry(NHibernateDelegate call, object state)\r
+        {\r
+            int retries = 3;\r
+            while (retries > 0)\r
+                try\r
+                {\r
+                    using (new SessionScope())\r
+                    {\r
+                        Execute(call, state);\r
+                        return;\r
+                    }\r
+                }\r
+                catch (ActiveRecordException )\r
+                {\r
+                    retries--;\r
+                    if (retries <= 0)\r
+                        throw;\r
+                }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Mark Unversioned all FileState rows from the database whose path\r
+        /// starts with one of the removed paths\r
+        /// </summary>\r
+        /// <param name="removed"></param>\r
+        public static void UnversionPaths(List<string> removed)\r
+        {\r
+            if (removed == null)\r
+                return;\r
+            if (removed.Count == 0)\r
+                return;\r
+\r
+            //Create a disjunction (list of OR statements\r
+            var disjunction = new Disjunction();            \r
+            foreach (var path in removed)\r
+            {\r
+                //with the restriction FileState.FilePath like '@path%'\r
+                disjunction.Add(Restrictions.On<FileState>(s => s.FilePath)\r
+                    .IsLike(path, MatchMode.Start));\r
+            }\r
+\r
+            //Generate a query from the disjunction\r
+            var query=QueryOver.Of<FileState>().Where(disjunction);\r
+                        \r
+            ExecuteWithRetry((session,instance)=>\r
+                                 {\r
+                                     using (var tx=session.BeginTransaction())\r
+                                     {\r
+                                         var states = query.GetExecutableQueryOver(session).List();\r
+                                         foreach (var state in states)\r
+                                         {\r
+                                             state.FileStatus = FileStatus.Unversioned;\r
+                                             state.OverlayStatus = FileOverlayStatus.Unversioned;\r
+                                             state.Update();\r
+                                         }\r
+                                         tx.Commit();\r
+                                     }\r
+                                     return null;\r
+                                 },null);\r
+        }\r
+\r
+        public string ToDebugString()\r
+        {\r
+            return String.Format("[STATE] FilePath:[{0}] ObjectID:[{1}], ETAG: [{2}], LastMD5:[{3}]", FilePath, ObjectID,\r
+                                 ETag, LastMD5);\r
+        }\r
+    }\r
+\r
+    [ActiveRecord("Tags")]\r
+    public class FileTag : ActiveRecordLinqBase<FileTag>\r
+    {\r
+        [PrimaryKey]\r
+        public int Id { get; set; }\r
+\r
+        [Property]\r
+        public string Name { get; set; }\r
+\r
+        [Property]\r
+        public string Value { get; set; }\r
+\r
+        [BelongsTo("FileStateId")]\r
+        public FileState FileState { get; set; }\r
+\r
+    }\r
+   \r
+}\r
index 6b8c6be..8c49f0c 100644 (file)
-#region
-/* -----------------------------------------------------------------------
- * <copyright file="IStatusKeeper.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.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using Pithos.Interfaces;
-
-namespace Pithos.Core
-{
-    [ContractClass(typeof(IStatusKeeperContract))]
-    public interface IStatusKeeper
-    {
-        Task SetFileOverlayStatus(string path, FileOverlayStatus status, string etag = null);
-        void UpdateFileChecksum(string path, string etag, string checksum);
-        void SetFileStatus(string path, FileStatus status);
-        FileStatus GetFileStatus(string path);
-        void ClearFileStatus(string path);
-        FileOverlayStatus GetFileOverlayStatus(string path);
-        void ProcessExistingFiles(IEnumerable<FileInfo> paths);
-        void Stop();
-        void SetFileState(string path, FileStatus fileStatus, FileOverlayStatus overlayStatus, string localFileMissingFromServer);
-        void StoreInfo(string path, ObjectInfo objectInfo);
-        //T GetStatus<T>(string path,Func<FileState,T> getter,T defaultValue );
-        //void SetStatus(string path, Action<FileState> setter);        
-
-        void StartProcessing(CancellationToken token);
-
-        string BlockHash { get; set; }
-        int BlockSize { get; set; }
-        IStatusNotification StatusNotification { get; set; }
-
-        void ChangeRoots(string oldPath, string newPath);
-        FileState GetStateByFilePath(string path);
-        void ClearFolderStatus(string path);
-        IEnumerable<FileState> GetChildren(FileState fileState);
-        void EnsureFileState(string path);
-
-        void CleanupStaleStates(Network.AccountInfo accountInfo, List<ObjectInfo> objectInfos);
-        void CleanupOrphanStates();
-        void UpdateLastMD5(FileInfo path, string etag);
-    }
-
-    [ContractClassFor(typeof(IStatusKeeper))]
-    public abstract class IStatusKeeperContract : IStatusKeeper
-    {
-        public Task SetFileOverlayStatus(string path, FileOverlayStatus status, string etag = null)
-        {
-            Contract.Requires(!String.IsNullOrWhiteSpace(path));
-            Contract.Requires(Path.IsPathRooted(path));
-            return default(Task);
-        }
-
-        public void UpdateFileChecksum(string path, string etag, string checksum)
-        {
-            Contract.Requires(!String.IsNullOrWhiteSpace(path));
-            Contract.Requires(checksum!=null);
-            Contract.Requires(Path.IsPathRooted(path));
-        }
-
-     /*   public void RemoveFileOverlayStatus(string path)
-        {
-            Contract.Requires(!String.IsNullOrWhiteSpace(path));
-            Contract.Requires(Path.IsPathRooted(path));
-        }*/
-
-        public void RenameFileOverlayStatus(string oldPath, string newPath)
-        {
-            Contract.Requires(!String.IsNullOrWhiteSpace(oldPath));
-            Contract.Requires(Path.IsPathRooted(oldPath));
-            Contract.Requires(!String.IsNullOrWhiteSpace(newPath));
-            Contract.Requires(Path.IsPathRooted(newPath));
-
-        }
-
-        public void SetFileStatus(string path, FileStatus status)
-        {
-            Contract.Requires(!String.IsNullOrWhiteSpace(path));
-            Contract.Requires(Path.IsPathRooted(path));
-        }
-
-        public FileStatus GetFileStatus(string path)
-        {
-            Contract.Requires(!String.IsNullOrWhiteSpace(path));
-            Contract.Requires(Path.IsPathRooted(path));
-
-            return default(FileStatus);
-        }
-
-        public FileOverlayStatus GetFileOverlayStatus(string path)
-        {
-            Contract.Requires(!String.IsNullOrWhiteSpace(path));
-            Contract.Requires(Path.IsPathRooted(path));
-
-            return default(FileOverlayStatus);
-        }
-
-        public void ProcessExistingFiles(IEnumerable<FileInfo> paths)
-        {
-            Contract.Requires(paths!=null);
-        }
-
-        public void Stop()
-        {
-            
-        }
-
-        public void SetFileState(string path, FileStatus fileStatus, FileOverlayStatus overlayStatus, string localFileMissingFromServer)
-        {
-            Contract.Requires(!String.IsNullOrWhiteSpace(path));
-            Contract.Requires(Path.IsPathRooted(path));
-        }
-
-        public void StoreInfo(string path, ObjectInfo objectInfo)
-        {
-            Contract.Requires(!String.IsNullOrWhiteSpace(path));
-            Contract.Requires(objectInfo!=null);
-            Contract.Requires(Path.IsPathRooted(path));
-        }
-
-        public T GetStatus<T>(string path, Func<FileState, T> getter, T defaultValue)
-        {
-            Contract.Requires(!String.IsNullOrWhiteSpace(path));
-            Contract.Requires(getter!=null);
-            Contract.Requires(Path.IsPathRooted(path));
-
-            return default(T);
-        }
-
-        public void SetStatus(string path, Action<FileState> setter)
-        {
-            Contract.Requires(!String.IsNullOrWhiteSpace(path));
-            Contract.Requires(setter != null);
-            Contract.Requires(Path.IsPathRooted(path));
-        }
-
-        public void SetNetworkState(string path, NetworkOperation operation)
-        {
-            Contract.Requires(!String.IsNullOrWhiteSpace(path));
-            Contract.Requires(Path.IsPathRooted(path));
-            Contract.Requires(Path.IsPathRooted(path));
-        }
-
-        public NetworkOperation GetNetworkState(string path)
-        {
-            Contract.Requires(!String.IsNullOrWhiteSpace(path));
-            Contract.Requires(Path.IsPathRooted(path));
-
-            return default(NetworkOperation);
-        }
-
-        public void ClearFileStatus(string path)
-        {
-            Contract.Requires(!String.IsNullOrWhiteSpace(path));
-            Contract.Requires(Path.IsPathRooted(path));
-        }
-
-        public void SetPithosStatus(PithosStatus status)
-        {
-        }
-
-        public void StartProcessing(CancellationToken token)
-        {
-            Contract.Requires(token != null, "token can't be empty");
-        }
-
-        public abstract string BlockHash { get; set; }
-        public abstract int BlockSize { get; set; }
-
-        public IStatusNotification StatusNotification { get; set; }
-
-        public void ChangeRoots(string oldPath, string newPath)
-        {
-            Contract.Requires(!String.IsNullOrWhiteSpace(oldPath));
-            Contract.Requires(Path.IsPathRooted(oldPath));
-            Contract.Requires(!string.IsNullOrWhiteSpace(newPath));
-            Contract.Requires(Path.IsPathRooted(newPath));            
-        }
-
-        public FileState GetStateByFilePath(string path)
-        {
-            Contract.Requires(!String.IsNullOrWhiteSpace(path));
-            Contract.Requires(Path.IsPathRooted(path));
-
-            return null;
-        }
-
-        public void ClearFolderStatus(string path)
-        {
-            Contract.Requires(!String.IsNullOrWhiteSpace(path));
-            Contract.Requires(Path.IsPathRooted(path));
-        }
-
-        public IEnumerable<FileState> GetChildren(FileState fileState)
-        {
-            Contract.Requires(fileState!=null);
-            Contract.Ensures(Contract.Result<IEnumerable<FileState>>()!=null);
-            return default(IEnumerable<FileState>);
-        }
-
-        public void EnsureFileState(string path)
-        {
-            
-        }
-
-
-        public void CleanupStaleStates(Network.AccountInfo accountInfo, List<ObjectInfo> objectInfos)
-        {
-            Contract.Requires(accountInfo != null);
-            Contract.Requires(objectInfos != null);
-        }
-
-
-        public void CleanupOrphanStates()
-        {            
-        }
-
-        public void UpdateLastMD5(FileInfo path, string etag)
-        {
-            
-        }
-    }
-}
+#region\r
+/* -----------------------------------------------------------------------\r
+ * <copyright file="IStatusKeeper.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.Contracts;\r
+using System.IO;\r
+using System.Linq;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+using Pithos.Interfaces;\r
+using Pithos.Network;\r
+\r
+namespace Pithos.Core\r
+{\r
+    [ContractClass(typeof(IStatusKeeperContract))]\r
+    public interface IStatusKeeper\r
+    {\r
+        Task SetFileOverlayStatus(string path, FileOverlayStatus status, string etag = null);\r
+        void UpdateFileChecksum(string path, string etag, string checksum);\r
+        void UpdateFileTreeHash(string path, TreeHash treeHash);\r
+        void SetFileStatus(string path, FileStatus status);\r
+        FileStatus GetFileStatus(string path);\r
+        void ClearFileStatus(string path);\r
+        FileOverlayStatus GetFileOverlayStatus(string path);\r
+        void ProcessExistingFiles(IEnumerable<FileInfo> paths);\r
+        void Stop();\r
+        void SetFileState(string path, FileStatus fileStatus, FileOverlayStatus overlayStatus, string localFileMissingFromServer);\r
+        void StoreInfo(string path, ObjectInfo objectInfo);\r
+        //T GetStatus<T>(string path,Func<FileState,T> getter,T defaultValue );\r
+        //void SetStatus(string path, Action<FileState> setter);        \r
+\r
+        void StartProcessing(CancellationToken token);\r
+\r
+        string BlockHash { get; set; }\r
+        int BlockSize { get; set; }\r
+        IStatusNotification StatusNotification { get; set; }\r
+\r
+        void ChangeRoots(string oldPath, string newPath);\r
+        FileState GetStateByFilePath(string path);\r
+        void ClearFolderStatus(string path);\r
+        IEnumerable<FileState> GetChildren(FileState fileState);\r
+        void EnsureFileState(string path);\r
+\r
+        void CleanupStaleStates(Network.AccountInfo accountInfo, List<ObjectInfo> objectInfos);\r
+        void CleanupOrphanStates();\r
+        void UpdateLastMD5(FileInfo path, string etag);\r
+    }\r
+\r
+    [ContractClassFor(typeof(IStatusKeeper))]\r
+    public abstract class IStatusKeeperContract : IStatusKeeper\r
+    {\r
+        public Task SetFileOverlayStatus(string path, FileOverlayStatus status, string etag = null)\r
+        {\r
+            Contract.Requires(!String.IsNullOrWhiteSpace(path));\r
+            Contract.Requires(Path.IsPathRooted(path));\r
+            return default(Task);\r
+        }\r
+\r
+        public void UpdateFileChecksum(string path, string etag, string checksum)\r
+        {\r
+            Contract.Requires(!String.IsNullOrWhiteSpace(path));\r
+            Contract.Requires(checksum!=null);\r
+            Contract.Requires(Path.IsPathRooted(path));\r
+        }\r
+\r
+        public void UpdateFileTreeHash(string path, TreeHash treeHash)\r
+        {\r
+            Contract.Requires(!String.IsNullOrWhiteSpace(path));\r
+            Contract.Requires(treeHash!=null);\r
+            Contract.Requires(Path.IsPathRooted(path));\r
+        }\r
+\r
+     /*   public void RemoveFileOverlayStatus(string path)\r
+        {\r
+            Contract.Requires(!String.IsNullOrWhiteSpace(path));\r
+            Contract.Requires(Path.IsPathRooted(path));\r
+        }*/\r
+\r
+        public void RenameFileOverlayStatus(string oldPath, string newPath)\r
+        {\r
+            Contract.Requires(!String.IsNullOrWhiteSpace(oldPath));\r
+            Contract.Requires(Path.IsPathRooted(oldPath));\r
+            Contract.Requires(!String.IsNullOrWhiteSpace(newPath));\r
+            Contract.Requires(Path.IsPathRooted(newPath));\r
+\r
+        }\r
+\r
+        public void SetFileStatus(string path, FileStatus status)\r
+        {\r
+            Contract.Requires(!String.IsNullOrWhiteSpace(path));\r
+            Contract.Requires(Path.IsPathRooted(path));\r
+        }\r
+\r
+        public FileStatus GetFileStatus(string path)\r
+        {\r
+            Contract.Requires(!String.IsNullOrWhiteSpace(path));\r
+            Contract.Requires(Path.IsPathRooted(path));\r
+\r
+            return default(FileStatus);\r
+        }\r
+\r
+        public FileOverlayStatus GetFileOverlayStatus(string path)\r
+        {\r
+            Contract.Requires(!String.IsNullOrWhiteSpace(path));\r
+            Contract.Requires(Path.IsPathRooted(path));\r
+\r
+            return default(FileOverlayStatus);\r
+        }\r
+\r
+        public void ProcessExistingFiles(IEnumerable<FileInfo> paths)\r
+        {\r
+            Contract.Requires(paths!=null);\r
+        }\r
+\r
+        public void Stop()\r
+        {\r
+            \r
+        }\r
+\r
+        public void SetFileState(string path, FileStatus fileStatus, FileOverlayStatus overlayStatus, string localFileMissingFromServer)\r
+        {\r
+            Contract.Requires(!String.IsNullOrWhiteSpace(path));\r
+            Contract.Requires(Path.IsPathRooted(path));\r
+        }\r
+\r
+        public void StoreInfo(string path, ObjectInfo objectInfo)\r
+        {\r
+            Contract.Requires(!String.IsNullOrWhiteSpace(path));\r
+            Contract.Requires(objectInfo!=null);\r
+            Contract.Requires(Path.IsPathRooted(path));\r
+        }\r
+\r
+        public T GetStatus<T>(string path, Func<FileState, T> getter, T defaultValue)\r
+        {\r
+            Contract.Requires(!String.IsNullOrWhiteSpace(path));\r
+            Contract.Requires(getter!=null);\r
+            Contract.Requires(Path.IsPathRooted(path));\r
+\r
+            return default(T);\r
+        }\r
+\r
+        public void SetStatus(string path, Action<FileState> setter)\r
+        {\r
+            Contract.Requires(!String.IsNullOrWhiteSpace(path));\r
+            Contract.Requires(setter != null);\r
+            Contract.Requires(Path.IsPathRooted(path));\r
+        }\r
+\r
+        public void SetNetworkState(string path, NetworkOperation operation)\r
+        {\r
+            Contract.Requires(!String.IsNullOrWhiteSpace(path));\r
+            Contract.Requires(Path.IsPathRooted(path));\r
+            Contract.Requires(Path.IsPathRooted(path));\r
+        }\r
+\r
+        public NetworkOperation GetNetworkState(string path)\r
+        {\r
+            Contract.Requires(!String.IsNullOrWhiteSpace(path));\r
+            Contract.Requires(Path.IsPathRooted(path));\r
+\r
+            return default(NetworkOperation);\r
+        }\r
+\r
+        public void ClearFileStatus(string path)\r
+        {\r
+            Contract.Requires(!String.IsNullOrWhiteSpace(path));\r
+            Contract.Requires(Path.IsPathRooted(path));\r
+        }\r
+\r
+        public void SetPithosStatus(PithosStatus status)\r
+        {\r
+        }\r
+\r
+        public void StartProcessing(CancellationToken token)\r
+        {\r
+            Contract.Requires(token != null, "token can't be empty");\r
+        }\r
+\r
+        public abstract string BlockHash { get; set; }\r
+        public abstract int BlockSize { get; set; }\r
+\r
+        public IStatusNotification StatusNotification { get; set; }\r
+\r
+        public void ChangeRoots(string oldPath, string newPath)\r
+        {\r
+            Contract.Requires(!String.IsNullOrWhiteSpace(oldPath));\r
+            Contract.Requires(Path.IsPathRooted(oldPath));\r
+            Contract.Requires(!string.IsNullOrWhiteSpace(newPath));\r
+            Contract.Requires(Path.IsPathRooted(newPath));            \r
+        }\r
+\r
+        public FileState GetStateByFilePath(string path)\r
+        {\r
+            Contract.Requires(!String.IsNullOrWhiteSpace(path));\r
+            Contract.Requires(Path.IsPathRooted(path));\r
+\r
+            return null;\r
+        }\r
+\r
+        public void ClearFolderStatus(string path)\r
+        {\r
+            Contract.Requires(!String.IsNullOrWhiteSpace(path));\r
+            Contract.Requires(Path.IsPathRooted(path));\r
+        }\r
+\r
+        public IEnumerable<FileState> GetChildren(FileState fileState)\r
+        {\r
+            Contract.Requires(fileState!=null);\r
+            Contract.Ensures(Contract.Result<IEnumerable<FileState>>()!=null);\r
+            return default(IEnumerable<FileState>);\r
+        }\r
+\r
+        public void EnsureFileState(string path)\r
+        {\r
+            \r
+        }\r
+\r
+\r
+        public void CleanupStaleStates(Network.AccountInfo accountInfo, List<ObjectInfo> objectInfos)\r
+        {\r
+            Contract.Requires(accountInfo != null);\r
+            Contract.Requires(objectInfos != null);\r
+        }\r
+\r
+\r
+        public void CleanupOrphanStates()\r
+        {            \r
+        }\r
+\r
+        public void UpdateLastMD5(FileInfo path, string etag)\r
+        {\r
+            \r
+        }\r
+    }\r
+}\r
index 3b4de87..ead6f53 100644 (file)
-#region
-/* -----------------------------------------------------------------------
- * <copyright file="FileInfoExtensions.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;
-
-
-namespace Pithos.Interfaces
-{
-    public static class FileInfoExtensions
-    {
-        public static  string AsRelativeTo(this FileSystemInfo fileInfo,string path )
-        {
-            if (String.IsNullOrWhiteSpace(path))
-                throw new ArgumentNullException("path");            
-            Contract.EndContractBlock();
-            Contract.Assume(Enum.IsDefined(typeof(StringComparison),StringComparison.InvariantCultureIgnoreCase));
-
-            var filePath = fileInfo.GetProperCapitalization();
-
-            return AsRelativeTo(filePath,path);
-        }
-
-        public static  string AsRelativeTo(this string filePath,string path )
-        {
-            if (String.IsNullOrWhiteSpace(filePath))
-                throw new ArgumentNullException("filePath");            
-            if (String.IsNullOrWhiteSpace(path))
-                throw new ArgumentNullException("path");            
-            Contract.EndContractBlock();
-            Contract.Assume(Enum.IsDefined(typeof(StringComparison),StringComparison.InvariantCultureIgnoreCase));
-
-            if (filePath.Equals(path,StringComparison.InvariantCultureIgnoreCase))
-                return String.Empty;
-
-            if (!path.EndsWith("\\"))
-                path=path.ToLower() + "\\";
-            int pathLength = path.Length;            
-                        
-            if (!filePath.StartsWith(path,StringComparison.InvariantCultureIgnoreCase))
-                throw new ArgumentException(String.Format("The path {0} doesn't contain the file {1}",path,filePath));
-            
-            var relativePath = filePath.Substring(pathLength, filePath.Length - pathLength);
-
-            return relativePath;
-        }
-
-        public static string AsRelativeUrlTo(this FileSystemInfo fileInfo,string path )
-        {
-            if (String.IsNullOrWhiteSpace(path))
-                throw new ArgumentNullException("path");
-            Contract.EndContractBlock();
-
-            var relativePath = fileInfo.AsRelativeTo(path);
-            var replacedSlashes = relativePath.Replace("\\","/");
-            var escaped = Uri.EscapeUriString(replacedSlashes);
-            return escaped;
-        }
-
-        public static string RelativeUriToFilePath(this Uri uri)
-        {
-            var unescaped = Uri.UnescapeDataString(uri.ToString());
-            var path = unescaped.Replace("/", "\\");
-            return path;
-        }
-
-
-        public static string GetProperDirectoryCapitalization(string fileName)
-        {
-            Contract.Ensures(!String.IsNullOrWhiteSpace(Contract.Result<string>()));
-            Contract.EndContractBlock();
-            
-            if (String.IsNullOrWhiteSpace(fileName))
-                return String.Empty;
-
-            var dirInfo = new DirectoryInfo(fileName);
-            return dirInfo.GetProperCapitalization();
-        }
-
-
-        public static string GetProperCapitalization(this DirectoryInfo dirInfo)
-        {
-            if (dirInfo == null)
-                throw new ArgumentNullException("dirInfo");
-            Contract.EndContractBlock();
-            Contract.Assume(!String.IsNullOrWhiteSpace(dirInfo.FullName));
-
-            var parentDirInfo = dirInfo.Parent;
-            if (null == parentDirInfo)
-                return dirInfo.Name;
-
-            try
-            {
-
-                dirInfo.Refresh();
-
-                if (dirInfo.Exists)
-                    return Path.Combine(GetProperDirectoryCapitalization(parentDirInfo.FullName),
-                                        parentDirInfo.GetDirectories(dirInfo.Name)[0].Name);
-                else
-                {
-                    return dirInfo.FullName;
-                }
-            }
-            catch (DirectoryNotFoundException)
-            {
-                //An exception can occur if a directory is deleted right after the Exists call
-                return dirInfo.FullName;
-            }
-        }
-
-
-        public static string GetProperFilePathCapitalization(string fileName)
-        {
-            Contract.Ensures(!String.IsNullOrWhiteSpace(Contract.Result<string>()));
-            Contract.EndContractBlock();
-            if (String.IsNullOrWhiteSpace(fileName))
-                return String.Empty;
-
-
-            var fileInfo = new FileInfo(fileName);
-            return fileInfo.GetProperCapitalization();
-        }
-
-        public static string GetProperCapitalization(this FileInfo fileInfo)
-        {
-            if (fileInfo == null)
-                throw new ArgumentNullException("fileInfo");
-            Contract.EndContractBlock();
-
-
-            var dirInfo = fileInfo.Directory;
-
-            //Directory will not be null for an absolute path
-            Contract.Assume(dirInfo != null);
-
-            try
-            {
-                //Exists returns a cached value that can be true even if a file was deleted since the
-                //FileInfo object was created.
-                fileInfo.Refresh();
-                if (fileInfo.Exists)
-                    return Path.Combine(GetProperDirectoryCapitalization(dirInfo.FullName),
-                                        dirInfo.GetFiles(fileInfo.Name)[0].Name);
-                else
-                {
-                    return fileInfo.FullName;
-                }
-            }
-            catch (FileNotFoundException)
-            {
-                //An exception can occur if a file is deleted right after the Exists call
-                return fileInfo.FullName;
-
-            }
-        }
-
-        public static string GetProperCapitalization(this FileSystemInfo info)
-        {
-            if (info is FileInfo)
-                return (info as FileInfo).GetProperCapitalization();
-            if (info is DirectoryInfo)
-                return (info as DirectoryInfo).GetProperCapitalization();
-            throw new NotSupportedException("Unexpected parameter type");
-        }
-
-        public static DirectoryInfo WithProperCapitalization(this DirectoryInfo dirInfo)
-        {
-            if (dirInfo==null)
-                throw new ArgumentNullException("dirInfo");
-            Contract.EndContractBlock();
-
-            var path = dirInfo.GetProperCapitalization();
-            return new DirectoryInfo(path);
-        }
-
-        public static FileInfo WithProperCapitalization(this FileInfo fileInfo)
-        {
-            if (fileInfo==null)
-                throw new ArgumentNullException("fileInfo");
-            Contract.EndContractBlock();
-
-            var path = fileInfo.GetProperCapitalization();
-            return new FileInfo(path);
-        }
-
-        public static FileSystemInfo WithProperCapitalization(this FileSystemInfo info)
-        {
-            if (info==null)
-                throw new ArgumentNullException("info");
-            Contract.EndContractBlock();
-
-            if (info is FileInfo)
-                return (info as FileInfo).WithProperCapitalization();
-            if (info is DirectoryInfo)
-                return (info as DirectoryInfo).WithProperCapitalization();
-
-            throw new NotSupportedException("Unexpected parameter type");
-        }
-
-        public static FileSystemInfo FromPath(string filePath)
-        {
-            if (String.IsNullOrWhiteSpace(filePath))
-                throw new ArgumentNullException("filePath");
-            Contract.EndContractBlock();
-
-            return Directory.Exists(filePath) ? 
-                (FileSystemInfo) new DirectoryInfo(filePath) 
-                : new FileInfo(filePath);
-        }
-    }
-}
+#region\r
+/* -----------------------------------------------------------------------\r
+ * <copyright file="FileInfoExtensions.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.Contracts;\r
+using System.Linq;\r
+using System.Text;\r
+using System.IO;\r
+using System.Text.RegularExpressions;\r
+using System.Threading.Tasks;\r
+\r
+\r
+namespace Pithos.Interfaces\r
+{\r
+    public static class FileInfoExtensions\r
+    {\r
+        public static  string AsRelativeTo(this FileSystemInfo fileInfo,string path )\r
+        {\r
+            if (String.IsNullOrWhiteSpace(path))\r
+                throw new ArgumentNullException("path");            \r
+            Contract.EndContractBlock();\r
+            Contract.Assume(Enum.IsDefined(typeof(StringComparison),StringComparison.InvariantCultureIgnoreCase));\r
+\r
+            var filePath = fileInfo.GetProperCapitalization();\r
+\r
+            return AsRelativeTo(filePath,path);\r
+        }\r
+\r
+        public static  string AsRelativeTo(this string filePath,string path )\r
+        {\r
+            if (String.IsNullOrWhiteSpace(filePath))\r
+                throw new ArgumentNullException("filePath");            \r
+            if (String.IsNullOrWhiteSpace(path))\r
+                throw new ArgumentNullException("path");            \r
+            Contract.EndContractBlock();\r
+            Contract.Assume(Enum.IsDefined(typeof(StringComparison),StringComparison.InvariantCultureIgnoreCase));\r
+\r
+            if (filePath.Equals(path,StringComparison.InvariantCultureIgnoreCase))\r
+                return String.Empty;\r
+\r
+            if (!path.EndsWith("\\"))\r
+                path=path.ToLower() + "\\";\r
+            int pathLength = path.Length;            \r
+                        \r
+            if (!filePath.StartsWith(path,StringComparison.InvariantCultureIgnoreCase))\r
+                throw new ArgumentException(String.Format("The path {0} doesn't contain the file {1}",path,filePath));\r
+            \r
+            var relativePath = filePath.Substring(pathLength, filePath.Length - pathLength);\r
+\r
+            return relativePath;\r
+        }\r
+\r
+        public static string AsRelativeUrlTo(this FileSystemInfo fileInfo,string path )\r
+        {\r
+            if (String.IsNullOrWhiteSpace(path))\r
+                throw new ArgumentNullException("path");\r
+            Contract.EndContractBlock();\r
+\r
+            var relativePath = fileInfo.AsRelativeTo(path);\r
+            var replacedSlashes = relativePath.Replace("\\","/");\r
+            var escaped = Uri.EscapeUriString(replacedSlashes);\r
+            return escaped;\r
+        }\r
+\r
+        public static string RelativeUriToFilePath(this Uri uri)\r
+        {\r
+            var unescaped = Uri.UnescapeDataString(uri.ToString());\r
+            var path = unescaped.Replace("/", "\\");\r
+            return path;\r
+        }\r
+\r
+\r
+        public static string GetProperDirectoryCapitalization(string fileName)\r
+        {\r
+            Contract.Ensures(!String.IsNullOrWhiteSpace(Contract.Result<string>()));\r
+            Contract.EndContractBlock();\r
+            \r
+            if (String.IsNullOrWhiteSpace(fileName))\r
+                return String.Empty;\r
+\r
+            var dirInfo = new DirectoryInfo(fileName);\r
+            return dirInfo.GetProperCapitalization();\r
+        }\r
+\r
+\r
+        public static string GetProperCapitalization(this DirectoryInfo dirInfo)\r
+        {\r
+            if (dirInfo == null)\r
+                throw new ArgumentNullException("dirInfo");\r
+            Contract.EndContractBlock();\r
+            Contract.Assume(!String.IsNullOrWhiteSpace(dirInfo.FullName));\r
+\r
+            var parentDirInfo = dirInfo.Parent;\r
+            if (null == parentDirInfo)\r
+                return dirInfo.Name;\r
+\r
+            try\r
+            {\r
+\r
+                dirInfo.Refresh();\r
+\r
+                if (dirInfo.Exists)\r
+                    return Path.Combine(GetProperDirectoryCapitalization(parentDirInfo.FullName),\r
+                                        parentDirInfo.GetDirectories(dirInfo.Name)[0].Name);\r
+                else\r
+                {\r
+                    return dirInfo.FullName;\r
+                }\r
+            }\r
+            catch (DirectoryNotFoundException)\r
+            {\r
+                //An exception can occur if a directory is deleted right after the Exists call\r
+                return dirInfo.FullName;\r
+            }\r
+        }\r
+\r
+\r
+        public static string GetProperFilePathCapitalization(string fileName)\r
+        {\r
+            Contract.Ensures(!String.IsNullOrWhiteSpace(Contract.Result<string>()));\r
+            Contract.EndContractBlock();\r
+            if (String.IsNullOrWhiteSpace(fileName))\r
+                return String.Empty;\r
+\r
+\r
+            var fileInfo = new FileInfo(fileName);\r
+            return fileInfo.GetProperCapitalization();\r
+        }\r
+\r
+        public static string GetProperCapitalization(this FileInfo fileInfo)\r
+        {\r
+            if (fileInfo == null)\r
+                throw new ArgumentNullException("fileInfo");\r
+            Contract.EndContractBlock();\r
+\r
+\r
+            var dirInfo = fileInfo.Directory;\r
+\r
+            //Directory will not be null for an absolute path\r
+            Contract.Assume(dirInfo != null);\r
+\r
+            try\r
+            {\r
+                //Exists returns a cached value that can be true even if a file was deleted since the\r
+                //FileInfo object was created.\r
+                fileInfo.Refresh();\r
+                if (fileInfo.Exists)\r
+                    return Path.Combine(GetProperDirectoryCapitalization(dirInfo.FullName),\r
+                                        dirInfo.GetFiles(fileInfo.Name)[0].Name);\r
+                else\r
+                {\r
+                    return fileInfo.FullName;\r
+                }\r
+            }\r
+            catch (FileNotFoundException)\r
+            {\r
+                //An exception can occur if a file is deleted right after the Exists call\r
+                return fileInfo.FullName;\r
+\r
+            }\r
+        }\r
+\r
+        public static string GetProperCapitalization(this FileSystemInfo info)\r
+        {\r
+            if (info is FileInfo)\r
+                return (info as FileInfo).GetProperCapitalization();\r
+            if (info is DirectoryInfo)\r
+                return (info as DirectoryInfo).GetProperCapitalization();\r
+            throw new NotSupportedException("Unexpected parameter type");\r
+        }\r
+\r
+        public static DirectoryInfo WithProperCapitalization(this DirectoryInfo dirInfo)\r
+        {\r
+            if (dirInfo==null)\r
+                throw new ArgumentNullException("dirInfo");\r
+            Contract.EndContractBlock();\r
+\r
+            var path = dirInfo.GetProperCapitalization();\r
+            return new DirectoryInfo(path);\r
+        }\r
+\r
+        public static FileInfo WithProperCapitalization(this FileInfo fileInfo)\r
+        {\r
+            if (fileInfo==null)\r
+                throw new ArgumentNullException("fileInfo");\r
+            Contract.EndContractBlock();\r
+\r
+            var path = fileInfo.GetProperCapitalization();\r
+            return new FileInfo(path);\r
+        }\r
+\r
+        public static FileSystemInfo WithProperCapitalization(this FileSystemInfo info)\r
+        {\r
+            if (info==null)\r
+                throw new ArgumentNullException("info");\r
+            Contract.EndContractBlock();\r
+\r
+            if (info is FileInfo)\r
+                return (info as FileInfo).WithProperCapitalization();\r
+            if (info is DirectoryInfo)\r
+                return (info as DirectoryInfo).WithProperCapitalization();\r
+\r
+            throw new NotSupportedException("Unexpected parameter type");\r
+        }\r
+\r
+        public static FileSystemInfo FromPath(string filePath)\r
+        {\r
+            if (String.IsNullOrWhiteSpace(filePath))\r
+                throw new ArgumentNullException("filePath");\r
+            Contract.EndContractBlock();\r
+\r
+            return Directory.Exists(filePath) ? \r
+                (FileSystemInfo) new DirectoryInfo(filePath).WithProperCapitalization() \r
+                : new FileInfo(filePath).WithProperCapitalization();\r
+        }\r
+    }\r
+}\r
index 64e8256..ae6425b 100644 (file)
-#region
-/* -----------------------------------------------------------------------
- * <copyright file="Signature.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.Concurrent;
-using System.Collections.Generic;
-using System.Diagnostics.Contracts;
-using System.IO;
-using System.Reflection;
-using System.Runtime.Remoting.Metadata.W3cXsd2001;
-using System.Security.Cryptography;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Linq;
-
-namespace Pithos.Network
-{
-    public static class Signature
-    {
-        private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
-        public const  int BufferSize = 16384;
-
-        public const string MD5_EMPTY = "d41d8cd98f00b204e9800998ecf8427e";
-        public const string MERKLE_EMPTY = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
-
-
-        public static string CalculateMD5(FileSystemInfo info)
-        {
-            if (info==null)
-                throw new ArgumentNullException("info");
-            if (String.IsNullOrWhiteSpace(info.FullName))
-                throw new ArgumentException("info.FullName is empty","info");
-            Contract.EndContractBlock();
-
-            if (info is DirectoryInfo)
-                return MD5_EMPTY;
-
-            return CalculateMD5(info.FullName);
-        }
-
-        public static string CalculateMD5(string path)
-        {
-            if (String.IsNullOrWhiteSpace(path))
-                throw new ArgumentNullException("path");
-            Contract.EndContractBlock();
-
-            //DON'T calculate hashes for folders
-            if (Directory.Exists(path))
-                return "";
-
-            string hash;
-            using (var hasher = MD5.Create())
-            using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, Signature.BufferSize, true))
-            {
-                var hashBytes = hasher.ComputeHash(stream);
-                hash = hashBytes.ToHashString();
-            }
-            return hash;
-        }
-
-/*
-        public static string BytesToString(byte[] hashBytes)
-        {
-            var shb=new SoapHexBinary(hashBytes);
-            return shb.ToString();
-            
-        }
-
-
-        public static byte[] StringToBytes(string hash)
-        {
-            var shb=SoapHexBinary.Parse(hash);
-            return shb.Value;
-        }
-*/
-
-        public static byte[] ToBytes(this string hash)
-        {
-            var shb = SoapHexBinary.Parse(hash);
-            return shb.Value;
-        }
-
-        public static string ToHashString(this byte[] hashBytes)
-        {
-            var shb = new SoapHexBinary(hashBytes);
-            return shb.ToString().ToLower();
-        }
-
-        public static TreeHash CalculateTreeHash(FileSystemInfo fileInfo, int blockSize, string algorithm,CancellationToken token,IProgress<double> progress )
-        {
-            if (fileInfo == null)
-                throw new ArgumentNullException("fileInfo");
-            if (String.IsNullOrWhiteSpace(fileInfo.FullName))
-                throw new ArgumentException("fileInfo.FullName is empty", "fileInfo");
-            if (blockSize <= 0)
-                throw new ArgumentOutOfRangeException("blockSize", "blockSize must be a value greater than zero ");
-            if (String.IsNullOrWhiteSpace(algorithm))
-                throw new ArgumentNullException("algorithm");
-            Contract.EndContractBlock();
-            fileInfo.Refresh();
-            if (fileInfo is DirectoryInfo || !fileInfo.Exists)
-                return TreeHash.Empty;
-
-            return CalculateTreeHash(fileInfo.FullName, blockSize, algorithm,token,progress);
-        }
-
-        /// <summary>
-        /// Calculates a file's tree hash synchronously, using the specified block size
-        /// </summary>
-        /// <param name="filePath">Path to an existing file</param>
-        /// <param name="blockSize">Block size used to calculate leaf hashes</param>
-        /// <param name="algorithm"></param>
-        /// <returns>A <see cref="TreeHash"/> with the block hashes and top hash</returns>
-        public static TreeHash CalculateTreeHash(string filePath, int blockSize, string algorithm,CancellationToken token,IProgress<double> progress )
-        {
-            if (String.IsNullOrWhiteSpace(filePath))
-                throw new ArgumentNullException("filePath");
-            if (blockSize<=0)
-                throw new ArgumentOutOfRangeException("blockSize","blockSize must be a value greater than zero ");
-            if (String.IsNullOrWhiteSpace(algorithm))
-                throw new ArgumentNullException("algorithm");
-            Contract.EndContractBlock();           
-            var hash=CalculateTreeHashAsync(filePath, blockSize, algorithm, 1,token,progress);
-            return hash;
-        }
-        
-        public static TreeHash CalculateTreeHashAsync(FileInfo fileInfo, int blockSize, string algorithm, byte parallelism,CancellationToken token,IProgress<double> progress )
-        {
-            if (fileInfo == null)
-                throw new ArgumentNullException("fileInfo");
-            if (String.IsNullOrWhiteSpace(fileInfo.FullName))
-                throw new ArgumentNullException("fileInfo.FullName is empty","fileInfo");
-            if (blockSize <= 0)
-                throw new ArgumentOutOfRangeException("blockSize", "blockSize must be a value greater than zero ");
-            if (String.IsNullOrWhiteSpace(algorithm))
-                throw new ArgumentNullException("algorithm");
-            Contract.EndContractBlock();
-            
-            return CalculateTreeHashAsync(fileInfo.FullName, blockSize, algorithm, parallelism,token,progress);
-        }
-
-
-        public static TreeHash CalculateTreeHashAsync(string filePath, int blockSize,string algorithm, int parallelism,CancellationToken token,IProgress<double> progress )
-        {
-            if (String.IsNullOrWhiteSpace(filePath))
-                throw new ArgumentNullException("filePath");
-            if (blockSize <= 0)
-                throw new ArgumentOutOfRangeException("blockSize", "blockSize must be a value greater than zero ");
-            if (String.IsNullOrWhiteSpace(algorithm))
-                throw new ArgumentNullException("algorithm");
-            Contract.EndContractBlock();
-
-            if (Log.IsDebugEnabled)
-                Log.DebugFormat("Calc Signature [{0}]",filePath);
-
-            if (filePath.Split('/').Contains(".pithos.cache"))
-                throw new ArgumentException(String.Format("Trying to hash file from the cache folder: [{0}]",filePath));
-
-            //DON'T calculate hashes for folders
-            if (Directory.Exists(filePath))
-                return new TreeHash(algorithm);
-            //The hash of a non-existent file is the empty hash
-            if (!File.Exists(filePath))
-                return new TreeHash(algorithm);
-
-            //Calculate the hash of all blocks using a blockhash iterator
-            using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, BufferSize, true))
-            {
-                var md5 = new MD5BlockCalculator();
-                Action<long, byte[], int> postAction = md5.PostBlock;
-                //Calculate the blocks asyncrhonously
-                var hashes = BlockHashAlgorithms.CalculateBlockHashesInPlacePFor(stream, blockSize, algorithm, parallelism,postAction,token, progress).Result;                
-
-                //And then proceed with creating and returning a TreeHash
-                var length = stream.Length;
-                var list = hashes.OrderBy(pair => pair.Key).Select(pair => pair.Value).ToList();
-
-                var treeHash = new TreeHash(algorithm)
-                {
-                    Bytes = length,
-                    BlockSize = blockSize,
-                    Hashes = list,
-                };
-
-                string fileHash;
-
-                var md5Hash=md5.GetHash().Result;
-/*
-                var hasher = HashAlgorithm.Create("MD5");
-                stream.Position = 0;
-*/
-                treeHash.MD5= md5Hash;
-
-                return treeHash;
-            }
-        }
-
-        
-        public static byte[] CalculateTopHash(IList<byte[]> hashMap, string algorithm)
-        {
-            if (hashMap == null)
-                throw new ArgumentNullException("hashMap");
-            if (String.IsNullOrWhiteSpace(algorithm))
-                throw new ArgumentNullException("algorithm");
-            Contract.EndContractBlock();            
-
-            var hashCount = hashMap.Count;
-            //The tophash of an empty hashmap is an empty array
-            if (hashCount == 0)
-                return new byte[0];
-            //The tophash of a one-item hashmap is the hash itself
-            if (hashCount == 1)
-                return hashMap[0];
-
-            //Calculate the required number of leaf nodes
-            var leafs =(int)Math.Pow(2, Math.Ceiling(Math.Log(hashCount,2)));
-            //The size of all nodes is the same and equal to the size of the input hashes
-            var hashSize = hashMap[0].Length;
-
-            //If the hashmap containes fewer nodes than the required leaf count, we need to fill
-            //the rest with empty blocks
-            byte[] empty=null;            
-            if (hashCount < leafs)
-                empty = new byte[hashSize];
-
-            //New hashes will be stored in a dictionary keyed by their step to preserve order
-            var newHashes=new ConcurrentDictionary<int, byte[]>();            
-            
-            Parallel.For(0, leafs/2,
-                (step, state) =>
-                {
-                    using (var hasher = HashAlgorithm.Create(algorithm))
-                    {
-                        var i = step*2;
-                        var block1 = i <= hashCount - 1 ? hashMap[i] : empty;
-                        var block2 = i <= hashCount - 2 ? hashMap[i + 1] : empty;
-
-                        hasher.TransformBlock(block1, 0, block1.Length, null, 0);
-                        hasher.TransformFinalBlock(block2, 0, block2.Length);
-
-                        var finalHash = hasher.Hash;
-                        //Store the final value in its proper place
-                        newHashes[step] = finalHash;
-                    }
-                });
-
-            //Extract the hashes to a list ordered by their step 
-            var hashes = newHashes.OrderBy(pair => pair.Key).Select(pair => pair.Value).ToList();
-            return CalculateTopHash(hashes, algorithm);                   
-        }        
-    
-
-        public static byte[] CalculateHash(byte[] buffer,string algorithm)
-        {
-            if (buffer == null)
-                throw new ArgumentNullException("buffer");
-            if (String.IsNullOrWhiteSpace(algorithm))
-                throw new ArgumentNullException("algorithm");
-            Contract.EndContractBlock();
-
-            using (var hasher = HashAlgorithm.Create(algorithm))
-            {
-                var hash = hasher.ComputeHash(buffer, 0, buffer.Length);
-                return hash;
-            }        
-        }
-    }
-}
-
-
+#region\r
+/* -----------------------------------------------------------------------\r
+ * <copyright file="Signature.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.Concurrent;\r
+using System.Collections.Generic;\r
+using System.Diagnostics.Contracts;\r
+using System.IO;\r
+using System.Reflection;\r
+using System.Runtime.Remoting.Metadata.W3cXsd2001;\r
+using System.Security.Cryptography;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+using System.Linq;\r
+using Pithos.Interfaces;\r
+\r
+namespace Pithos.Network\r
+{\r
+    public static class Signature\r
+    {\r
+        private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);\r
+        public const  int BufferSize = 16384;\r
+\r
+        public const string MD5_EMPTY = "d41d8cd98f00b204e9800998ecf8427e";\r
+        public const string MERKLE_EMPTY = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";\r
+\r
+\r
+        public static string CalculateMD5(FileSystemInfo info)\r
+        {\r
+            if (info==null)\r
+                throw new ArgumentNullException("info");\r
+            if (String.IsNullOrWhiteSpace(info.FullName))\r
+                throw new ArgumentException("info.FullName is empty","info");\r
+            Contract.EndContractBlock();\r
+\r
+            if (info is DirectoryInfo)\r
+                return MD5_EMPTY;\r
+\r
+            return CalculateMD5(info.FullName);\r
+        }\r
+\r
+        public static string CalculateMD5(string path)\r
+        {\r
+            if (String.IsNullOrWhiteSpace(path))\r
+                throw new ArgumentNullException("path");\r
+            Contract.EndContractBlock();\r
+\r
+            //DON'T calculate hashes for folders\r
+            if (Directory.Exists(path))\r
+                return "";\r
+\r
+            string hash;\r
+            using (var hasher = MD5.Create())\r
+            using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, Signature.BufferSize, true))\r
+            {\r
+                var hashBytes = hasher.ComputeHash(stream);\r
+                hash = hashBytes.ToHashString();\r
+            }\r
+            return hash;\r
+        }\r
+\r
+/*\r
+        public static string BytesToString(byte[] hashBytes)\r
+        {\r
+            var shb=new SoapHexBinary(hashBytes);\r
+            return shb.ToString();\r
+            \r
+        }\r
+\r
+\r
+        public static byte[] StringToBytes(string hash)\r
+        {\r
+            var shb=SoapHexBinary.Parse(hash);\r
+            return shb.Value;\r
+        }\r
+*/\r
+\r
+        public static byte[] ToBytes(this string hash)\r
+        {\r
+            var shb = SoapHexBinary.Parse(hash);\r
+            return shb.Value;\r
+        }\r
+\r
+        public static string ToHashString(this byte[] hashBytes)\r
+        {\r
+            var shb = new SoapHexBinary(hashBytes);\r
+            return shb.ToString().ToLower();\r
+        }\r
+\r
+        public static TreeHash CalculateTreeHash(FileSystemInfo fileInfo, int blockSize, string algorithm,CancellationToken token,IProgress<double> progress )\r
+        {\r
+            if (fileInfo == null)\r
+                throw new ArgumentNullException("fileInfo");\r
+            if (String.IsNullOrWhiteSpace(fileInfo.FullName))\r
+                throw new ArgumentException("fileInfo.FullName is empty", "fileInfo");\r
+            if (blockSize <= 0)\r
+                throw new ArgumentOutOfRangeException("blockSize", "blockSize must be a value greater than zero ");\r
+            if (String.IsNullOrWhiteSpace(algorithm))\r
+                throw new ArgumentNullException("algorithm");\r
+            Contract.EndContractBlock();\r
+            fileInfo.Refresh();\r
+            if (fileInfo is DirectoryInfo || !fileInfo.Exists)\r
+                return TreeHash.Empty;\r
+\r
+            return CalculateTreeHashAsync(fileInfo, blockSize, algorithm, 1, token, progress);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Calculates a file's tree hash synchronously, using the specified block size\r
+        /// </summary>\r
+        /// <param name="filePath">Path to an existing file</param>\r
+        /// <param name="blockSize">Block size used to calculate leaf hashes</param>\r
+        /// <param name="algorithm"></param>\r
+        /// <returns>A <see cref="TreeHash"/> with the block hashes and top hash</returns>\r
+        public static TreeHash CalculateTreeHash(string filePath, int blockSize, string algorithm,CancellationToken token,IProgress<double> progress )\r
+        {\r
+            if (String.IsNullOrWhiteSpace(filePath))\r
+                throw new ArgumentNullException("filePath");\r
+            if (blockSize<=0)\r
+                throw new ArgumentOutOfRangeException("blockSize","blockSize must be a value greater than zero ");\r
+            if (String.IsNullOrWhiteSpace(algorithm))\r
+                throw new ArgumentNullException("algorithm");\r
+            Contract.EndContractBlock();\r
+\r
+            var info = FileInfoExtensions.FromPath(filePath);\r
+            var hash=CalculateTreeHashAsync(info, blockSize, algorithm, 1,token,progress);\r
+            return hash;\r
+        }\r
+        \r
+\r
+        public static TreeHash CalculateTreeHashAsync(string filePath, int blockSize, string algorithm, byte parallelism,CancellationToken token,IProgress<double> progress )\r
+        {\r
+            if (filePath== null)\r
+                throw new ArgumentNullException("filePath");\r
+            if (blockSize <= 0)\r
+                throw new ArgumentOutOfRangeException("blockSize", "blockSize must be a value greater than zero ");\r
+            if (String.IsNullOrWhiteSpace(algorithm))\r
+                throw new ArgumentNullException("algorithm");\r
+            Contract.EndContractBlock();\r
+\r
+            var info = FileInfoExtensions.FromPath(filePath);\r
+            return CalculateTreeHashAsync(info, blockSize, algorithm, parallelism,token,progress);\r
+        }\r
+\r
+\r
+\r
+        public static TreeHash CalculateTreeHashAsync(FileSystemInfo info, int blockSize,string algorithm, int parallelism,CancellationToken token,IProgress<double> progress )\r
+        {\r
+            if (info==null)\r
+                throw new ArgumentNullException("info");\r
+            if (blockSize <= 0)\r
+                throw new ArgumentOutOfRangeException("blockSize", "blockSize must be a value greater than zero ");\r
+            if (String.IsNullOrWhiteSpace(algorithm))\r
+                throw new ArgumentNullException("algorithm");\r
+            Contract.EndContractBlock();\r
+\r
+            var filePath = info.FullName;\r
+\r
+            if (Log.IsDebugEnabled)\r
+                Log.DebugFormat("Calc Signature [{0}]",filePath);\r
+\r
+            if (filePath.Split('/').Contains(".pithos.cache"))\r
+                throw new ArgumentException(String.Format("Trying to hash file from the cache folder: [{0}]",filePath));\r
+\r
+            //DON'T calculate hashes for folders\r
+            if (Directory.Exists(filePath))\r
+                return new TreeHash(algorithm);\r
+            //The hash of a non-existent file is the empty hash\r
+            if (!File.Exists(filePath))\r
+                return new TreeHash(algorithm);            \r
+\r
+            if (info is FileInfo && (info as FileInfo).Length==0)\r
+                return new TreeHash(algorithm);\r
+\r
+            //Calculate the hash of all blocks using a blockhash iterator\r
+            using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, BufferSize, true))\r
+            {\r
+                var md5 = new MD5BlockCalculator();\r
+                Action<long, byte[], int> postAction = md5.PostBlock;\r
+                //Calculate the blocks asyncrhonously\r
+                var hashes = BlockHashAlgorithms.CalculateBlockHashesInPlacePFor(stream, blockSize, algorithm, parallelism,postAction,token, progress).Result;                \r
+\r
+                //And then proceed with creating and returning a TreeHash\r
+                var length = stream.Length;\r
+                var list = hashes.OrderBy(pair => pair.Key).Select(pair => pair.Value).ToList();\r
+\r
+                var treeHash = new TreeHash(algorithm)\r
+                {\r
+                    Bytes = length,\r
+                    BlockSize = blockSize,\r
+                    Hashes = list,\r
+                };\r
+\r
+                string fileHash;\r
+\r
+                var md5Hash=md5.GetHash().Result;\r
+/*\r
+                var hasher = HashAlgorithm.Create("MD5");\r
+                stream.Position = 0;\r
+*/\r
+                treeHash.MD5= md5Hash;\r
+\r
+                return treeHash;\r
+            }\r
+        }\r
+\r
+        \r
+        public static byte[] CalculateTopHash(IList<byte[]> hashMap, string algorithm)\r
+        {\r
+            if (hashMap == null)\r
+                throw new ArgumentNullException("hashMap");\r
+            if (String.IsNullOrWhiteSpace(algorithm))\r
+                throw new ArgumentNullException("algorithm");\r
+            Contract.EndContractBlock();            \r
+\r
+            var hashCount = hashMap.Count;\r
+            //The tophash of an empty hashmap is an empty array\r
+            if (hashCount == 0)\r
+            {\r
+                using (var hasher = HashAlgorithm.Create(algorithm))\r
+                {\r
+                    var emptyHash=hasher.ComputeHash(new byte[0]);\r
+                    return emptyHash;\r
+                }                \r
+            }\r
+            //The tophash of a one-item hashmap is the hash itself\r
+            if (hashCount == 1)\r
+                return hashMap[0];\r
+\r
+            //Calculate the required number of leaf nodes\r
+            var leafs =(int)Math.Pow(2, Math.Ceiling(Math.Log(hashCount,2)));\r
+            //The size of all nodes is the same and equal to the size of the input hashes\r
+            var hashSize = hashMap[0].Length;\r
+\r
+            //If the hashmap containes fewer nodes than the required leaf count, we need to fill\r
+            //the rest with empty blocks\r
+            byte[] empty=null;            \r
+            if (hashCount < leafs)\r
+                empty = new byte[hashSize];\r
+\r
+            //New hashes will be stored in a dictionary keyed by their step to preserve order\r
+            var newHashes=new ConcurrentDictionary<int, byte[]>();            \r
+            \r
+            Parallel.For(0, leafs/2,\r
+                (step, state) =>\r
+                {\r
+                    using (var hasher = HashAlgorithm.Create(algorithm))\r
+                    {\r
+                        var i = step*2;\r
+                        var block1 = i <= hashCount - 1 ? hashMap[i] : empty;\r
+                        var block2 = i <= hashCount - 2 ? hashMap[i + 1] : empty;\r
+\r
+                        hasher.TransformBlock(block1, 0, block1.Length, null, 0);\r
+                        hasher.TransformFinalBlock(block2, 0, block2.Length);\r
+\r
+                        var finalHash = hasher.Hash;\r
+                        //Store the final value in its proper place\r
+                        newHashes[step] = finalHash;\r
+                    }\r
+                });\r
+\r
+            //Extract the hashes to a list ordered by their step \r
+            var hashes = newHashes.OrderBy(pair => pair.Key).Select(pair => pair.Value).ToList();\r
+            return CalculateTopHash(hashes, algorithm);                   \r
+        }        \r
+    \r
+\r
+        public static byte[] CalculateHash(byte[] buffer,string algorithm)\r
+        {\r
+            if (buffer == null)\r
+                throw new ArgumentNullException("buffer");\r
+            if (String.IsNullOrWhiteSpace(algorithm))\r
+                throw new ArgumentNullException("algorithm");\r
+            Contract.EndContractBlock();\r
+\r
+            using (var hasher = HashAlgorithm.Create(algorithm))\r
+            {\r
+                var hash = hasher.ComputeHash(buffer, 0, buffer.Length);\r
+                return hash;\r
+            }        \r
+        }\r
+    }\r
+}\r
+\r
+\r
   
\ No newline at end of file