Changed ETag calculation to SHA256
[pithos-ms-client] / trunk / Pithos.Core / Agents / Downloader.cs
index d0419b8..ea480ff 100644 (file)
@@ -1,9 +1,7 @@
 using System;\r
-using System.Collections.Generic;\r
 using System.ComponentModel.Composition;\r
 using System.Diagnostics.Contracts;\r
 using System.IO;\r
-using System.Linq;\r
 using System.Reflection;\r
 using System.Threading;\r
 using System.Threading.Tasks;\r
@@ -21,6 +19,8 @@ namespace Pithos.Core.Agents
         [Import]\r
         private IStatusKeeper StatusKeeper { get; set; }\r
 \r
+        [Import]\r
+        private IPithosSettings Settings { get; set; }\r
         \r
         public IStatusNotification StatusNotification { get; set; }\r
 \r
@@ -35,7 +35,7 @@ namespace Pithos.Core.Agents
 \r
 \r
         //Download a file.\r
-        public async Task DownloadCloudFile(AccountInfo accountInfo, ObjectInfo cloudFile, string filePath,CancellationToken cancellationToken)\r
+        public async Task<TreeHash> DownloadCloudFile(AccountInfo accountInfo, ObjectInfo cloudFile, string filePath,CancellationToken cancellationToken)\r
         {\r
             if (accountInfo == null)\r
                 throw new ArgumentNullException("accountInfo");\r
@@ -54,34 +54,43 @@ namespace Pithos.Core.Agents
                 {\r
                    // var cancellationToken=_cts.Token;//  .ThrowIfCancellationRequested();\r
 \r
+                    //The file's treehash after download completes. For directories, the treehash is always the empty hash\r
+                    var finalHash = TreeHash.Empty;\r
+\r
                     if (await WaitOrAbort(accountInfo,cloudFile, cancellationToken).ConfigureAwait(false))\r
-                        return;\r
-                \r
+                        return finalHash;\r
+\r
+                    var fileName = Path.GetFileName(filePath);\r
+\r
+                    var info = FileInfoExtensions.FromPath(filePath).WithProperCapitalization();\r
+\r
                     TreeHash localTreeHash;\r
-                    using (StatusNotification.GetNotifier("Hashing for Download {0}", "Hashed for Download {0}", Path.GetFileName(filePath)))\r
+\r
+                    using (StatusNotification.GetNotifier("Hashing for Download {0}", "Hashed for Download {0}", fileName))\r
                     {\r
+                        var state = StatusKeeper.GetStateByFilePath(filePath);\r
+                        var progress = new Progress<double>(d =>\r
+                            StatusNotification.Notify(new StatusNotification(String.Format("Hashing for Download {0} of {1}", d, fileName))));\r
 \r
-                        localTreeHash = Signature.CalculateTreeHashAsync(filePath,\r
-                                                                            accountInfo.BlockSize,\r
-                                                                            accountInfo.BlockHash, 1);\r
+                        localTreeHash = StatusAgent.CalculateTreeHash(info, accountInfo, state, Settings.HashingParallelism, cancellationToken, progress);\r
                     }\r
-\r
-                    var localPath = FileInfoExtensions.GetProperFilePathCapitalization(filePath);\r
+                    \r
+                    var localPath = info.FullName;\r
                     var relativeUrl = new Uri(cloudFile.Name, UriKind.Relative);\r
 \r
                     var url = relativeUrl.ToString();\r
                     if (cloudFile.Name.EndsWith(".ignore", StringComparison.InvariantCultureIgnoreCase))\r
-                        return;\r
+                        return finalHash;\r
 \r
                     if (!Selectives.IsSelected(accountInfo,cloudFile))\r
-                        return;\r
+                        return finalHash;\r
 \r
 \r
                     //Are we already downloading or uploading the file? \r
                     using (var gate = NetworkGate.Acquire(localPath, NetworkOperation.Downloading))\r
                     {\r
                         if (gate.Failed)\r
-                            return;\r
+                            return finalHash;\r
 \r
                         var client = new CloudFilesClient(accountInfo);\r
                         var account = cloudFile.Account;\r
@@ -111,7 +120,7 @@ namespace Pithos.Core.Agents
                         }\r
                         else\r
                         {\r
-                            var isChanged = IsObjectChanged(cloudFile, localPath);\r
+                            var isChanged = IsObjectChanged(cloudFile, localPath,localTreeHash);\r
                             if (isChanged)\r
                             {\r
                                 //Retrieve the hashmap from the server\r
@@ -132,13 +141,18 @@ namespace Pithos.Core.Agents
                                     var attributes = File.GetAttributes(localPath);\r
                                     File.SetAttributes(localPath, attributes | FileAttributes.ReadOnly);\r
                                 }\r
+\r
+                                //Once download completes, the final hash will be equal to the server hash\r
+                                finalHash = serverHash;\r
+\r
                             }\r
                         }\r
 \r
                         //Now we can store the object's metadata without worrying about ghost status entries\r
-                        StatusKeeper.StoreInfo(localPath, cloudFile);\r
+                        StatusKeeper.StoreInfo(localPath, cloudFile,finalHash);\r
 \r
                     }\r
