using System; using System.Collections.Generic; using System.Linq; using System.IO; namespace AppLimit.CloudComputing.SharpBox.SyncFramework { /// /// This class generates the differences between two folders, one on the local /// filesystem and one in the cloud /// internal class DirectoryDiff { private readonly DirectoryInfo _localPath; private readonly ICloudDirectoryEntry _remotePath; /// /// ctor for DirectoryDiff /// /// path of the local directory /// path of the remote directory public DirectoryDiff(DirectoryInfo localPath, ICloudDirectoryEntry remotePath) { _localPath = localPath; _remotePath = remotePath; } /// /// compares a local and a remote directory. The result will be a list of differences! /// /// check also sub directories /// public List Compare(bool bRecursive) { // 1. create a recursive local file list var localFiles = CreateLocalFileList(_localPath, bRecursive); // 2. create a recursive remote file list var remoteFiles = CreateRemoteFileList(_remotePath, bRecursive); // 3. create the result list var result = new List(); // 4. performe a sorted list comparation var i = 0; var j = 0; var m = Math.Max(localFiles.Keys.Count, remoteFiles.Keys.Count); while (i < m) { string left = null; string right = null; if (i < localFiles.Keys.Count) left = localFiles.Keys.ElementAt(i); if (j < remoteFiles.Keys.Count) right = remoteFiles.Keys.ElementAt(j); var ritem = new DirectoryDiffResultItem(); if (right == null) { // right list is at end, all left items are missing ritem.localItem = localFiles.Values.ElementAt(i); ritem.remoteItem = null; ritem.compareResult = ComparisonResult.MissingInRemoteFolder; // increase local i++; } else if (left == null) { // left list is at end, all rightitems are missing ritem.localItem = null; ritem.remoteItem = remoteFiles.Values.ElementAt(j); ritem.compareResult = ComparisonResult.MissingInLocalFolder; // increase remote j++; } else { // compare both elements var iRet = left.CompareTo(right); if (iRet == 0) { // are the same elements ritem.localItem = localFiles.Values.ElementAt(i); ritem.remoteItem = remoteFiles.Values.ElementAt(j); // compare the size // set the result ritem.compareResult = ComparisonResult.Identical; // increase both i++; j++; } else if (iRet < 0) { // local missing in remote ritem.localItem = localFiles.Values.ElementAt(i); ritem.compareResult = ComparisonResult.MissingInRemoteFolder; // increase in local i++; } else { // remote missing in local ritem.remoteItem = remoteFiles.Values.ElementAt(j); ritem.compareResult = ComparisonResult.MissingInLocalFolder; // increase in remote j++; } } result.Add(ritem); } return result; } private static SortedDictionary CreateRemoteFileList(ICloudDirectoryEntry start, bool bRescusive) { // result var result = new SortedDictionary(); // directoryStack var directoryStack = new Stack(); // add the start directory to the stack directoryStack.Push(start); // do enumeration until stack is empty while (directoryStack.Count > 0) { var current = directoryStack.Pop(); foreach (var fsinfo in current) { if (fsinfo is ICloudDirectoryEntry) { // check if recursion allowed if (bRescusive == false) continue; // push the directory to stack directoryStack.Push(fsinfo as ICloudDirectoryEntry); } // build the path var path = CloudStorage.GetFullCloudPath(fsinfo, Path.DirectorySeparatorChar); var startpath = CloudStorage.GetFullCloudPath(start, Path.DirectorySeparatorChar); path = path.Remove(0, startpath.Length); // add the entry to our output list result.Add(path, fsinfo); } } return result; } private static SortedDictionary CreateLocalFileList(DirectoryInfo start, bool bRescusive) { // result var result = new SortedDictionary(); // directoryStack var directoryStack = new Stack(); // add the start directory to the stack directoryStack.Push(start); // do enumeration until stack is empty while (directoryStack.Count > 0) { var current = directoryStack.Pop(); foreach (var fsinfo in current.GetFileSystemInfos()) { if ((fsinfo.Attributes & FileAttributes.Directory) == FileAttributes.Directory) { // check if recursion allowed if (bRescusive == false) continue; // push the directory to stack directoryStack.Push(fsinfo as DirectoryInfo); } // build path var path = fsinfo.FullName; path = path.Remove(0, start.FullName.Length); // add the entry to our output list result.Add(path, fsinfo); } } return result; } } }