2024-06-24 09:27:12 +00:00
|
|
|
|
namespace Common;
|
|
|
|
|
|
2024-10-12 06:30:56 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Dir比较方法
|
|
|
|
|
/// </summary>
|
2024-09-24 06:27:39 +00:00
|
|
|
|
public static class DirExtension
|
2024-06-24 09:27:12 +00:00
|
|
|
|
{
|
2024-09-24 09:46:52 +00:00
|
|
|
|
/// <summary>
|
2024-09-24 06:27:39 +00:00
|
|
|
|
/// 比较两个目录文件树是否相同,不相同返回差异部分,左侧是右侧的下一个版本,任何一个节点的nextop != null,即所有
|
|
|
|
|
/// 节点都会打上标记
|
|
|
|
|
/// 文件夹的 NextOp 只有新增和删除
|
2024-09-24 09:46:52 +00:00
|
|
|
|
///
|
2024-09-24 06:27:39 +00:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="otherRootDir"></param>
|
|
|
|
|
/// <returns>右侧版本接下来进行的操作</returns>
|
|
|
|
|
public static Dir Diff(this Dir thisDir, Dir other)
|
2024-06-24 09:27:12 +00:00
|
|
|
|
{
|
2024-09-24 06:27:39 +00:00
|
|
|
|
var ldir = thisDir;
|
|
|
|
|
var rdir = other;
|
|
|
|
|
Dir? cDir = new() { Path = rdir.FormatedPath, Children = [] };
|
|
|
|
|
//分别对文件和文件夹分组
|
|
|
|
|
List<File> lFiles = [];
|
|
|
|
|
List<File> rFiles = [];
|
|
|
|
|
List<Dir> lDirs = [];
|
|
|
|
|
List<Dir> rDirs = [];
|
|
|
|
|
var lGroups = ldir.Children.GroupBy(x => x.Type);
|
|
|
|
|
var rGroups = rdir.Children.GroupBy(x => x.Type);
|
|
|
|
|
foreach (var g in lGroups)
|
2024-06-24 09:27:12 +00:00
|
|
|
|
{
|
2024-09-24 06:27:39 +00:00
|
|
|
|
if (g.Key == DirOrFile.Dir)
|
|
|
|
|
{
|
|
|
|
|
lDirs = g.AsEnumerable()
|
|
|
|
|
.Select(n =>
|
|
|
|
|
{
|
|
|
|
|
if (n is Dir dir)
|
|
|
|
|
{
|
|
|
|
|
return dir;
|
|
|
|
|
}
|
|
|
|
|
throw new Exception("cannot be here");
|
|
|
|
|
})
|
|
|
|
|
.ToList();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
lFiles = g.AsEnumerable()
|
|
|
|
|
.Select(n =>
|
|
|
|
|
{
|
|
|
|
|
if (n is File file)
|
|
|
|
|
{
|
|
|
|
|
return file;
|
|
|
|
|
}
|
|
|
|
|
throw new Exception("cannot be here");
|
|
|
|
|
})
|
|
|
|
|
.ToList();
|
|
|
|
|
}
|
2024-06-24 09:27:12 +00:00
|
|
|
|
}
|
2024-09-24 06:27:39 +00:00
|
|
|
|
|
|
|
|
|
foreach (var g in rGroups)
|
2024-06-24 09:27:12 +00:00
|
|
|
|
{
|
2024-09-24 06:27:39 +00:00
|
|
|
|
if (g.Key == DirOrFile.Dir)
|
2024-06-24 09:27:12 +00:00
|
|
|
|
{
|
2024-09-24 06:27:39 +00:00
|
|
|
|
rDirs = g.AsEnumerable()
|
|
|
|
|
.Select(n =>
|
|
|
|
|
{
|
|
|
|
|
if (n is Dir dir)
|
|
|
|
|
{
|
|
|
|
|
return dir;
|
|
|
|
|
}
|
|
|
|
|
throw new Exception("cannot be here");
|
|
|
|
|
})
|
|
|
|
|
.ToList();
|
2024-06-24 09:27:12 +00:00
|
|
|
|
}
|
2024-09-24 06:27:39 +00:00
|
|
|
|
else
|
2024-06-24 09:27:12 +00:00
|
|
|
|
{
|
2024-09-24 06:27:39 +00:00
|
|
|
|
rFiles = g.AsEnumerable()
|
|
|
|
|
.Select(n =>
|
|
|
|
|
{
|
|
|
|
|
if (n is File file)
|
|
|
|
|
{
|
|
|
|
|
return file;
|
|
|
|
|
}
|
|
|
|
|
throw new Exception("cannot be here");
|
|
|
|
|
})
|
|
|
|
|
.ToList();
|
2024-06-24 09:27:12 +00:00
|
|
|
|
}
|
2024-09-24 06:27:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//排序,然后对比
|
|
|
|
|
int lIndex_f = 0;
|
|
|
|
|
int rIndex_f = 0;
|
|
|
|
|
int lIndex_d = 0;
|
|
|
|
|
int rIndex_d = 0;
|
|
|
|
|
lFiles.Sort(AFileOrDir.Compare);
|
|
|
|
|
rFiles.Sort(AFileOrDir.Compare);
|
|
|
|
|
lDirs.Sort(AFileOrDir.Compare);
|
|
|
|
|
rDirs.Sort(AFileOrDir.Compare);
|
|
|
|
|
//对比文件
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
//当两个线性表都走到最后时,退出循环
|
|
|
|
|
if (lIndex_f == lFiles.Count && rIndex_f == rFiles.Count)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
//左侧先到底,右侧都是将要删除的
|
|
|
|
|
if (lIndex_f == lFiles.Count)
|
2024-06-24 09:27:12 +00:00
|
|
|
|
{
|
2024-09-24 06:27:39 +00:00
|
|
|
|
var er = rFiles[rIndex_f];
|
|
|
|
|
cDir.Children.Add(
|
|
|
|
|
new File
|
|
|
|
|
{
|
|
|
|
|
Path = er.FormatedPath,
|
|
|
|
|
MTime = er.MTime,
|
|
|
|
|
NextOp = NextOpType.Del
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
rIndex_f++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
//右侧先到底,左侧都是要添加的
|
|
|
|
|
if (rIndex_f == rFiles.Count)
|
|
|
|
|
{
|
|
|
|
|
var el = lFiles[lIndex_f];
|
|
|
|
|
|
|
|
|
|
cDir.Children.Add(
|
|
|
|
|
new File
|
|
|
|
|
{
|
|
|
|
|
Path = el.FormatedPath.Replace(ldir.FormatedPath, rdir.FormatedPath),
|
|
|
|
|
MTime = el.MTime,
|
|
|
|
|
NextOp = NextOpType.Add
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
lIndex_f++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
var l = lFiles[lIndex_f];
|
|
|
|
|
var r = rFiles[rIndex_f];
|
|
|
|
|
//将根路径差异抹平
|
|
|
|
|
var lreativePath = l.FormatedPath.Replace(ldir.FormatedPath, "");
|
|
|
|
|
var rreativePath = r.FormatedPath.Replace(rdir.FormatedPath, "");
|
|
|
|
|
//两文件相同,对比文件修改时间,不同增加到diff内容
|
|
|
|
|
if (lreativePath == rreativePath)
|
|
|
|
|
{
|
|
|
|
|
lIndex_f++;
|
|
|
|
|
rIndex_f++;
|
2024-09-27 07:02:55 +00:00
|
|
|
|
// 如果最新版的时间大于旧版时间超过5s才更新,文件时间在传输过程中产生了精度损失。
|
|
|
|
|
// Warrning 如果旧版文件的最后修改时间大于新版文件,将不会更新
|
|
|
|
|
if ((l.MTime - r.MTime).TotalSeconds > 5)
|
2024-06-24 09:27:12 +00:00
|
|
|
|
{
|
2024-09-24 06:27:39 +00:00
|
|
|
|
cDir.Children.Add(
|
|
|
|
|
new File
|
|
|
|
|
{
|
|
|
|
|
Path = r.FormatedPath,
|
|
|
|
|
MTime = l.MTime,
|
|
|
|
|
NextOp = NextOpType.Modify
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//因为已经按照文件路径排过序了,当左侧文件名大于右侧,那么将根据右侧,添加一个删除diff
|
|
|
|
|
if (lreativePath.CompareTo(rreativePath) > 0)
|
|
|
|
|
{
|
|
|
|
|
rIndex_f++;
|
|
|
|
|
cDir.Children.Add(
|
|
|
|
|
new File
|
|
|
|
|
{
|
|
|
|
|
Path = r.FormatedPath,
|
|
|
|
|
MTime = r.MTime,
|
|
|
|
|
NextOp = NextOpType.Del
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
//相反,根据左侧,添加一个新增diff
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
lIndex_f++;
|
|
|
|
|
cDir.Children.Add(
|
|
|
|
|
new File
|
|
|
|
|
{
|
|
|
|
|
Path = l.FormatedPath.Replace(ldir.FormatedPath, rdir.FormatedPath),
|
|
|
|
|
MTime = l.MTime,
|
|
|
|
|
NextOp = NextOpType.Add
|
|
|
|
|
}
|
|
|
|
|
);
|
2024-06-24 09:27:12 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-24 06:27:39 +00:00
|
|
|
|
//文件夹的比较和文件类似,但是他会递归调用文件夹的diff函数,直至文件停止
|
2024-06-24 09:27:12 +00:00
|
|
|
|
|
2024-09-24 06:27:39 +00:00
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
if (lIndex_d == lDirs.Count && rIndex_d == rDirs.Count)
|
2024-06-24 09:27:12 +00:00
|
|
|
|
{
|
2024-09-24 06:27:39 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (lIndex_d == lDirs.Count)
|
|
|
|
|
{
|
|
|
|
|
var er = rDirs[rIndex_d];
|
|
|
|
|
cDir.Children.Add(er.Clone(NextOpType.Del, true));
|
|
|
|
|
rIndex_d++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (rIndex_d == rDirs.Count)
|
|
|
|
|
{
|
|
|
|
|
var el = lDirs[lIndex_d];
|
|
|
|
|
cDir.Children.Add(
|
|
|
|
|
el.Clone(NextOpType.Add, true)
|
|
|
|
|
.ResetRootPath(ldir.FormatedPath, rdir.FormatedPath)
|
|
|
|
|
);
|
|
|
|
|
lIndex_d++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
var l = lDirs[lIndex_d];
|
|
|
|
|
var r = rDirs[rIndex_d];
|
|
|
|
|
var lreativePath = l.FormatedPath.Replace(ldir.FormatedPath, "");
|
|
|
|
|
var rreativePath = r.FormatedPath.Replace(rdir.FormatedPath, "");
|
|
|
|
|
if (lreativePath == rreativePath)
|
|
|
|
|
{
|
|
|
|
|
lIndex_d++;
|
|
|
|
|
rIndex_d++;
|
|
|
|
|
var rDir = l.Diff(r);
|
|
|
|
|
//而等于0,这表示此文件夹的内容没有变化
|
|
|
|
|
if (rDir.Children.Count != 0)
|
2024-06-24 09:27:12 +00:00
|
|
|
|
{
|
2024-09-24 06:27:39 +00:00
|
|
|
|
cDir.Children.Add(rDir);
|
2024-06-24 09:27:12 +00:00
|
|
|
|
}
|
2024-09-24 06:27:39 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//文件夹重命名将会触发整个文件夹的删除和新增操作,这里没有办法定位到操作是修改文件夹(?) 和git类似。
|
|
|
|
|
//潜在的问题是,修改文件夹名,此文件夹包含大量的文件,将触发大量操作。
|
|
|
|
|
|
|
|
|
|
if (lreativePath.CompareTo(rreativePath) > 0)
|
2024-06-24 09:27:12 +00:00
|
|
|
|
{
|
2024-09-24 06:27:39 +00:00
|
|
|
|
cDir.Children.Add(r.Clone(NextOpType.Del, true));
|
|
|
|
|
rIndex_d++;
|
2024-06-24 09:27:12 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-09-24 06:27:39 +00:00
|
|
|
|
cDir.Children.Add(
|
|
|
|
|
l.Clone(NextOpType.Add, true)
|
|
|
|
|
.ResetRootPath(ldir.FormatedPath, rdir.FormatedPath)
|
|
|
|
|
);
|
|
|
|
|
lIndex_d++;
|
2024-06-24 09:27:12 +00:00
|
|
|
|
}
|
2024-09-24 06:27:39 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return cDir;
|
|
|
|
|
}
|
2024-06-24 09:27:12 +00:00
|
|
|
|
|
2024-10-12 06:30:56 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 根据Dirobject记录的信息,写入磁盘
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="thisDir"></param>
|
|
|
|
|
/// <param name="fileDirOp"> 文件操作类,它是如何写入文件的方法</param>
|
|
|
|
|
/// <exception cref="ArgumentException"></exception>
|
2024-09-24 06:27:39 +00:00
|
|
|
|
public static void WriteByThisInfo(this Dir thisDir, FileDirOpStra fileDirOp)
|
|
|
|
|
{
|
|
|
|
|
static void f(Dir dir, FileDirOpStra fileDirOp)
|
|
|
|
|
{
|
|
|
|
|
dir.AccessCheck();
|
|
|
|
|
foreach (var child in dir.Children)
|
|
|
|
|
{
|
|
|
|
|
if (child.Type == DirOrFile.Dir)
|
|
|
|
|
{
|
|
|
|
|
if (child is Dir childDir)
|
|
|
|
|
{
|
2024-09-27 10:41:12 +00:00
|
|
|
|
if (childDir.NextOp != NextOpType.Del)
|
|
|
|
|
{
|
|
|
|
|
fileDirOp.DirCreate(childDir, false);
|
|
|
|
|
f(childDir, fileDirOp);
|
|
|
|
|
}
|
2024-09-24 06:27:39 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (child is File childFile)
|
|
|
|
|
{
|
2024-09-27 10:41:12 +00:00
|
|
|
|
if (childFile.NextOp != NextOpType.Del)
|
|
|
|
|
{
|
|
|
|
|
fileDirOp.FileCreate(child.FormatedPath, childFile.MTime);
|
|
|
|
|
}
|
2024-09-24 06:27:39 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException("child is not File!");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
f(thisDir, fileDirOp);
|
2024-06-24 09:27:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-10-12 06:30:56 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 从文件夹中提取文件信息
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="thisDir"></param>
|
|
|
|
|
/// <param name="cherryPicks">只提取这些信息,最高级别</param>
|
|
|
|
|
/// <param name="exculdes">忽略这些文件信息</param>
|
|
|
|
|
/// <exception cref="NotSupportedException"></exception>
|
2024-09-24 06:27:39 +00:00
|
|
|
|
public static void ExtractInfo(
|
|
|
|
|
this Dir thisDir,
|
|
|
|
|
List<string>? cherryPicks = null,
|
|
|
|
|
List<string>? exculdes = null
|
|
|
|
|
)
|
2024-06-24 09:27:12 +00:00
|
|
|
|
{
|
2024-09-24 06:27:39 +00:00
|
|
|
|
bool filter(string path)
|
2024-06-24 09:27:12 +00:00
|
|
|
|
{
|
2024-09-24 09:46:52 +00:00
|
|
|
|
var relativePath = path.Replace('\\', '/').Replace(thisDir.FormatedPath, "");
|
2024-09-24 06:27:39 +00:00
|
|
|
|
if (cherryPicks != null)
|
2024-06-24 09:27:12 +00:00
|
|
|
|
{
|
2024-09-24 09:46:52 +00:00
|
|
|
|
return cherryPicks.Contains(relativePath);
|
2024-06-24 09:27:12 +00:00
|
|
|
|
}
|
2024-09-24 06:27:39 +00:00
|
|
|
|
|
|
|
|
|
if (exculdes != null)
|
2024-06-24 09:27:12 +00:00
|
|
|
|
{
|
2024-09-24 09:46:52 +00:00
|
|
|
|
return !exculdes.Contains(relativePath);
|
2024-06-24 09:27:12 +00:00
|
|
|
|
}
|
2024-09-24 06:27:39 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (thisDir.Children.Count != 0)
|
|
|
|
|
{
|
|
|
|
|
throw new NotSupportedException("this dir is not empty.");
|
|
|
|
|
}
|
2024-09-24 09:46:52 +00:00
|
|
|
|
if (Directory.Exists(thisDir.FormatedPath))
|
2024-09-24 06:27:39 +00:00
|
|
|
|
{
|
2024-09-24 09:46:52 +00:00
|
|
|
|
string[] files = Directory.GetFiles(thisDir.FormatedPath);
|
|
|
|
|
string[] dirs = Directory.GetDirectories(thisDir.FormatedPath);
|
|
|
|
|
foreach (var file in files)
|
2024-09-24 06:27:39 +00:00
|
|
|
|
{
|
2024-09-24 09:46:52 +00:00
|
|
|
|
if (filter(file))
|
|
|
|
|
{
|
|
|
|
|
thisDir.Children.Add(
|
|
|
|
|
new File { Path = file, MTime = System.IO.File.GetLastWriteTime($"{file}") }
|
|
|
|
|
);
|
|
|
|
|
}
|
2024-09-24 06:27:39 +00:00
|
|
|
|
}
|
2024-09-24 09:46:52 +00:00
|
|
|
|
foreach (var dir in dirs)
|
2024-09-24 06:27:39 +00:00
|
|
|
|
{
|
2024-09-24 09:46:52 +00:00
|
|
|
|
if (filter(dir))
|
|
|
|
|
{
|
|
|
|
|
var ndir = new Dir { Path = dir, Children = [] };
|
|
|
|
|
ndir.ExtractInfo(cherryPicks, exculdes);
|
|
|
|
|
thisDir.Children.Add(ndir);
|
|
|
|
|
}
|
2024-09-24 06:27:39 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-24 09:27:12 +00:00
|
|
|
|
}
|
2024-10-12 06:30:56 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 添加一个子对象,这个不包含文件或文件夹的创建
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="thisDir"></param>
|
|
|
|
|
/// <param name="child"></param>
|
|
|
|
|
/// <exception cref="ArgumentException"></exception>
|
2024-09-24 06:27:39 +00:00
|
|
|
|
public static void AddChild(this Dir thisDir, AFileOrDir child)
|
|
|
|
|
{
|
|
|
|
|
if (child.FormatedPath[..thisDir.FormatedPath.Length] != thisDir.FormatedPath)
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException("their rootpath are not same!");
|
|
|
|
|
}
|
|
|
|
|
var filtedChildren = thisDir.Children.Where(x => x.Type == child.Type);
|
|
|
|
|
|
|
|
|
|
var mached = filtedChildren.Where(x => x.FormatedPath == child.FormatedPath);
|
|
|
|
|
|
|
|
|
|
if (mached.Any())
|
|
|
|
|
{
|
|
|
|
|
if (child is File)
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException(
|
|
|
|
|
$"there are same path in the children:{child.FormatedPath}"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else if (child is Dir dir)
|
|
|
|
|
{
|
|
|
|
|
var tdir = mached.FirstOrDefault();
|
|
|
|
|
if (tdir is Dir ndir)
|
|
|
|
|
{
|
|
|
|
|
foreach (var d in dir.Children)
|
|
|
|
|
{
|
|
|
|
|
ndir.AddChild(d);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
thisDir.Children.Add(child);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-12 06:30:56 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 合并diffdir中的内容
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="thisDir"></param>
|
|
|
|
|
/// <param name="diffdir"></param>
|
|
|
|
|
/// <param name="IsUpdateObject">是否更新对象</param>
|
|
|
|
|
/// <param name="IsUpdateDirFile">是否更新文件夹和文件</param>
|
|
|
|
|
/// <exception cref="ArgumentException"></exception>
|
|
|
|
|
/// <exception cref="NotImplementedException"></exception>
|
2024-09-24 06:27:39 +00:00
|
|
|
|
public static void Combine(
|
|
|
|
|
this Dir thisDir,
|
2024-07-26 08:04:00 +00:00
|
|
|
|
FileDirOpStra? fileDirOp,
|
2024-07-12 06:15:38 +00:00
|
|
|
|
Dir diffdir,
|
|
|
|
|
bool IsUpdateObject = true,
|
|
|
|
|
bool IsUpdateDirFile = false
|
|
|
|
|
)
|
|
|
|
|
{
|
2024-07-30 05:24:47 +00:00
|
|
|
|
///验证 target 文件或者文件夹是否具备相关文件权限。
|
|
|
|
|
if (IsUpdateDirFile)
|
|
|
|
|
{
|
|
|
|
|
diffdir.AccessCheck();
|
|
|
|
|
}
|
2024-09-24 06:27:39 +00:00
|
|
|
|
if (thisDir.FormatedPath != diffdir.FormatedPath)
|
2024-07-12 06:15:38 +00:00
|
|
|
|
{
|
2024-07-26 04:49:08 +00:00
|
|
|
|
throw new ArgumentException("their path is not same");
|
2024-07-12 06:15:38 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-09-24 06:27:39 +00:00
|
|
|
|
var ldir = thisDir;
|
2024-07-12 06:15:38 +00:00
|
|
|
|
var rdir = diffdir;
|
|
|
|
|
|
|
|
|
|
foreach (var oc in diffdir.Children)
|
|
|
|
|
{
|
|
|
|
|
if (oc is File rfile)
|
|
|
|
|
{
|
|
|
|
|
if (rfile.NextOp != null)
|
|
|
|
|
{
|
|
|
|
|
if (oc.NextOp == NextOpType.Add)
|
|
|
|
|
{
|
|
|
|
|
if (IsUpdateObject)
|
|
|
|
|
{
|
2024-09-24 06:27:39 +00:00
|
|
|
|
ldir.AddChild(
|
|
|
|
|
new File { Path = rfile.FormatedPath, MTime = rfile.MTime }
|
|
|
|
|
);
|
2024-07-12 06:15:38 +00:00
|
|
|
|
}
|
|
|
|
|
if (IsUpdateDirFile)
|
|
|
|
|
{
|
|
|
|
|
fileDirOp?.FileCreate(rfile.FormatedPath, rfile.MTime);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
var n = ldir
|
|
|
|
|
.Children.Where(x =>
|
|
|
|
|
x.FormatedPath == oc.FormatedPath && x.Type == DirOrFile.File
|
|
|
|
|
)
|
|
|
|
|
.FirstOrDefault();
|
|
|
|
|
if (n is not null)
|
|
|
|
|
{
|
|
|
|
|
if (oc.NextOp == NextOpType.Del)
|
|
|
|
|
{
|
|
|
|
|
if (IsUpdateObject)
|
|
|
|
|
{
|
|
|
|
|
ldir.Children.Remove(n);
|
|
|
|
|
}
|
|
|
|
|
if (IsUpdateDirFile)
|
|
|
|
|
{
|
|
|
|
|
fileDirOp?.FileDel(rfile.FormatedPath);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (oc.NextOp == NextOpType.Modify)
|
|
|
|
|
{
|
|
|
|
|
if (n is File lfile)
|
|
|
|
|
{
|
|
|
|
|
if (IsUpdateObject)
|
|
|
|
|
{
|
|
|
|
|
lfile.MTime = rfile.MTime;
|
|
|
|
|
}
|
|
|
|
|
if (IsUpdateDirFile)
|
|
|
|
|
{
|
|
|
|
|
fileDirOp?.FileModify(rfile.FormatedPath, rfile.MTime);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (oc is Dir rrdir)
|
|
|
|
|
{
|
|
|
|
|
//新增和删除意味着整个文件夹都被新增和删除
|
|
|
|
|
if (rrdir.NextOp == NextOpType.Add)
|
|
|
|
|
{
|
|
|
|
|
if (IsUpdateDirFile)
|
|
|
|
|
{
|
|
|
|
|
fileDirOp?.DirCreate(rrdir);
|
|
|
|
|
}
|
|
|
|
|
if (IsUpdateObject)
|
|
|
|
|
{
|
|
|
|
|
ldir.AddChild(rrdir.Clone(null, true));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (rrdir.NextOp == NextOpType.Del)
|
|
|
|
|
{
|
|
|
|
|
if (IsUpdateDirFile)
|
|
|
|
|
{
|
2024-07-26 04:49:08 +00:00
|
|
|
|
fileDirOp?.DirDel(rrdir, false);
|
2024-07-12 06:15:38 +00:00
|
|
|
|
}
|
|
|
|
|
if (IsUpdateObject)
|
|
|
|
|
{
|
|
|
|
|
ldir.Children.RemoveAt(
|
|
|
|
|
ldir.Children.FindIndex(x => x.FormatedPath == rrdir.FormatedPath)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//当子文件夹和文件不确定时
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
var n = ldir
|
|
|
|
|
.Children.Where(x =>
|
|
|
|
|
x.FormatedPath == rrdir.FormatedPath && x.Type == DirOrFile.Dir
|
|
|
|
|
)
|
|
|
|
|
.FirstOrDefault();
|
|
|
|
|
if (n is Dir lldir)
|
|
|
|
|
{
|
|
|
|
|
lldir.Combine(fileDirOp, rrdir, IsUpdateObject, IsUpdateDirFile);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-24 09:27:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-10-12 06:30:56 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// clone一个新的对象
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="thisDir"></param>
|
|
|
|
|
/// <param name="optype">重设的操作类型</param>
|
|
|
|
|
/// <param name="IsResetNextOpType">是否重设操作类型</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
/// <exception cref="Exception"></exception>
|
2024-09-24 06:27:39 +00:00
|
|
|
|
public static Dir Clone(
|
|
|
|
|
this Dir thisDir,
|
|
|
|
|
NextOpType? optype = null,
|
|
|
|
|
bool IsResetNextOpType = false
|
|
|
|
|
)
|
2024-06-24 09:27:12 +00:00
|
|
|
|
{
|
2024-09-24 06:27:39 +00:00
|
|
|
|
var ndir = new Dir
|
2024-06-24 09:27:12 +00:00
|
|
|
|
{
|
2024-09-24 06:27:39 +00:00
|
|
|
|
Path = thisDir.FormatedPath,
|
|
|
|
|
Children = [],
|
|
|
|
|
NextOp = IsResetNextOpType ? optype : thisDir.NextOp
|
|
|
|
|
};
|
2024-06-24 09:27:12 +00:00
|
|
|
|
|
2024-09-24 06:27:39 +00:00
|
|
|
|
var nchildren = thisDir
|
|
|
|
|
.Children.AsEnumerable()
|
|
|
|
|
.Select(x =>
|
2024-06-24 09:27:12 +00:00
|
|
|
|
{
|
2024-09-24 06:27:39 +00:00
|
|
|
|
if (x is File file)
|
2024-06-24 09:27:12 +00:00
|
|
|
|
{
|
2024-09-24 06:27:39 +00:00
|
|
|
|
return new File
|
|
|
|
|
{
|
|
|
|
|
Path = file.FormatedPath,
|
|
|
|
|
MTime = file.MTime,
|
|
|
|
|
NextOp = IsResetNextOpType ? optype : file.NextOp
|
|
|
|
|
} as AFileOrDir;
|
|
|
|
|
}
|
|
|
|
|
else if (x is Dir dir)
|
|
|
|
|
{
|
|
|
|
|
return dir.Clone(optype, IsResetNextOpType);
|
2024-06-24 09:27:12 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-09-24 06:27:39 +00:00
|
|
|
|
throw new Exception("cannot be here!");
|
2024-06-24 09:27:12 +00:00
|
|
|
|
}
|
2024-09-24 06:27:39 +00:00
|
|
|
|
})
|
|
|
|
|
.ToList();
|
|
|
|
|
ndir.Children = nchildren;
|
|
|
|
|
|
|
|
|
|
return ndir;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-12 06:30:56 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 改变根路径位置
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="thisDir"></param>
|
|
|
|
|
/// <param name="oldPath"></param>
|
|
|
|
|
/// <param name="newPath"></param>
|
|
|
|
|
/// <returns></returns>
|
2024-09-24 06:27:39 +00:00
|
|
|
|
public static Dir ResetRootPath(this Dir thisDir, string oldPath, string newPath)
|
|
|
|
|
{
|
|
|
|
|
thisDir.FormatedPath = thisDir.FormatedPath.Replace(oldPath, newPath);
|
|
|
|
|
thisDir.Children.ForEach(e =>
|
|
|
|
|
{
|
|
|
|
|
if (e is File file)
|
|
|
|
|
{
|
|
|
|
|
file.FormatedPath = file.FormatedPath.Replace(oldPath, newPath);
|
2024-06-24 09:27:12 +00:00
|
|
|
|
}
|
2024-09-24 06:27:39 +00:00
|
|
|
|
else if (e is Dir dir)
|
|
|
|
|
{
|
|
|
|
|
dir.ResetRootPath(oldPath, newPath);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return thisDir;
|
2024-06-24 09:27:12 +00:00
|
|
|
|
}
|
2024-07-12 06:15:38 +00:00
|
|
|
|
|
2024-10-12 06:30:56 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 文件操作权限检查(废弃)
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="thisDir"></param>
|
2024-09-24 06:27:39 +00:00
|
|
|
|
public static void AccessCheck(this Dir thisDir)
|
2024-07-26 08:04:00 +00:00
|
|
|
|
{
|
2024-09-09 00:59:33 +00:00
|
|
|
|
//不是核心关注点,下面实现有bug。不校验所有文件夹权限,创建时会抛出错误,此时手动处理吧。
|
|
|
|
|
return;
|
|
|
|
|
//this.Children.ForEach(e =>
|
|
|
|
|
//{
|
|
|
|
|
// if (e is File file)
|
|
|
|
|
// {
|
|
|
|
|
// if (file.NextOp == null) { }
|
|
|
|
|
// else if (file.NextOp == NextOpType.Add)
|
|
|
|
|
// {
|
|
|
|
|
// if (
|
|
|
|
|
// !AccessWrapper.CheckDirAccess(
|
|
|
|
|
// Path.GetDirectoryName(file.FormatedPath)
|
|
|
|
|
// ?? throw new DirectoryNotFoundException(
|
|
|
|
|
// $"{file.FormatedPath} 此父路径不存在"
|
|
|
|
|
// ),
|
|
|
|
|
// [DirAcess.CreateFiles]
|
|
|
|
|
// )
|
|
|
|
|
// )
|
|
|
|
|
// {
|
|
|
|
|
// throw new UnauthorizedAccessException($"{file.FormatedPath} 无权限创建文件");
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// else if (file.NextOp == NextOpType.Modify)
|
|
|
|
|
// {
|
|
|
|
|
// if (
|
|
|
|
|
// !(
|
|
|
|
|
// AccessWrapper.CheckFileAccess(file.FormatedPath, [FileAccess.Delete])
|
|
|
|
|
// && AccessWrapper.CheckDirAccess(
|
|
|
|
|
// Path.GetDirectoryName(file.FormatedPath)
|
|
|
|
|
// ?? throw new DirectoryNotFoundException(
|
|
|
|
|
// $"{file.FormatedPath} 此父路径不存在"
|
|
|
|
|
// ),
|
|
|
|
|
// [DirAcess.CreateFiles]
|
|
|
|
|
// )
|
|
|
|
|
// )
|
|
|
|
|
// )
|
|
|
|
|
// {
|
|
|
|
|
// throw new UnauthorizedAccessException(
|
|
|
|
|
// $"{file.FormatedPath} 无权限删除源文件或者创建新文件"
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// else if (file.NextOp == NextOpType.Del)
|
|
|
|
|
// {
|
|
|
|
|
// if (!AccessWrapper.CheckFileAccess(file.FormatedPath, [FileAccess.Delete]))
|
|
|
|
|
// {
|
|
|
|
|
// throw new UnauthorizedAccessException($"{file.FormatedPath} 无权限删除源文件");
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// else if (e is Dir dir)
|
|
|
|
|
// {
|
|
|
|
|
// if (dir.NextOp == null) { }
|
|
|
|
|
// else if (dir.NextOp == NextOpType.Add)
|
|
|
|
|
// {
|
|
|
|
|
// if (
|
|
|
|
|
// !AccessWrapper.CheckDirAccess(
|
|
|
|
|
// Path.GetDirectoryName(dir.FormatedPath)
|
|
|
|
|
// ?? throw new DirectoryNotFoundException(
|
|
|
|
|
// $"{dir.FormatedPath} 此父路径不存在"
|
|
|
|
|
// ),
|
|
|
|
|
// [DirAcess.CreateDirectories, DirAcess.CreateFiles]
|
|
|
|
|
// )
|
|
|
|
|
// )
|
|
|
|
|
// {
|
|
|
|
|
// throw new UnauthorizedAccessException($"{dir.FormatedPath} 无权限创建文件夹或者文件");
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// else if (dir.NextOp == NextOpType.Del)
|
|
|
|
|
// {
|
|
|
|
|
// if (!AccessWrapper.CheckDirAccess(dir.FormatedPath, [DirAcess.Delete]))
|
|
|
|
|
// {
|
|
|
|
|
// throw new UnauthorizedAccessException($"{dir.FormatedPath} 无权限删除文件夹");
|
|
|
|
|
// }
|
|
|
|
|
// else
|
|
|
|
|
// {
|
|
|
|
|
// //校验是否拥有子文件或者文件夹的删除权限,
|
|
|
|
|
// dir.AccessCheck();
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//});
|
2024-07-26 08:04:00 +00:00
|
|
|
|
}
|
2024-09-24 06:27:39 +00:00
|
|
|
|
}
|