+                    return finalHash;\r
                 }\r
            \r
         }\r
@@ -175,8 +189,11 @@ namespace Pithos.Core.Agents
             StatusNotification.SetPithosStatus(PithosStatus.LocalSyncing, String.Format("Calculating hashmap for {0} before download", Path.GetFileName(localPath)));\r
             //Calculate the file's treehash\r
 \r
-            //TODO: Should pass cancellation token here\r
-            var treeHash = localTreeHash ?? Signature.CalculateTreeHashAsync(localPath, (int)serverHash.BlockSize, serverHash.BlockHash, 2);\r
+            var fileName = Path.GetFileName(localPath);\r
+            var progress = new Progress<double>(d =>\r
+                StatusNotification.Notify(new StatusNotification(String.Format("Hashing for Download {0} of {1}", d, fileName))));\r
+            \r
+            var treeHash = localTreeHash ?? Signature.CalculateTreeHashAsync(localPath, (int)serverHash.BlockSize, serverHash.BlockHash, Settings.HashingParallelism,cancellationToken,progress);\r
 \r
             //And compare it with the server's hash\r
             var upHashes = serverHash.GetHashesAsStrings();\r
@@ -213,7 +230,7 @@ namespace Pithos.Core.Agents
                     if (i < upHashes.Length - 1)\r
                         end = ((i + 1) * serverHash.BlockSize);\r
 \r
-                    //TODO: Pass token here\r
+                    \r
                     //Download the missing block\r
                     byte[] block = await client.GetBlock(cloudFile.Account, cloudFile.Container, relativeUrl, start, end, cancellationToken).ConfigureAwait(false);\r
 \r
@@ -235,6 +252,7 @@ namespace Pithos.Core.Agents
                 StatusNotification.NotifyChangedFile(localPath);\r
 \r
             Log.InfoFormat("[BLOCK GET] COMPLETE {0}", localPath);\r
+            \r
         }\r
 \r
         //Download a small file with a single GET operation\r
@@ -272,8 +290,6 @@ namespace Pithos.Core.Agents
             if (!Directory.Exists(tempFolder))\r
                 Directory.CreateDirectory(tempFolder);\r
 \r
-            //TODO: Should pass the token here\r
-\r
             //Download the object to the temporary location\r
             await client.GetObject(cloudFile.Account, cloudFile.Container, relativeUrl.ToString(), tempPath, cancellationToken).ConfigureAwait(false);\r
 \r
@@ -317,7 +333,7 @@ namespace Pithos.Core.Agents
                                           : new ProgressNotification(fileName, "Downloading", block, blockPercentage, totalBlocks, fileSize));\r
         }\r
 \r
-        private bool IsObjectChanged(ObjectInfo cloudFile, string localPath)\r
+        private bool IsObjectChanged(ObjectInfo cloudFile, string localPath,TreeHash localTreeHash)\r
         {\r
             //If the target is a directory, there are no changes to download\r
             if (Directory.Exists(localPath))\r
@@ -330,10 +346,9 @@ namespace Pithos.Core.Agents
             if (localState == null)\r
                 return true;\r
 \r
-            var info = new FileInfo(localPath);\r
-            var shortHash = info.ComputeShortHash(StatusNotification);\r
+            var localHash= localTreeHash.TopHash.ToHashString();\r
             //If the file is different from the stored state, we have a change\r
-            if (localState.ShortHash != shortHash)\r
+            if (localState.Checksum != localHash)\r
                 return true;\r
             //If the top hashes differ, we have a change\r
             return (localState.Checksum != cloudFile.X_Object_Hash);\r