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
[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
\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
throw new ArgumentNullException("cloudFile");\r
if (String.IsNullOrWhiteSpace(cloudFile.Account))\r
throw new ArgumentNullException("cloudFile");\r
- if (String.IsNullOrWhiteSpace(cloudFile.Container))\r
+ if (cloudFile.Container==null)\r
+ throw new ArgumentNullException("cloudFile");\r
+ if (cloudFile.Container.IsAbsoluteUri)\r
throw new ArgumentNullException("cloudFile");\r
if (String.IsNullOrWhiteSpace(filePath))\r
throw new ArgumentNullException("filePath");\r
{\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
+ return finalHash;\r
\r
var fileName = Path.GetFileName(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
+ var info = FileInfoExtensions.FromPath(filePath).WithProperCapitalization();\r
\r
TreeHash localTreeHash;\r
- \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,progress);\r
+ localTreeHash = StatusAgent.CalculateTreeHash(info, accountInfo, state, Settings.HashingParallelism, cancellationToken, progress);\r
}\r
-\r
- var localPath = FileInfoExtensions.GetProperFilePathCapitalization(filePath);\r
- var relativeUrl = new Uri(cloudFile.Name, UriKind.Relative);\r
+ \r
+ var localPath = info.FullName;\r
+ var relativeUrl = cloudFile.Name;\r
\r
var url = relativeUrl.ToString();\r
- if (cloudFile.Name.EndsWith(".ignore", StringComparison.InvariantCultureIgnoreCase))\r
- return;\r
+ if (url.EndsWith(".ignore", StringComparison.InvariantCultureIgnoreCase))\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
}\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
- var serverHash = await client.GetHashMap(account, container, url).ConfigureAwait(false);\r
+ var serverHash = await client.GetHashMap(account, container, relativeUrl).ConfigureAwait(false);\r
//If it's a small file\r
if (serverHash.Hashes.Count == 1)\r
//Download it in one go\r
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
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
- //TODO: Should pass cancellation token here\r
- var treeHash = localTreeHash ?? Signature.CalculateTreeHashAsync(localPath, (int)serverHash.BlockSize, serverHash.BlockHash, 2,progress);\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
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
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
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
+ await client.GetObject(cloudFile.Account, cloudFile.Container, relativeUrl, tempPath, cancellationToken).ConfigureAwait(false);\r
\r
//Create the local folder if it doesn't exist (necessary for shared objects)\r
var localFolder = Path.GetDirectoryName(localPath);\r
: 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
if (localState == null)\r
return true;\r
\r
- var info = new FileInfo(localPath);\r
- var etag = 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.ETag != etag)\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