diff --git a/Duplicati Console.sln b/Duplicati Console.sln
index 238311cf4..49b2af1a3 100644
--- a/Duplicati Console.sln
+++ b/Duplicati Console.sln
@@ -5,11 +5,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Main", "Duplicati
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.CommandLine", "Duplicati\CommandLine\Duplicati.CommandLine.csproj", "{81765A64-3661-4E3E-B850-2F6F87A51F74}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackendInterface", "Duplicati\Backend\BackendInterface\BackendInterface.csproj", "{994F3D0A-E91E-4EEE-80EE-064485E09909}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Backend.BackendInterface", "Duplicati\Backend\BackendInterface\Duplicati.Backend.BackendInterface.csproj", "{994F3D0A-E91E-4EEE-80EE-064485E09909}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackendLoader", "Duplicati\Backend\BackendLoader\BackendLoader.csproj", "{0CA86ECF-5BEC-4909-B4F6-110A03B30B92}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Backend.BackendLoader", "Duplicati\Backend\BackendLoader\Duplicati.Backend.BackendLoader.csproj", "{0CA86ECF-5BEC-4909-B4F6-110A03B30B92}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "File", "Duplicati\Backend\File\File.csproj", "{FC9B7611-836F-4127-8B44-A7C31F506807}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Backend.File", "Duplicati\Backend\File\Duplicati.Backend.File.csproj", "{FC9B7611-836F-4127-8B44-A7C31F506807}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Core", "Duplicati\Core\Duplicati.Core.csproj", "{DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}"
EndProject
@@ -19,6 +19,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.SharpRSync", "Dup
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Logging", "Duplicati\Logging\Duplicati.Logging.csproj", "{D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Encryption", "Duplicati\Encryption\Duplicati.Encryption.csproj", "{94484FDB-2EFA-4CF0-9BE6-A561157B4F87}"
+EndProject
Global
GlobalSection(SubversionScc) = preSolution
Svn-Managed = True
@@ -65,6 +67,10 @@ Global
{D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Release|Any CPU.Build.0 = Release|Any CPU
+ {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Duplicati/Backend/BackendInterface/BackendInterface.csproj b/Duplicati/Backend/BackendInterface/Duplicati.Backend.BackendInterface.csproj
similarity index 100%
rename from Duplicati/Backend/BackendInterface/BackendInterface.csproj
rename to Duplicati/Backend/BackendInterface/Duplicati.Backend.BackendInterface.csproj
diff --git a/Duplicati/Backend/BackendLoader/BackendLoader.cs b/Duplicati/Backend/BackendLoader/BackendLoader.cs
index fdcac69b2..7a923a1cb 100644
--- a/Duplicati/Backend/BackendLoader/BackendLoader.cs
+++ b/Duplicati/Backend/BackendLoader/BackendLoader.cs
@@ -100,6 +100,9 @@ namespace Duplicati.Backend
string scheme = new Uri(url).Scheme.ToLower();
+ if (m_backends == null)
+ LoadBackends();
+
if (m_backends.ContainsKey(scheme))
return (IBackendInterface)Activator.CreateInstance(m_backends[scheme], url, options);
else
diff --git a/Duplicati/Backend/BackendLoader/BackendLoader.csproj b/Duplicati/Backend/BackendLoader/Duplicati.Backend.BackendLoader.csproj
similarity index 91%
rename from Duplicati/Backend/BackendLoader/BackendLoader.csproj
rename to Duplicati/Backend/BackendLoader/Duplicati.Backend.BackendLoader.csproj
index 9a746916a..16eeb5555 100644
--- a/Duplicati/Backend/BackendLoader/BackendLoader.csproj
+++ b/Duplicati/Backend/BackendLoader/Duplicati.Backend.BackendLoader.csproj
@@ -37,9 +37,9 @@
-
+
{994F3D0A-E91E-4EEE-80EE-064485E09909}
- BackendInterface
+ Duplicati.Backend.BackendInterface
diff --git a/Duplicati/Backend/DuplicatiBackend/DuplicatiBackend.csproj b/Duplicati/Backend/DuplicatiBackend/DuplicatiBackend.csproj
deleted file mode 100644
index 207c909f9..000000000
--- a/Duplicati/Backend/DuplicatiBackend/DuplicatiBackend.csproj
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
- Debug
- AnyCPU
- 8.0.50727
- 2.0
- {A0819A66-A2EF-48B1-BA69-14140C6C230E}
- Exe
- Properties
- Duplicati.Backend
- DuplicatiBackend
-
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
-
-
-
-
-
-
-
-
-
- {994F3D0A-E91E-4EEE-80EE-064485E09909}
- BackendInterface
-
-
- {0CA86ECF-5BEC-4909-B4F6-110A03B30B92}
- BackendLoader
-
-
- {FC9B7611-836F-4127-8B44-A7C31F506807}
- File
-
-
- {F61679A9-E5DE-468A-B5A4-05F92D0143D2}
- FTP
-
-
- {6BA21DCB-1701-4936-B177-3B6D4DE3474E}
- SSH
-
-
-
-
-
\ No newline at end of file
diff --git a/Duplicati/Backend/DuplicatiBackend/DuplicatiBackend.sln b/Duplicati/Backend/DuplicatiBackend/DuplicatiBackend.sln
deleted file mode 100644
index 0e7f05153..000000000
--- a/Duplicati/Backend/DuplicatiBackend/DuplicatiBackend.sln
+++ /dev/null
@@ -1,50 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 9.00
-# Visual Studio 2005
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DuplicatiBackend", "DuplicatiBackend.csproj", "{A0819A66-A2EF-48B1-BA69-14140C6C230E}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackendInterface", "..\BackendInterface\BackendInterface.csproj", "{994F3D0A-E91E-4EEE-80EE-064485E09909}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FTP", "..\FTP\FTP.csproj", "{F61679A9-E5DE-468A-B5A4-05F92D0143D2}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackendLoader", "..\BackendLoader\BackendLoader.csproj", "{0CA86ECF-5BEC-4909-B4F6-110A03B30B92}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SSH", "..\SSH\SSH.csproj", "{6BA21DCB-1701-4936-B177-3B6D4DE3474E}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "File", "..\File\File.csproj", "{FC9B7611-836F-4127-8B44-A7C31F506807}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {A0819A66-A2EF-48B1-BA69-14140C6C230E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A0819A66-A2EF-48B1-BA69-14140C6C230E}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A0819A66-A2EF-48B1-BA69-14140C6C230E}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A0819A66-A2EF-48B1-BA69-14140C6C230E}.Release|Any CPU.Build.0 = Release|Any CPU
- {994F3D0A-E91E-4EEE-80EE-064485E09909}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {994F3D0A-E91E-4EEE-80EE-064485E09909}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {994F3D0A-E91E-4EEE-80EE-064485E09909}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {994F3D0A-E91E-4EEE-80EE-064485E09909}.Release|Any CPU.Build.0 = Release|Any CPU
- {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Release|Any CPU.Build.0 = Release|Any CPU
- {0CA86ECF-5BEC-4909-B4F6-110A03B30B92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {0CA86ECF-5BEC-4909-B4F6-110A03B30B92}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {0CA86ECF-5BEC-4909-B4F6-110A03B30B92}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {0CA86ECF-5BEC-4909-B4F6-110A03B30B92}.Release|Any CPU.Build.0 = Release|Any CPU
- {6BA21DCB-1701-4936-B177-3B6D4DE3474E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {6BA21DCB-1701-4936-B177-3B6D4DE3474E}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {6BA21DCB-1701-4936-B177-3B6D4DE3474E}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {6BA21DCB-1701-4936-B177-3B6D4DE3474E}.Release|Any CPU.Build.0 = Release|Any CPU
- {FC9B7611-836F-4127-8B44-A7C31F506807}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {FC9B7611-836F-4127-8B44-A7C31F506807}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {FC9B7611-836F-4127-8B44-A7C31F506807}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {FC9B7611-836F-4127-8B44-A7C31F506807}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
diff --git a/Duplicati/Backend/DuplicatiBackend/Program.cs b/Duplicati/Backend/DuplicatiBackend/Program.cs
deleted file mode 100644
index 41d43e105..000000000
--- a/Duplicati/Backend/DuplicatiBackend/Program.cs
+++ /dev/null
@@ -1,186 +0,0 @@
-#region Disclaimer / License
-// Copyright (C) 2008, Kenneth Skovhede
-// http://www.hexad.dk, opensource@hexad.dk
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-//
-#endregion
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace Duplicati.Backend
-{
-
- class Program
- {
- const string HELPMESSAGE =
- "Invalid number of arguments.\r\n\r\n" +
- "Usage: DuplicatiBackend [options]\r\n\r\n" +
- "Operations:\r\n" +
- "\tHELP \t: Return this message\r\n" +
- "\tBACKENDS \t: List the avalible backends\r\n" +
- "\tLIST \t: Return a list of files at the given url\r\n" +
- "\tGET \t: Write the file at the given url to stdout\r\n" +
- "\tPUT \t: Write the contents of stdin to the given url\r\n" +
- "\tDELETE \t: Delete the file at the given url\r\n" +
- "\r\n\r\n" +
- "Options:\r\n" +
- "\t--file= \t: For GET, use filename rather than stdin\r\n" +
- " \t: For PUT, use filename rather than stdout\r\n" +
- " \t: For LIST, use filename rather than stdout\r\n";
-
- static int Main(string[] args)
- {
- List largs = new List(args);
-
- Dictionary options = ExtractOptions(largs);
-
- if (largs.Count < 1)
- {
- Console.WriteLine(HELPMESSAGE);
- return -1;
- }
-
- string operation = args[0].ToUpper();
- if (operation == "HELP")
- {
- Console.WriteLine(HELPMESSAGE);
- return 0;
- }
- else if (operation == "BACKENDS")
- {
- Console.WriteLine("Registered backends:\r\n");
- foreach (string b in BackendLoader.Backends)
- Console.WriteLine(b + "\t: " + BackendLoader.GetBackend(b).DisplayName);
-
- return 0;
- }
-
- if (largs.Count != 2)
- {
- Console.WriteLine(HELPMESSAGE);
- return -1;
- }
-
-
- string url = largs[1];
- IBackendInterface backend = null;
- try
- {
- backend = new BackendLoader(url);
- }
- catch (Exception ex)
- {
- Console.WriteLine(string.Format("Failed to load backend: {0}", ex.Message));
- return -1;
- }
-
- string file = options.ContainsKey("file") ? options["file"] : null;
-
- System.IO.Stream s = null;
-
- try
- {
- switch (operation.Trim().ToUpper())
- {
- case "LIST":
- if (file == null)
- s = Console.OpenStandardOutput();
- else
- s = new System.IO.FileStream(file, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None);
-
- using (System.IO.StreamWriter sw = new System.IO.StreamWriter(s))
- foreach (FileEntry fe in backend.List(url, options))
- sw.WriteLine(fe.Name);
-
- break;
- case "PUT":
- if (file == null)
- s = Console.OpenStandardInput();
- else
- s = new System.IO.FileStream(file, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read);
-
- backend.Put(url, options, s);
- break;
- case "GET":
- if (file == null)
- s = Console.OpenStandardOutput();
- else
- s = new System.IO.FileStream(file, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None);
- Utility.CopyStream(backend.Get(url, options), s, true);
- break;
- case "DELETE":
- backend.Delete(url, options);
- break;
-
- default:
- Console.WriteLine(HELPMESSAGE);
- return -1;
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine(string.Format("Failed: {0}", ex.Message));
- return -1;
- }
- finally
- {
- if (file != null && s != null)
- {
- try { s.Close(); }
- catch { }
-
- try { s.Dispose(); }
- catch { }
- }
-
- }
- return 0;
- }
-
- private static Dictionary ExtractOptions(List args)
- {
- Dictionary options = new Dictionary();
-
- for (int i = 0; i < args.Count; i++)
- {
- if (args[i].StartsWith("--"))
- {
- string key = null;
- string value = null;
- if (args[i].IndexOf("=") > 0)
- {
- key = args[i].Substring(0, args[i].IndexOf("="));
- value = args[i].Substring(args[i].IndexOf("=") + 1);
- }
- else
- key = args[i];
-
- //Skip the leading --
- key = key.Substring(2);
- if (!string.IsNullOrEmpty(value) && value.Length > 1 && value.StartsWith("\"") && value.EndsWith("\""))
- value = value.Substring(1, value.Length - 2);
- options[key] = value;
-
- i--;
- }
- }
-
- return options;
-
- }
- }
-}
diff --git a/Duplicati/Backend/DuplicatiBackend/Properties/AssemblyInfo.cs b/Duplicati/Backend/DuplicatiBackend/Properties/AssemblyInfo.cs
deleted file mode 100644
index a42134a46..000000000
--- a/Duplicati/Backend/DuplicatiBackend/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-#region Disclaimer / License
-// Copyright (C) 2008, Kenneth Skovhede
-// http://www.hexad.dk, opensource@hexad.dk
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-//
-#endregion
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("DuplicatiBackend")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("HexaD")]
-[assembly: AssemblyProduct("DuplicatiBackend")]
-[assembly: AssemblyCopyright("Copyright © HexaD 2008")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("3c3285d4-1f1c-4673-80fa-7b76bab4b909")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Duplicati/Backend/FTP/FTP.csproj b/Duplicati/Backend/FTP/Duplicati.Backend.FTP.csproj
similarity index 100%
rename from Duplicati/Backend/FTP/FTP.csproj
rename to Duplicati/Backend/FTP/Duplicati.Backend.FTP.csproj
diff --git a/Duplicati/Backend/File/File.csproj b/Duplicati/Backend/File/Duplicati.Backend.File.csproj
similarity index 91%
rename from Duplicati/Backend/File/File.csproj
rename to Duplicati/Backend/File/Duplicati.Backend.File.csproj
index f8f00b0e5..5cacbb04c 100644
--- a/Duplicati/Backend/File/File.csproj
+++ b/Duplicati/Backend/File/Duplicati.Backend.File.csproj
@@ -41,9 +41,9 @@
{DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}
Duplicati.Core
-
+
{994F3D0A-E91E-4EEE-80EE-064485E09909}
- BackendInterface
+ Duplicati.Backend.BackendInterface
diff --git a/Duplicati/Backend/SSH/SSH.csproj b/Duplicati/Backend/SSH/Dplicati.Backend.SSH.csproj
similarity index 100%
rename from Duplicati/Backend/SSH/SSH.csproj
rename to Duplicati/Backend/SSH/Dplicati.Backend.SSH.csproj
diff --git a/Duplicati/CommandLine/CommandLineParser.cs b/Duplicati/CommandLine/CommandLineParser.cs
index cd95de832..4f30a16b7 100644
--- a/Duplicati/CommandLine/CommandLineParser.cs
+++ b/Duplicati/CommandLine/CommandLineParser.cs
@@ -48,8 +48,8 @@ namespace Duplicati.CommandLine
if (!string.IsNullOrEmpty(value) && value.Length > 1 && value.StartsWith("\"") && value.EndsWith("\""))
value = value.Substring(1, value.Length - 2);
- //This is a bit ugly, but we want to preserve the order of "include" and "exclude"
- options.Add(key, value);
+ //Last argument overwrites the current
+ options[key] = value;
args.RemoveAt(i);
i--;
diff --git a/Duplicati/CommandLine/Duplicati.CommandLine.csproj b/Duplicati/CommandLine/Duplicati.CommandLine.csproj
index 0279420ae..d58210e88 100644
--- a/Duplicati/CommandLine/Duplicati.CommandLine.csproj
+++ b/Duplicati/CommandLine/Duplicati.CommandLine.csproj
@@ -39,9 +39,9 @@
-
+
{FC9B7611-836F-4127-8B44-A7C31F506807}
- File
+ Duplicati.Backend.File
{19ECCE09-B5EB-406C-8C57-BAC66997D469}
diff --git a/Duplicati/CommandLine/Program.cs b/Duplicati/CommandLine/Program.cs
index e7bc05303..1583dc794 100644
--- a/Duplicati/CommandLine/Program.cs
+++ b/Duplicati/CommandLine/Program.cs
@@ -39,15 +39,113 @@ namespace Duplicati.CommandLine
cargs.Add(Core.FilenameFilter.EncodeAsFilter(Core.FilenameFilter.ParseCommandLine(cargs, true)));
Dictionary options = CommandLineParser.ExtractOptions(cargs);
+ //TODO: Print usage window
+ if (cargs.Count < 2)
+ throw new Exception("Not enough parameters");
+
string source = cargs[0];
string target = cargs[1];
+ if (source.Trim().ToLower() == "restore" && cargs.Count == 3)
+ {
+ source = target;
+ target = cargs[2];
+ options["restore"] = null;
+ }
+
+ if (!options.ContainsKey("passphrase"))
+ if (!string.IsNullOrEmpty(System.Environment.GetEnvironmentVariable("PASSPHRASE")))
+ options["passphrase"] = System.Environment.GetEnvironmentVariable("PASSPHRASE");
+
if (source.Trim().ToLower() == "list")
Console.WriteLine(string.Join("\r\n", Duplicati.Main.Interface.List(target, options)));
- else if (source.IndexOf("://") > 0)
+ else if (source.IndexOf("://") > 0 || options.ContainsKey("restore"))
+ {
+ if (!options.ContainsKey("passphrase") && !options.ContainsKey("no-encryption"))
+ {
+ string pwd = ReadPassphraseFromConsole(false);
+ if (pwd == null)
+ return;
+ else
+ options["passphrase"] = pwd;
+ }
+
Duplicati.Main.Interface.Restore(source, target, options);
+ }
else
+ {
+ if (!options.ContainsKey("passphrase") && !options.ContainsKey("no-encryption"))
+ {
+ string pwd = ReadPassphraseFromConsole(true);
+ if (pwd == null)
+ return;
+ else
+ options["passphrase"] = pwd;
+ }
+
Duplicati.Main.Interface.Backup(source, target, options);
+ }
+ }
+
+ private static string ReadPassphraseFromConsole(bool confirm)
+ {
+ Console.Write("\nEnter passphrase: ");
+ StringBuilder password = new StringBuilder();
+
+ while (true)
+ {
+ ConsoleKeyInfo k = Console.ReadKey(true);
+ if (k.Key == ConsoleKey.Enter)
+ break;
+
+ if (k.Key == ConsoleKey.Escape)
+ return null;
+
+ password.Append(k.KeyChar);
+
+ //Unix/Linux user know that there is no feedback, Win user gets scared :)
+ if (System.Environment.OSVersion.Platform != PlatformID.Unix)
+ Console.Write("*");
+ }
+
+ Console.WriteLine();
+
+ if (confirm)
+ {
+ Console.Write("\nConfirm passphrase: ");
+ StringBuilder password2 = new StringBuilder();
+
+ while (true)
+ {
+ ConsoleKeyInfo k = Console.ReadKey(true);
+ if (k.Key == ConsoleKey.Enter)
+ break;
+
+ if (k.Key == ConsoleKey.Escape)
+ return null;
+
+ password2.Append(k.KeyChar);
+
+ //Unix/Linux user know that there is no feedback, Win user gets scared :)
+ if (System.Environment.OSVersion.Platform != PlatformID.Unix)
+ Console.Write("*");
+ }
+ Console.WriteLine();
+
+ if (password.ToString() != password2.ToString())
+ {
+ Console.WriteLine("The passwords do not match");
+ return null;
+ }
+ }
+
+ if (password.ToString().Length == 0)
+ {
+ Console.WriteLine("Empty passwords are not allowed");
+ return null;
+ }
+
+ return password.ToString();
}
}
}
diff --git a/Duplicati/CommandLine/UnitTest.cs b/Duplicati/CommandLine/UnitTest.cs
index a86f1d573..bb0a0199f 100644
--- a/Duplicati/CommandLine/UnitTest.cs
+++ b/Duplicati/CommandLine/UnitTest.cs
@@ -17,6 +17,9 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
#endregion
+
+#if DEBUG
+
using System;
using System.Collections.Generic;
using System.Text;
@@ -43,6 +46,8 @@ namespace Duplicati.CommandLine
{
Dictionary options = new Dictionary();
options["time-separator"] = "'";
+ options["passphrase"] = "secret password!";
+
Console.WriteLine("Backing up the full copy: " + folders[0]);
using (new Logging.Timer("Full backup of " + folders[0]))
Duplicati.Main.Interface.Backup(folders[0], "file://" + tf, options);
@@ -166,3 +171,5 @@ namespace Duplicati.CommandLine
}
}
}
+
+#endif
\ No newline at end of file
diff --git a/Duplicati/Core/FilenameFilter.cs b/Duplicati/Core/FilenameFilter.cs
index 9a65f12bd..7e1a519da 100644
--- a/Duplicati/Core/FilenameFilter.cs
+++ b/Duplicati/Core/FilenameFilter.cs
@@ -41,15 +41,18 @@ namespace Duplicati.Core
/// A parsed ordered set of filters
public static List> ParseCommandLine(List commandline, bool remove)
{
+ //TODO: Support the options --include-filelist, --include-globbin-filelist, --include-regexp-filelist
+ //and the exclude variants (all work on the lines in a file)
+
List> lst = new List>();
- Regex includeOrExclude = new Regex(@"(?(\-\-include\=)|(\-\-exclude\=)|(\-\-regexp\-include\=)|(\-\-regexp\-exclude\=))(?.+)", RegexOptions.IgnoreCase);
+ Regex includeOrExclude = new Regex(@"(?(\-\-include\=)|(\-\-exclude\=)|(\-\-include\-regexp\=)|(\-\-exclude\-regexp\=))(?.+)", RegexOptions.IgnoreCase);
for (int i = 0; i < commandline.Count; i++ )
{
string s = commandline[i];
Match m = includeOrExclude.Match(s.ToLower());
if (m.Success)
{
- bool include = m.Groups["prefix"].Value.ToLower() == "--include=" || m.Groups["prefix"].Value.ToLower() == "--regexp-include=";
+ bool include = m.Groups["prefix"].Value.ToLower() == "--include=" || m.Groups["prefix"].Value.ToLower() == "--include-regexp=";
string cmd = m.Groups["content"].Value;
if (!m.Groups["prefix"].Value.ToLower().StartsWith("--regexp"))
cmd = ConvertGlobbingToRegExp(cmd);
diff --git a/Duplicati/Core/Sizeparser.cs b/Duplicati/Core/Sizeparser.cs
index b232898f0..296dba57b 100644
--- a/Duplicati/Core/Sizeparser.cs
+++ b/Duplicati/Core/Sizeparser.cs
@@ -1,3 +1,22 @@
+#region Disclaimer / License
+// Copyright (C) 2008, Kenneth Skovhede
+// http://www.hexad.dk, opensource@hexad.dk
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+//
+#endregion
using System;
using System.Collections.Generic;
using System.Text;
diff --git a/Duplicati/Core/TempFile.cs b/Duplicati/Core/TempFile.cs
index a96ece0a7..cdbb82b12 100644
--- a/Duplicati/Core/TempFile.cs
+++ b/Duplicati/Core/TempFile.cs
@@ -31,7 +31,7 @@ namespace Duplicati.Core
private string m_path;
public TempFile()
- : this(System.IO.Path.GetTempFileName())
+ : this(System.IO.Path.Combine(TempFolder.SystemTempPath, System.IO.Path.GetRandomFileName()))
{
}
@@ -39,7 +39,8 @@ namespace Duplicati.Core
{
m_path = path;
if (!System.IO.File.Exists(m_path))
- System.IO.File.Create(m_path);
+ using (System.IO.File.Create(m_path))
+ { /*Dispose it immediately*/ }
}
public static implicit operator string(TempFile path)
diff --git a/Duplicati/Core/TempFolder.cs b/Duplicati/Core/TempFolder.cs
index ca877f6d2..968520909 100644
--- a/Duplicati/Core/TempFolder.cs
+++ b/Duplicati/Core/TempFolder.cs
@@ -31,7 +31,7 @@ namespace Duplicati.Core
private string m_folder;
public TempFolder()
- : this(System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName()))
+ : this(System.IO.Path.Combine(SystemTempPath, System.IO.Path.GetRandomFileName()))
{
}
@@ -67,5 +67,22 @@ namespace Duplicati.Core
}
#endregion
+
+ private static string m_system_temp_dir = null;
+
+ ///
+ /// Gets or sets the global temporary path used to store temporary files.
+ /// Set to null to use the system default.
+ ///
+ public static string SystemTempPath
+ {
+ get { return m_system_temp_dir == null ? System.IO.Path.GetTempPath() : m_system_temp_dir; }
+ set
+ {
+ if (!System.IO.Directory.Exists(value))
+ throw new Exception("Temporary folder does not exist: " + value);
+ m_system_temp_dir = value;
+ }
+ }
}
}
diff --git a/Duplicati/Encryption/AESEncryption.cs b/Duplicati/Encryption/AESEncryption.cs
index 0e993e057..74b95ef6a 100644
--- a/Duplicati/Encryption/AESEncryption.cs
+++ b/Duplicati/Encryption/AESEncryption.cs
@@ -1,3 +1,22 @@
+#region Disclaimer / License
+// Copyright (C) 2008, Kenneth Skovhede
+// http://www.hexad.dk, opensource@hexad.dk
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+//
+#endregion
using System;
using System.Collections.Generic;
using System.Text;
@@ -62,8 +81,11 @@ namespace Duplicati.Encryption
throw new Exception("Useless encryption detected");
System.Security.Cryptography.ICryptoTransform ct = m_instance.CreateEncryptor();
- using (System.Security.Cryptography.CryptoStream cs = new System.Security.Cryptography.CryptoStream(input, ct, System.Security.Cryptography.CryptoStreamMode.Write))
- Core.Utility.CopyStream(cs, output);
+ using (System.Security.Cryptography.CryptoStream cs = new System.Security.Cryptography.CryptoStream(output, ct, System.Security.Cryptography.CryptoStreamMode.Write))
+ {
+ Core.Utility.CopyStream(input, cs);
+ cs.FlushFinalBlock();
+ }
}
public override void Decrypt(System.IO.Stream input, System.IO.Stream output)
diff --git a/Duplicati/Encryption/Duplicati.Encryption.csproj b/Duplicati/Encryption/Duplicati.Encryption.csproj
index 3fee9ef5d..8e6b1d132 100644
--- a/Duplicati/Encryption/Duplicati.Encryption.csproj
+++ b/Duplicati/Encryption/Duplicati.Encryption.csproj
@@ -34,12 +34,21 @@
+
+
+ {994F3D0A-E91E-4EEE-80EE-064485E09909}
+ Duplicati.Backend.BackendInterface
+
+
+ {0CA86ECF-5BEC-4909-B4F6-110A03B30B92}
+ Duplicati.Backend.BackendLoader
+
{DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}
Duplicati.Core
diff --git a/Duplicati/Encryption/EncryptedBackendWrapper.cs b/Duplicati/Encryption/EncryptedBackendWrapper.cs
new file mode 100644
index 000000000..d8b8f6097
--- /dev/null
+++ b/Duplicati/Encryption/EncryptedBackendWrapper.cs
@@ -0,0 +1,105 @@
+#region Disclaimer / License
+// Copyright (C) 2008, Kenneth Skovhede
+// http://www.hexad.dk, opensource@hexad.dk
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+//
+#endregion
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Duplicati.Encryption
+{
+ ///
+ /// Class that wraps a backend and transparently encrypts and decrypts data to and from the backend
+ ///
+ public class EncryptedBackendWrapper : Backend.IBackendInterface
+ {
+ private Backend.IBackendInterface m_realbackend;
+ private IEncryption m_encryptionEngine;
+
+ public EncryptedBackendWrapper(string target, Dictionary options)
+ : this(Backend.BackendLoader.GetBackend(target, options), options)
+ {
+ }
+
+ public EncryptedBackendWrapper(Backend.IBackendInterface backend, Dictionary options)
+ {
+ if (!options.ContainsKey("passphrase") || string.IsNullOrEmpty(options["passphrase"]))
+ throw new Exception("No passphrase set");
+
+ string passphrase = options["passphrase"];
+
+ m_realbackend = backend;
+ if (options.ContainsKey("gpg-encryption"))
+ m_encryptionEngine = new GPGEncryption(passphrase, options.ContainsKey("sign-key") ? options["sign-key"] : null);
+ else
+ m_encryptionEngine = new AESEncryption(passphrase);
+ }
+
+ #region IBackendInterface Members
+
+ public string DisplayName
+ {
+ get { return m_realbackend.DisplayName; }
+ }
+
+ public string ProtocolKey
+ {
+ get { return m_realbackend.ProtocolKey; }
+ }
+
+ public List List()
+ {
+ return m_realbackend.List();
+ }
+
+ public void Put(string remotename, string filename)
+ {
+ remotename += (m_encryptionEngine is AESEncryption ? ".aes" : ".gpg");
+ using (Core.TempFile tf = new Duplicati.Core.TempFile())
+ {
+ m_encryptionEngine.Encrypt(filename, tf);
+ m_realbackend.Put(remotename, tf);
+ }
+ }
+
+ public void Get(string remotename, string filename)
+ {
+ using (Core.TempFile tf = new Duplicati.Core.TempFile())
+ {
+ m_realbackend.Get(remotename, tf);
+ m_encryptionEngine.Decrypt(tf, filename);
+ }
+ }
+
+ public void Delete(string remotename)
+ {
+ m_realbackend.Delete(remotename);
+ }
+
+ #endregion
+
+ public static Backend.IBackendInterface WrapWithEncryption(Backend.IBackendInterface backend, Dictionary options)
+ {
+ if (options.ContainsKey("no-encryption"))
+ return backend;
+ else
+ return new EncryptedBackendWrapper(backend, options);
+ }
+
+ }
+}
diff --git a/Duplicati/Encryption/EncryptionBase.cs b/Duplicati/Encryption/EncryptionBase.cs
index 70a11275a..71944a9a7 100644
--- a/Duplicati/Encryption/EncryptionBase.cs
+++ b/Duplicati/Encryption/EncryptionBase.cs
@@ -1,3 +1,22 @@
+#region Disclaimer / License
+// Copyright (C) 2008, Kenneth Skovhede
+// http://www.hexad.dk, opensource@hexad.dk
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+//
+#endregion
using System;
using System.Collections.Generic;
using System.Text;
diff --git a/Duplicati/Encryption/GPGEncryption.cs b/Duplicati/Encryption/GPGEncryption.cs
index 5fac85aed..a10aa8256 100644
--- a/Duplicati/Encryption/GPGEncryption.cs
+++ b/Duplicati/Encryption/GPGEncryption.cs
@@ -1,3 +1,22 @@
+#region Disclaimer / License
+// Copyright (C) 2008, Kenneth Skovhede
+// http://www.hexad.dk, opensource@hexad.dk
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+//
+#endregion
using System;
using System.Collections.Generic;
using System.Text;
diff --git a/Duplicati/Encryption/IEncryption.cs b/Duplicati/Encryption/IEncryption.cs
index 0ca5893a3..c438827e5 100644
--- a/Duplicati/Encryption/IEncryption.cs
+++ b/Duplicati/Encryption/IEncryption.cs
@@ -1,3 +1,22 @@
+#region Disclaimer / License
+// Copyright (C) 2008, Kenneth Skovhede
+// http://www.hexad.dk, opensource@hexad.dk
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+//
+#endregion
using System;
using System.Collections.Generic;
using System.Text;
diff --git a/Duplicati/Encryption/Properties/AssemblyInfo.cs b/Duplicati/Encryption/Properties/AssemblyInfo.cs
index d99f1bb9f..0b8710da8 100644
--- a/Duplicati/Encryption/Properties/AssemblyInfo.cs
+++ b/Duplicati/Encryption/Properties/AssemblyInfo.cs
@@ -1,4 +1,23 @@
-using System.Reflection;
+#region Disclaimer / License
+// Copyright (C) 2008, Kenneth Skovhede
+// http://www.hexad.dk, opensource@hexad.dk
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+//
+#endregion
+using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
diff --git a/Duplicati/Main/Duplicati.Main.csproj b/Duplicati/Main/Duplicati.Main.csproj
index 6d11324e9..c40417384 100644
--- a/Duplicati/Main/Duplicati.Main.csproj
+++ b/Duplicati/Main/Duplicati.Main.csproj
@@ -41,13 +41,13 @@
-
+
{994F3D0A-E91E-4EEE-80EE-064485E09909}
- BackendInterface
+ Duplicati.Backend.BackendInterface
-
+
{0CA86ECF-5BEC-4909-B4F6-110A03B30B92}
- BackendLoader
+ Duplicati.Backend.BackendLoader
{19ECCE09-B5EB-406C-8C57-BAC66997D469}
@@ -57,6 +57,10 @@
{DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}
Duplicati.Core
+
+ {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}
+ Duplicati.Encryption
+
{D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}
Duplicati.Logging
diff --git a/Duplicati/Main/FilenameStrategy.cs b/Duplicati/Main/FilenameStrategy.cs
index d359943a5..612cb45d5 100644
--- a/Duplicati/Main/FilenameStrategy.cs
+++ b/Duplicati/Main/FilenameStrategy.cs
@@ -33,6 +33,8 @@ namespace Duplicati.Main
private bool m_useShortFilenames;
private string m_timeSeperator;
+ private const long TICKS_PR_SECOND = 10000000;
+
public FilenameStrategy(Dictionary options)
{
//--short-filenames
@@ -68,34 +70,38 @@ namespace Duplicati.Main
}
else
{
- //TODO: Finish this
- byte[] tmp = new byte[4 + 2 + 2 + 2 + 2 + 2];
- return prefix + "-" + t + (full ? "F" : "I") + "";
+ return prefix + "-" + t + (full ? "F" : "I") + (time.Ticks / TICKS_PR_SECOND).ToString("X");
}
}
public BackupEntry DecodeFilename(string prefix, Duplicati.Backend.FileEntry fe)
{
- //TODO: Implement short filenames
+ string shortregexp = @"(?%filename%)\-(?(C|S|M)(?(F|I))(?