diff --git a/Duplicati.sln b/Duplicati.sln index 879a03397..47c8cfa25 100644 --- a/Duplicati.sln +++ b/Duplicati.sln @@ -166,6 +166,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Crashlog" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.CIFS", "Duplicati\Library\Backend\CIFS\Duplicati.Library.Backend.CIFS.csproj", "{836E0557-B40C-4DC7-9A2A-5C062F9ACC6B}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{15388C37-9218-4818-972E-738EEA8F1602}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RemoteSynchronization", "Tools\RemoteSynchronization\RemoteSynchronization.csproj", "{D3A7E41E-279D-4E0A-A2DB-5E8002E02B6D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -472,6 +476,10 @@ Global {836E0557-B40C-4DC7-9A2A-5C062F9ACC6B}.Debug|Any CPU.Build.0 = Debug|Any CPU {836E0557-B40C-4DC7-9A2A-5C062F9ACC6B}.Release|Any CPU.ActiveCfg = Release|Any CPU {836E0557-B40C-4DC7-9A2A-5C062F9ACC6B}.Release|Any CPU.Build.0 = Release|Any CPU + {D3A7E41E-279D-4E0A-A2DB-5E8002E02B6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D3A7E41E-279D-4E0A-A2DB-5E8002E02B6D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D3A7E41E-279D-4E0A-A2DB-5E8002E02B6D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D3A7E41E-279D-4E0A-A2DB-5E8002E02B6D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -532,6 +540,7 @@ Global {CA1A0EE8-DFFF-42AF-B15D-EF538357A2DE} = {E1A9B303-F281-45C5-A4F6-CADD9DE3F3C4} {8ACA2736-3C69-4FA5-BCF9-5EDF50CAF332} = {566EBBDA-19A4-4056-A615-D901D57D2439} {836E0557-B40C-4DC7-9A2A-5C062F9ACC6B} = {E1A9B303-F281-45C5-A4F6-CADD9DE3F3C4} + {D3A7E41E-279D-4E0A-A2DB-5E8002E02B6D} = {15388C37-9218-4818-972E-738EEA8F1602} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {8B40BAFE-D862-4397-9495-8F5EAF5CE80C} diff --git a/Tools/RemoteSynchronization/Program.cs b/Tools/RemoteSynchronization/Program.cs new file mode 100644 index 000000000..bd19630fe --- /dev/null +++ b/Tools/RemoteSynchronization/Program.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Duplicati.Library.Main; +using Duplicati.Library.Common.IO; +using Duplicati.Library.Interface; +using System.IO; +using System.Threading; + + +namespace RemoteSynchronization +{ + class Program + { + static void Main(string[] args) + { + var home = Environment.GetEnvironmentVariable("HOME"); + var base_path = $"{home}/git/duplicati-carl/rsync"; + var l1 = $"{base_path}/l1"; + var l2 = $"{base_path}/l2"; + var l1r = $"{base_path}/l1_restore"; + var l2r = $"{base_path}/l2_restore"; + var backup_path = $"{home}/tmp/adaptivecpp"; + + Dictionary options = new (){ + ["passphrase"] = "1234" + }; + + // Create the directories if they do not exist + foreach (var p in new string[] { base_path, l1, l2, l1r, l2r }) + { + if (!SystemIO.IO_OS.DirectoryExists(p)) + SystemIO.IO_OS.DirectoryCreate(p); + } + + // Backup the first level + using (var c = new Controller($"file://{l1}", options, null)) + { + var results = c.Backup([backup_path]); + Console.WriteLine($"Backed up {results.AddedFiles} files to {l1}"); + } + + // Sync the first level to the second level + long count = 0; + using (var b1 = Duplicati.Library.DynamicLoader.BackendLoader.GetBackend($"file://{l1}", options)) + { + var b1s = b1 as IStreamingBackend; + System.Diagnostics.Debug.Assert(b1s != null); + using (var b2 = Duplicati.Library.DynamicLoader.BackendLoader.GetBackend($"file://{l2}", options)) + { + var b2s = b2 as IStreamingBackend; + System.Diagnostics.Debug.Assert(b2s != null); + var files1 = b1s.List(); + Console.WriteLine($"Found {files1.Count()} remote files in {l1}"); + var files2 = b2s.List(); + Console.WriteLine($"Found {files2.Count()} remote files in {l2}"); + if (files1.Count() >= files2.Count()) + { + foreach (var f1 in files1) + { + if (!files2.Any(f2 => f2.Name == f1.Name)) + { + var s = new MemoryStream(); + var s1 = b1s.GetAsync(f1.Name, s, CancellationToken.None); + s1.Wait(); + var s2 = b2s.PutAsync(f1.Name, s, CancellationToken.None); + s2.Wait(); + count++; + } + } + } + else + { + Console.WriteLine("Error: l1 has less files than l2 - something is wrong"); + } + } + } + Console.WriteLine($"Synced {count} files from {l1} to {l2}"); + + // Try to restore the first level + options["restore-path"] = l1r; + using (var c = new Controller($"file://{l1}", options, null)) + { + var results = c.Restore([Path.Combine(backup_path, "*")]); + Console.WriteLine($"Restored {results.RestoredFiles} files to {options["restore-path"]}"); + } + + // Try to restore the second level + options["restore-path"] = l2r; + using (var c = new Controller($"file://{l2}", options, null)) + { + var results = c.Restore([]); + Console.WriteLine($"Restored {results.RestoredFiles} files to {options["restore-path"]}"); + } + } + } +} diff --git a/Tools/RemoteSynchronization/RemoteSynchronization.csproj b/Tools/RemoteSynchronization/RemoteSynchronization.csproj new file mode 100644 index 000000000..d1e587209 --- /dev/null +++ b/Tools/RemoteSynchronization/RemoteSynchronization.csproj @@ -0,0 +1,13 @@ + + + + Exe + net8.0 + disable + enable + + + + + +