diff --git a/Duplicati/Library/Main/DatabaseLocator.cs b/Duplicati/Library/Main/DatabaseLocator.cs
index 124add6b4..d2b0c14d7 100644
--- a/Duplicati/Library/Main/DatabaseLocator.cs
+++ b/Duplicati/Library/Main/DatabaseLocator.cs
@@ -22,8 +22,6 @@
using System;
using System.Linq;
using System.Collections.Generic;
-using Newtonsoft.Json.Serialization;
-using Duplicati.Library.Common;
namespace Duplicati.Library.Main
{
@@ -38,10 +36,65 @@ namespace Duplicati.Library.Main
public string Username;
//public string Passwordhash;
public int Port;
- public string Databasepath;
+ public string Databasepath;
public string ParameterFile;
}
-
+
+ ///
+ /// The filename of the file with database configurations
+ ///
+ private const string CONFIG_FILE = "dbconfig.json";
+
+ ///
+ /// Finds a default storage folder, using the operating system specific locations.
+ /// The targetfilename is used to detect locations that are used in previous versions.
+ /// If the targetfilename is found in an old location, but not the current, the old location is used.
+ ///
+ /// The filename to look for
+ /// The name of the application
+ /// The default storage folder
+ public static string GetDefaultStorageFolder(string targetfilename, string appName = "Duplicati")
+ {
+ //Normal mode uses the systems "(Local) Application Data" folder
+ // %LOCALAPPDATA% on Windows, ~/.config on Linux
+ var folder = System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), appName);
+
+ if (OperatingSystem.IsWindows())
+ {
+ // Special handling for Windows:
+ // - Older versions use %APPDATA%
+ // - but new versions use %LOCALAPPDATA%
+ var newlocation = System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), appName);
+
+ var prevfile = System.IO.Path.Combine(folder, targetfilename);
+ var curfile = System.IO.Path.Combine(newlocation, targetfilename);
+
+ // If the new file exists, we use that
+ // If the new file does not exist, and the old file exists we use the old
+ // Otherwise we use the new location
+ if (System.IO.File.Exists(curfile) || !System.IO.File.Exists(prevfile))
+ folder = newlocation;
+ }
+
+ if (OperatingSystem.IsMacOS())
+ {
+ // Special handling for MacOS:
+ // - Older versions use ~/.config/
+ // - but new versions use ~/Library/Application\ Support/
+ var configfolder = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", appName);
+
+ var prevfile = System.IO.Path.Combine(configfolder, targetfilename);
+ var curfile = System.IO.Path.Combine(folder, targetfilename);
+
+ // If the old file exists, and not the new file, we use the old
+ // Otherwise we use the new location
+ if (!System.IO.File.Exists(curfile) && System.IO.File.Exists(prevfile))
+ folder = configfolder;
+ }
+
+ return folder;
+ }
+
public static string GetDatabasePath(string backend, Options options, bool autoCreate = true, bool anyUsername = false)
{
if (options == null)
@@ -50,40 +103,15 @@ namespace Duplicati.Library.Main
if (!string.IsNullOrEmpty(options.Dbpath))
return options.Dbpath;
- //Normal mode uses the systems "(Local) Application Data" folder
- // %LOCALAPPDATA% on Windows, ~/.config on Linux
+ var folder = GetDefaultStorageFolder(CONFIG_FILE);
- // Special handling for Windows:
- // - Older versions use %APPDATA%
- // - but new versions use %LOCALAPPDATA%
- //
- // If we find a new version, lets use that
- // otherwise use the older location
- //
-
- var folder = System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Duplicati");
-
- if (OperatingSystem.IsWindows())
- {
- var newlocation = System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Duplicati");
-
- var prevfile = System.IO.Path.Combine(folder, "dbconfig.json");
- var curfile = System.IO.Path.Combine(newlocation, "dbconfig.json");
-
- // If the new file exists, we use that
- // If the new file does not exist, and the old file exists we use the old
- // Otherwise we use the new location
- if (System.IO.File.Exists(curfile) || !System.IO.File.Exists(prevfile))
- folder = newlocation;
- }
-
- var file = System.IO.Path.Combine(folder, "dbconfig.json");
+ var file = System.IO.Path.Combine(folder, CONFIG_FILE);
List configs;
if (!System.IO.File.Exists(file))
configs = new List();
else
configs = Newtonsoft.Json.JsonConvert.DeserializeObject>(System.IO.File.ReadAllText(file, System.Text.Encoding.UTF8));
-
+
var uri = new Library.Utility.Uri(backend);
string server = uri.Host;
string path = uri.Path;
@@ -91,64 +119,64 @@ namespace Duplicati.Library.Main
int port = uri.Port;
string username = uri.Username;
string prefix = options.Prefix;
-
+
if (username == null || uri.Password == null)
{
var sopts = DynamicLoader.BackendLoader.GetSupportedCommands(backend);
var ropts = new Dictionary(options.RawOptions);
- foreach(var k in uri.QueryParameters.AllKeys)
+ foreach (var k in uri.QueryParameters.AllKeys)
ropts[k] = uri.QueryParameters[k];
-
+
if (sopts != null)
{
- foreach(var o in sopts)
+ foreach (var o in sopts)
{
if (username == null && o.Aliases != null && o.Aliases.Contains("auth-username", StringComparer.OrdinalIgnoreCase) && ropts.ContainsKey(o.Name))
username = ropts[o.Name];
}
-
- foreach(var o in sopts)
+
+ foreach (var o in sopts)
{
if (username == null && o.Name.Equals("auth-username", StringComparison.OrdinalIgnoreCase) && ropts.ContainsKey("auth-username"))
username = ropts["auth-username"];
}
}
}
-
+
//Now find the one that matches :)
var matches = (from n in configs
- where
- n.Type == type &&
- //n.Passwordhash == password &&
- n.Username == username &&
- n.Port == port &&
- n.Server == server &&
- n.Path == path &&
- n.Prefix == prefix
- select n).ToList();
-
+ where
+ n.Type == type &&
+ //n.Passwordhash == password &&
+ n.Username == username &&
+ n.Port == port &&
+ n.Server == server &&
+ n.Path == path &&
+ n.Prefix == prefix
+ select n).ToList();
+
if (matches.Count > 1)
throw new Duplicati.Library.Interface.UserInformationException(string.Format("Multiple sources found for: {0}", backend), "MultipleLocalDatabaseSourcesFound");
-
+
// Re-select
if (matches.Count == 0 && anyUsername && string.IsNullOrEmpty(username))
{
matches = (from n in configs
- where
- n.Type == type &&
- n.Port == port &&
- n.Server == server &&
- n.Path == path &&
- n.Prefix == prefix
- select n).ToList();
-
+ where
+ n.Type == type &&
+ n.Port == port &&
+ n.Server == server &&
+ n.Path == path &&
+ n.Prefix == prefix
+ select n).ToList();
+
if (matches.Count > 1)
throw new Duplicati.Library.Interface.UserInformationException(String.Format("Multiple sources found for \"{0}\", try supplying --{1}", backend, "auth-username"), "MultipleLocalDatabaseSourcesFound");
}
-
+
if (matches.Count == 0 && !autoCreate)
return null;
-
+
if (matches.Count == 0)
{
var backupname = options.BackupName;
@@ -156,20 +184,21 @@ namespace Duplicati.Library.Main
backupname = GenerateRandomName();
else
{
- foreach(var c in System.IO.Path.GetInvalidFileNameChars())
+ foreach (var c in System.IO.Path.GetInvalidFileNameChars())
backupname = backupname.Replace(c.ToString(), "");
}
-
+
var newpath = System.IO.Path.Combine(folder, backupname + ".sqlite");
int max_tries = 100;
while (System.IO.File.Exists(newpath) && max_tries-- > 0)
newpath = System.IO.Path.Combine(folder, GenerateRandomName());
-
+
if (System.IO.File.Exists(newpath))
throw new Duplicati.Library.Interface.UserInformationException("Unable to find a unique name for the database, please use --dbpath", "CannotCreateRandomName");
-
+
//Create a new one, add it to the list, and save it
- configs.Add(new BackendEntry() {
+ configs.Add(new BackendEntry()
+ {
Type = type,
Server = server,
Path = path,
@@ -177,7 +206,7 @@ namespace Duplicati.Library.Main
Username = username,
//Passwordhash = password,
Port = port,
- Databasepath = newpath,
+ Databasepath = newpath,
ParameterFile = null
});
@@ -187,16 +216,16 @@ namespace Duplicati.Library.Main
var settings = new Newtonsoft.Json.JsonSerializerSettings();
settings.Formatting = Newtonsoft.Json.Formatting.Indented;
System.IO.File.WriteAllText(file, Newtonsoft.Json.JsonConvert.SerializeObject(configs, settings), System.Text.Encoding.UTF8);
-
+
return newpath;
}
else
{
return matches[0].Databasepath;
}
-
+
}
-
+
public static string GenerateRandomName()
{
var rnd = new Random();
@@ -210,11 +239,7 @@ namespace Duplicati.Library.Main
public static bool IsDatabasePathInUse(string path)
{
- var folder = System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Duplicati");
- if (!System.IO.Directory.Exists(folder))
- return false;
-
- var file = System.IO.Path.Combine(folder, "dbconfig.json");
+ var file = System.IO.Path.Combine(GetDefaultStorageFolder(CONFIG_FILE), CONFIG_FILE);
if (!System.IO.File.Exists(file))
return false;
diff --git a/Duplicati/Server/Program.cs b/Duplicati/Server/Program.cs
index 1436cd48f..34904a14f 100644
--- a/Duplicati/Server/Program.cs
+++ b/Duplicati/Server/Program.cs
@@ -24,6 +24,7 @@ using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Duplicati.Library.Common.IO;
+using Duplicati.Library.Main;
using Duplicati.Library.Main.Database;
using Duplicati.Library.RestAPI;
using Duplicati.Server.Database;
@@ -622,50 +623,7 @@ namespace Duplicati.Server
{
//Normal release mode uses the systems "(Local) Application Data" folder
// %LOCALAPPDATA% on Windows, ~/.config on Linux, ~/Library/Application\ Support on MacOS
-
- serverDataFolder = System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Library.AutoUpdater.AutoUpdateSettings.AppName);
- if (OperatingSystem.IsWindows())
- {
- // Special handling for Windows:
- // - Older versions use %APPDATA%
- // - but new versions use %LOCALAPPDATA%
- //
- // If we find a new version, lets use that
- // otherwise use the older location
-
- var localappdata = System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), Library.AutoUpdater.AutoUpdateSettings.AppName);
-
- var prefile = System.IO.Path.Combine(serverDataFolder, SERVER_DATABASE_FILENAME);
- var curfile = System.IO.Path.Combine(localappdata, SERVER_DATABASE_FILENAME);
-
- // If the new file exists, we use that
- // If the new file does not exist, and the old file exists we use the old
- // Otherwise we use the new location
- if (System.IO.File.Exists(curfile) || !System.IO.File.Exists(prefile))
- serverDataFolder = localappdata;
- }
-
- if (OperatingSystem.IsMacOS())
- {
- // Special handling for MacOS:
- // - Older versions use ~/.config/
- // - but new versions use ~/Library/Application\ Support/
- //
- // If we find a new version, lets use that
- // otherwise use the older location
-
- var homefolder = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
- var configfolder = System.IO.Path.Combine(homefolder, ".config", Library.AutoUpdater.AutoUpdateSettings.AppName);
-
- var prevfile = System.IO.Path.Combine(configfolder, SERVER_DATABASE_FILENAME);
- var curfile = System.IO.Path.Combine(serverDataFolder, SERVER_DATABASE_FILENAME);
-
- // If the old file exists and the new does not, we switch back to the old location
- if (System.IO.File.Exists(prevfile) && !System.IO.File.Exists(curfile))
- serverDataFolder = configfolder;
- }
-
- DataFolder = serverDataFolder;
+ DataFolder = DatabaseLocator.GetDefaultStorageFolder(SERVER_DATABASE_FILENAME, Library.AutoUpdater.AutoUpdateSettings.AppName);
}
}
else