+ private void ProcessChildren(AccountInfo accountInfo, StateTuple tuple, FileAgent agent, ConcurrentDictionary<string, MovedEventArgs> moves,HashSet<string> processedPaths,CancellationToken token)\r
+ {\r
+\r
+ var dirInfo = tuple.FileInfo as DirectoryInfo;\r
+ var folderTuples = from folder in dirInfo.EnumerateDirectories("*", SearchOption.AllDirectories)\r
+ select new StateTuple(folder){C=Signature.MERKLE_EMPTY};\r
+ \r
+ var fileTuples = from file in dirInfo.EnumerateFiles("*", SearchOption.AllDirectories)\r
+ let state=StatusKeeper.GetStateByFilePath(file.FullName)\r
+ select new StateTuple(file){\r
+ Merkle=StatusAgent.CalculateTreeHash(file,accountInfo,state,\r
+ Settings.HashingParallelism,token,null)\r
+ };\r
+ \r
+ //Process folders first, to ensure folders appear on the sever as soon as possible\r
+ folderTuples.ApplyAction(t => SyncSingleItem(accountInfo, t, agent, moves, processedPaths,token).Wait());\r
+ \r
+ fileTuples.ApplyAction(t => SyncSingleItem(accountInfo, t, agent, moves,processedPaths, token).Wait());\r
+ }\r
+\r
+\r
+\r
+\r
+ \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
+ /// <param name="threshold"></param>\r
+ /// <param name="cloudObjects"></param>\r
+ /// <returns></returns>\r
+ private static DateTimeOffset? GetLatestDateBefore(DateTime? threshold, IList<ObjectInfo> cloudObjects)\r
+ {\r
+ DateTimeOffset? maxDate = null;\r
+ if (cloudObjects!=null && cloudObjects.Count > 0)\r
+ maxDate = cloudObjects.Max(obj => obj.Last_Modified);\r
+ if (!maxDate.HasValue)\r
+ return threshold;\r
+ if (!threshold.HasValue|| threshold > maxDate)\r
+ return maxDate;\r
+ return threshold;\r
+ }\r
+\r
+ /// <summary>\r
+ /// Returns the latest LastModified date from the list of objects, but only if it is after\r
+ /// the threshold value\r
+ /// </summary>\r
+ /// <param name="threshold"></param>\r
+ /// <param name="cloudObjects"></param>\r
+ /// <returns></returns>\r
+ private static DateTimeOffset? GetLatestDateAfter(DateTimeOffset? threshold, IList<ObjectInfo> cloudObjects)\r
+ {\r
+ DateTimeOffset? maxDate = null;\r
+ if (cloudObjects!=null && cloudObjects.Count > 0)\r
+ maxDate = cloudObjects.Max(obj => obj.Last_Modified);\r
+ if (!maxDate.HasValue)\r
+ return threshold;\r
+ if (!threshold.HasValue|| threshold < maxDate)\r
+ return maxDate;\r
+ return threshold;\r
+ }\r
+\r
+ readonly AccountsDifferencer _differencer = new AccountsDifferencer();\r
+ private bool _pause;\r
+ \r
+\r
+\r
+\r
+ private void ReportConflictForMismatch(string localFilePath)\r
+ {\r
+ if (String.IsNullOrWhiteSpace(localFilePath))\r
+ throw new ArgumentNullException("localFilePath");\r
+ Contract.EndContractBlock();\r
+\r
+ StatusKeeper.SetFileState(localFilePath, FileStatus.Conflict, FileOverlayStatus.Conflict, "File changed at the server");\r
+ UpdateStatus(PithosStatus.HasConflicts);\r
+ var message = String.Format("Conflict detected for file {0}", localFilePath);\r
+ Log.Warn(message);\r
+ StatusNotification.NotifyChange(message, TraceLevel.Warning);\r
+ }\r
+\r
+ private void ReportConflictForDoubleRename(string localFilePath)\r
+ {\r
+ if (String.IsNullOrWhiteSpace(localFilePath))\r
+ throw new ArgumentNullException("localFilePath");\r
+ Contract.EndContractBlock();\r
+\r
+ StatusKeeper.SetFileState(localFilePath, FileStatus.Conflict, FileOverlayStatus.Conflict, "File renamed both locally and on the server");\r
+ UpdateStatus(PithosStatus.HasConflicts);\r
+ var message = String.Format("Double rename conflict detected for file {0}", localFilePath);\r
+ Log.Warn(message);\r
+ StatusNotification.NotifyChange(message, TraceLevel.Warning);\r
+ }\r
+\r
+\r