diff --git a/DuplicateCheck/DuplicateCheck.csproj b/DuplicateCheck/DuplicateCheck.csproj new file mode 100644 index 0000000..c73e0d1 --- /dev/null +++ b/DuplicateCheck/DuplicateCheck.csproj @@ -0,0 +1,8 @@ + + + + Exe + netcoreapp3.1 + + + diff --git a/DuplicateCheck/Program.cs b/DuplicateCheck/Program.cs new file mode 100644 index 0000000..737e126 --- /dev/null +++ b/DuplicateCheck/Program.cs @@ -0,0 +1,87 @@ +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using System.Security.Cryptography; + +namespace DuplicateCheck +{ + class DuplicateCheckInfo + { + public string fileName; + public byte[] hashValue; + public long fileSize; + + public ulong HashKey + { + get + { + ulong hashKey = 0; + for (int i = 0; i < sizeof(ulong); i++) + { + hashKey = (hashKey << 8) ^ hashValue[i]; + } + return hashKey; + } + } + + public DuplicateCheckInfo(string fileName) + { + this.fileName = fileName; + var hash = SHA256.Create(); + using (FileStream fs = File.OpenRead(fileName)) + { + fileSize = fs.Length; + if (fileSize > 4096) + { + hash.ComputeHash(fs); + hashValue = hash.Hash; + } + } + } + + public bool IsMatch(DuplicateCheckInfo srce) + { + if (this.fileSize != srce.fileSize) + return false; + + for (int i = 0;i < hashValue.Length;i ++) + { + if (hashValue[i] != srce.hashValue[i]) + return false; + } + + return true; + } + } + + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Duplicate Check Test Logic."); + Dictionary hashData = new Dictionary(); + foreach (var item in Directory.GetFiles(@"D:\Projects\", "*", SearchOption.AllDirectories)) + { + DuplicateCheckInfo info = new DuplicateCheckInfo(item); + if (info.fileSize > 4096) + { + ulong hashValue = info.HashKey; + if (hashData.TryGetValue(hashValue, out DuplicateCheckInfo srceInfo)) + { + if (srceInfo.IsMatch(info)) + { + Console.WriteLine("Duplicate {0}, {1}", item, srceInfo.fileName); + Console.WriteLine("Copy-Item -Path \"{0}\" -Destination \"{1}\"", srceInfo.fileName, item); + Console.WriteLine("Set-ItemProperty -Path \"{0}\" -Name LastWriteTime -Value \"{1}\"", item, File.GetLastWriteTime(item).ToString("yyyy-MM-dd HH:mm:ss")); + } + } + else + { + hashData.Add(hashValue, info); + } + } + } + } + } +} diff --git a/wbackup/ArchiveTarFile.cs b/wbackup/ArchiveTarFile.cs index 1492b38..c339e61 100644 --- a/wbackup/ArchiveTarFile.cs +++ b/wbackup/ArchiveTarFile.cs @@ -26,8 +26,7 @@ public ArchiveTarFile(string exportPath, BackupStreamBase stream = null):base(stream) { - string postFixString = DateTime.Now.ToString("yyyyMMddHHmmss"); - string zipFileName = exportPath + postFixString + ".tar.gz"; + string zipFileName = exportPath + ".tar.gz"; // 出力先ストリームのインスタンス生成 fileOutputStream = new FileStream(zipFileName, FileMode.Create, FileAccess.Write); diff --git a/wbackup/Program.cs b/wbackup/Program.cs index 598dc45..37bb285 100644 --- a/wbackup/Program.cs +++ b/wbackup/Program.cs @@ -33,24 +33,26 @@ // 出力先インスタンスを生成する ParallelBackup parallel = new ParallelBackup(); + string postFixString = DateTime.Now.ToString("yyyyMMddHHmmss"); for (int i = 0; i < param.maxThreadCount; i++) { - string exportFileName = param.destinationDir + "-" + i.ToString("00") + "-"; + string exportFileName = param.destinationDir + "-" + postFixString + "-" + i.ToString("00"); parallel.AddNextStream(new ArchiveTarFile(exportFileName, new ClearArchiveFlag())); } // バックアップエンジンのインスタンスを生成する if (param.backupMode == BackupMopde.Full) { - backupEngine = new ListingAllSourceFile(parallel); + //backupEngine = new ListingAllSourceFile(parallel); + backupEngine = new ListingAllSourceFile(new RejectDuplicateFile(param.destinationDir + "-" + postFixString + ".ps1", parallel)); } if (param.backupMode == BackupMopde.Incremental) { - backupEngine = new ListingArchiveSourceFile(parallel); + backupEngine = new ListingArchiveSourceFile(new RejectDuplicateFile(param.destinationDir + "-" + postFixString + ".ps1", parallel)); } if (param.backupMode == BackupMopde.Differencial) { - backupEngine = new ListingArchiveSourceFile(parallel); + backupEngine = new ListingArchiveSourceFile(new RejectDuplicateFile(param.destinationDir + "-" + postFixString + ".ps1", parallel)); } foreach (var ignoreFile in param.ignoreFile) diff --git a/wbackup/Properties/launchSettings.json b/wbackup/Properties/launchSettings.json index a5ae103..496cd2d 100644 --- a/wbackup/Properties/launchSettings.json +++ b/wbackup/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "wbackup": { "commandName": "Project", - "commandLineArgs": "-srce \"D:\\Projects\\atozip\" -dest \"D:\\backup\\archive\" -log \"D:\\backup\\archive\" -incremental -ignore D:\\Projects\\atozip\\.git\\ -ignore D:\\Projects\\atozip\\.vs\\" + "commandLineArgs": "-srce \"D:\\Projects\\atozip\" -dest \"D:\\backup\\archive\" -log \"D:\\backup\\archive\" -full" } } } \ No newline at end of file diff --git a/wbackup/RejectDuplicateFile.cs b/wbackup/RejectDuplicateFile.cs new file mode 100644 index 0000000..f5fa511 --- /dev/null +++ b/wbackup/RejectDuplicateFile.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using System.Security.Cryptography; + +namespace wbackup +{ + class DuplicateCheckInfo + { + public string fileName; + public byte[] hashValue; + public long fileSize; + + public ulong HashKey + { + get + { + ulong hashKey = 0; + for (int i = 0; i < sizeof(ulong); i++) + { + hashKey = (hashKey << 8) ^ hashValue[i]; + } + return hashKey; + } + } + + public DuplicateCheckInfo(string fileName) + { + this.fileName = fileName; + var hash = SHA256.Create(); + using (FileStream fs = File.OpenRead(fileName)) + { + fileSize = fs.Length; + if (fileSize > 4096) + { + hash.ComputeHash(fs); + hashValue = hash.Hash; + } + } + } + + public bool IsMatch(DuplicateCheckInfo srce) + { + if (this.fileSize != srce.fileSize) + return false; + + for (int i = 0; i < hashValue.Length; i++) + { + if (hashValue[i] != srce.hashValue[i]) + return false; + } + + return true; + } + } + + class RejectDuplicateFile : BackupStreamBase + { + protected string recoveryScriptName; + protected Dictionary hashData; + + public RejectDuplicateFile(string scriptName, BackupStreamBase stream = null) : base(stream) + { + recoveryScriptName = scriptName; + hashData = new Dictionary(); + } + + protected override void DoWork(string sourceFileName) + { + if (sourceFileName == "") + AddNextSource(sourceFileName); + + DuplicateCheckInfo info = new DuplicateCheckInfo(sourceFileName); + if (info.fileSize > 4096) + { + ulong hashValue = info.HashKey; + if (hashData.TryGetValue(hashValue, out DuplicateCheckInfo srceInfo)) + { + if (srceInfo.IsMatch(info)) + { + Console.WriteLine("Duplicate {0}, {1}", sourceFileName, srceInfo.fileName); + + StringBuilder script = new StringBuilder(); + string destDir = sourceFileName.Substring(0, sourceFileName.LastIndexOf("\\") + 1); + script.AppendFormat("New-Item -Path \"{0}\" -ItemType Directory", destDir); + script.AppendLine(); + script.AppendFormat("Copy-Item -Path \"{0}\" -Destination \"{1}\"", srceInfo.fileName, sourceFileName); + script.AppendLine(); + script.AppendFormat("Set-ItemProperty -Path \"{0}\" -Name LastWriteTime -Value \"{1}\"", sourceFileName, File.GetLastWriteTime(sourceFileName).ToString("yyyy-MM-dd HH:mm:ss")); + script.AppendLine(); + File.AppendAllText(recoveryScriptName, script.ToString()); + } + else + { + AddNextSource(sourceFileName); + } + } + else + { + hashData.Add(hashValue, info); + AddNextSource(sourceFileName); + } + } + else + { + AddNextSource(sourceFileName); + } + } + } +} diff --git a/wbackup/wbackup.csproj b/wbackup/wbackup.csproj index 29d6f97..9090ef9 100644 --- a/wbackup/wbackup.csproj +++ b/wbackup/wbackup.csproj @@ -16,7 +16,7 @@ - +