DocSpace-client/thirdparty/AppLimit.CloudComputing.SharpBox/SyncFramework/DirectoryDiff.cs
2020-03-13 16:40:58 +03:00

209 lines
7.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
namespace AppLimit.CloudComputing.SharpBox.SyncFramework
{
/// <summary>
/// This class generates the differences between two folders, one on the local
/// filesystem and one in the cloud
/// </summary>
internal class DirectoryDiff
{
private readonly DirectoryInfo _localPath;
private readonly ICloudDirectoryEntry _remotePath;
/// <summary>
/// ctor for DirectoryDiff
/// </summary>
/// <param name="localPath">path of the local directory</param>
/// <param name="remotePath">path of the remote directory</param>
public DirectoryDiff(DirectoryInfo localPath, ICloudDirectoryEntry remotePath)
{
_localPath = localPath;
_remotePath = remotePath;
}
/// <summary>
/// compares a local and a remote directory. The result will be a list of differences!
/// </summary>
/// <param name="bRecursive">check also sub directories</param>
/// <returns></returns>
public List<DirectoryDiffResultItem> 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<DirectoryDiffResultItem>();
// 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<string, ICloudFileSystemEntry> CreateRemoteFileList(ICloudDirectoryEntry start, bool bRescusive)
{
// result
var result = new SortedDictionary<string, ICloudFileSystemEntry>();
// directoryStack
var directoryStack = new Stack<ICloudDirectoryEntry>();
// 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<string, FileSystemInfo> CreateLocalFileList(DirectoryInfo start, bool bRescusive)
{
// result
var result = new SortedDictionary<string, FileSystemInfo>();
// directoryStack
var directoryStack = new Stack<DirectoryInfo>();
// 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;
}
}
}