Merge branch 'warwickmm-fix_line_endings'
This commit is contained in:
+2
-37
@@ -55,6 +55,7 @@ jobs:
|
||||
- env: CATEGORY=Purge
|
||||
- env: CATEGORY=Serialization
|
||||
- env: CATEGORY=Utility
|
||||
- env: CATEGORY=UriUtility
|
||||
|
||||
- env: CATEGORY=GUI
|
||||
addons:
|
||||
@@ -66,40 +67,4 @@ before_install:
|
||||
- echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-
|
||||
|
||||
script:
|
||||
# build duplicati
|
||||
- ls -la "${TRAVIS_BUILD_DIR}"/packages/
|
||||
- echo "travis_fold:start:build_duplicati"
|
||||
- msbuild /p:Configuration=Release Duplicati.sln
|
||||
- echo "travis_fold:end:build_duplicati"
|
||||
- cp -r ./Duplicati/Server/webroot ./Duplicati/GUI/Duplicati.GUI.TrayIcon/bin/Release/webroot
|
||||
# download and extract testdata
|
||||
- echo "travis_fold:start:download_extract_testdata"
|
||||
- ls -la .
|
||||
- if [ ! -d ~/tmp ]; then mkdir ~/tmp; fi
|
||||
- if [ ! -d ~/download ]; then mkdir ~/download; fi
|
||||
- if [ ! -d ~/download/svn ]; then mkdir ~/download/svn; fi
|
||||
- if [ ! -d ~/download/bulk ]; then mkdir ~/download/bulk; fi
|
||||
- if [ ! -f ~/download/svn/DSMCBE.zip ] && ([ "$CATEGORY" == "SVNData" ] || [ "$CATEGORY" == "SVNDataLong" ]); then wget --progress=dot:giga "https://s3.amazonaws.com/duplicati-test-file-hosting/DSMCBE.zip" -O ~/download/svn/DSMCBE.zip; fi
|
||||
- if [ ! -f ~/download/bulk/data.zip ] && ([ "$CATEGORY" == "BulkNormal" ] || [ "$CATEGORY" == "BulkNoSize" ]); then wget --progress=dot:giga "https://s3.amazonaws.com/duplicati-test-file-hosting/data.zip" -O ~/download/bulk/data.zip; fi
|
||||
- ls -la .
|
||||
- mkdir ~/testdata
|
||||
- mkdir ~/testdata/data
|
||||
- mkdir ~/testdata/DSMCBE
|
||||
- if [ "$CATEGORY" == "SVNData" ] || [ "$CATEGORY" == "SVNDataLong" ]; then unzip -q ~/download/svn/DSMCBE.zip -d ~/testdata/; fi
|
||||
- if [ "$CATEGORY" == "BulkNormal" ] || [ "$CATEGORY" == "BulkNoSize" ]; then unzip -q ~/download/bulk/data.zip -d ~/testdata/; fi
|
||||
- chown -R travis ~/testdata/
|
||||
- chmod -R 755 ~/testdata
|
||||
- ls -la ~/testdata
|
||||
- ls -la ~/testdata/DSMCBE
|
||||
- ls -la ~/testdata/data
|
||||
- echo "travis_fold:end:download_extract_testdata"
|
||||
# run unit tests
|
||||
- echo "travis_fold:start:unit_test"
|
||||
- if [[ "$CATEGORY" != "GUI" ]]; then mono ./testrunner/NUnit.ConsoleRunner.3.5.0/tools/nunit3-console.exe ./Duplicati/UnitTest/bin/Release/Duplicati.UnitTest.dll --where:cat==$CATEGORY --workers=1; fi
|
||||
- echo "travis_fold:end:unit_test"
|
||||
# start server and run gui tests
|
||||
- echo "travis_fold:start:gui_unit_test"
|
||||
- mono ./Duplicati/GUI/Duplicati.GUI.TrayIcon/bin/Release/Duplicati.Server.exe &
|
||||
- if [[ "$CATEGORY" == "GUI" ]]; then python guiTests/guiTest.py; fi
|
||||
- echo "travis_fold:end:gui_unit_test"
|
||||
|
||||
- ./build.sh ${TRAVIS_BUILD_DIR} ${CATEGORY}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Duplicati.Library.Interface;
|
||||
|
||||
namespace Duplicati.CommandLine.BackendTool
|
||||
|
||||
@@ -27,12 +27,12 @@ namespace Duplicati.CommandLine
|
||||
private class PeriodicOutput : IDisposable
|
||||
{
|
||||
public event Action<float, long, long, bool> WriteOutput;
|
||||
|
||||
private System.Threading.ManualResetEvent m_readyEvent;
|
||||
private System.Threading.ManualResetEvent m_finishEvent;
|
||||
private ConsoleOutput m_output;
|
||||
|
||||
private readonly System.Threading.ManualResetEvent m_readyEvent;
|
||||
private readonly System.Threading.ManualResetEvent m_finishEvent;
|
||||
private readonly ConsoleOutput m_output;
|
||||
private System.Threading.Thread m_thread;
|
||||
private TimeSpan m_updateFrequency;
|
||||
private readonly TimeSpan m_updateFrequency;
|
||||
|
||||
public PeriodicOutput(ConsoleOutput messageSink, TimeSpan updateFrequency)
|
||||
{
|
||||
@@ -133,11 +133,7 @@ namespace Duplicati.CommandLine
|
||||
|
||||
public static int Help(TextWriter outwriter, Action<Duplicati.Library.Main.Controller> setup, List<string> args, Dictionary<string, string> options, Library.Utility.IFilter filter)
|
||||
{
|
||||
if (args.Count < 1)
|
||||
Duplicati.CommandLine.Help.PrintUsage(outwriter, "help", options);
|
||||
else
|
||||
Duplicati.CommandLine.Help.PrintUsage(outwriter, args[0], options);
|
||||
|
||||
Duplicati.CommandLine.Help.PrintUsage(outwriter, args.Count > 1? args[1] : "help", options);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -409,10 +409,10 @@ namespace Duplicati.CommandLine
|
||||
|
||||
string c = s;
|
||||
|
||||
string leadingSpaces = "";
|
||||
StringBuilder leadingSpaces = new StringBuilder();
|
||||
while (c.Length > 0 && c.StartsWith(" ", StringComparison.Ordinal))
|
||||
{
|
||||
leadingSpaces += " ";
|
||||
leadingSpaces.Append(" ");
|
||||
c = c.Remove(0, 1);
|
||||
}
|
||||
|
||||
@@ -434,7 +434,7 @@ namespace Duplicati.CommandLine
|
||||
if (extraIndent)
|
||||
{
|
||||
extraIndent = false;
|
||||
leadingSpaces += " ";
|
||||
leadingSpaces.Append(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -442,13 +442,15 @@ namespace Duplicati.CommandLine
|
||||
|
||||
private class Matcher
|
||||
{
|
||||
Dictionary<string, Library.Interface.ICommandLineArgument> args = new Dictionary<string, Library.Interface.ICommandLineArgument>(StringComparer.OrdinalIgnoreCase);
|
||||
readonly Dictionary<string, Library.Interface.ICommandLineArgument> args = new Dictionary<string, Library.Interface.ICommandLineArgument>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public Matcher()
|
||||
{
|
||||
List<IList<Library.Interface.ICommandLineArgument>> foundArgs = new List<IList<Library.Interface.ICommandLineArgument>>();
|
||||
foundArgs.Add(new Library.Main.Options(new Dictionary<string, string>()).SupportedCommands);
|
||||
foundArgs.Add(Program.SupportedOptions);
|
||||
List<IList<Library.Interface.ICommandLineArgument>> foundArgs = new List<IList<Library.Interface.ICommandLineArgument>>
|
||||
{
|
||||
new Library.Main.Options(new Dictionary<string, string>()).SupportedCommands,
|
||||
Program.SupportedOptions
|
||||
};
|
||||
|
||||
foreach (Duplicati.Library.Interface.IBackend backend in Library.DynamicLoader.BackendLoader.Backends)
|
||||
if (backend.SupportedCommands != null)
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Duplicati.CommandLine
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
private static string LOGTAG = Library.Logging.Log.LogTagFromType<Program>();
|
||||
private static readonly string LOGTAG = Library.Logging.Log.LogTagFromType<Program>();
|
||||
|
||||
public static bool FROM_COMMANDLINE = false;
|
||||
|
||||
@@ -163,34 +163,22 @@ namespace Duplicati.CommandLine
|
||||
}
|
||||
|
||||
// Probe for "help" to avoid extra processing
|
||||
bool isHelp = cargs.Count == 0 || (cargs.Count >= 1 && string.Equals(cargs[0], "help", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (isHelp)
|
||||
if (cargs.Count == 0 || (string.Equals(cargs[0], "help", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return Commands.Help(outwriter, setup, cargs, options, filter);
|
||||
}
|
||||
|
||||
if ((options.ContainsKey("parameters-file") && !string.IsNullOrEmpty("parameters-file")) || (options.ContainsKey("parameter-file") && !string.IsNullOrEmpty("parameter-file")) || (options.ContainsKey("parameterfile") && !string.IsNullOrEmpty("parameterfile")))
|
||||
// try and parse all parameter file aliases
|
||||
foreach (string parameterOption in new []{ "parameters-file", "parameters-file", "parameterfile"} )
|
||||
{
|
||||
string filename;
|
||||
if (options.ContainsKey("parameters-file") && !string.IsNullOrEmpty("parameters-file"))
|
||||
if (options.ContainsKey(parameterOption) && !string.IsNullOrEmpty(options[parameterOption]))
|
||||
{
|
||||
filename = options["parameters-file"];
|
||||
options.Remove("parameters-file");
|
||||
}
|
||||
else if (options.ContainsKey("parameter-file") && !string.IsNullOrEmpty("parameter-file"))
|
||||
{
|
||||
filename = options["parameter-file"];
|
||||
options.Remove("parameter-file");
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = options["parameterfile"];
|
||||
options.Remove("parameterfile");
|
||||
}
|
||||
|
||||
if (!ReadOptionsFromFile(outwriter, filename, ref filter, cargs, options))
|
||||
return 100;
|
||||
string filename = options[parameterOption];
|
||||
options.Remove(parameterOption);
|
||||
if (!ReadOptionsFromFile(outwriter, filename, ref filter, cargs, options))
|
||||
return 100;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!options.ContainsKey("passphrase"))
|
||||
@@ -204,7 +192,7 @@ namespace Duplicati.CommandLine
|
||||
if (!options.ContainsKey("auth-username"))
|
||||
if (!string.IsNullOrEmpty(System.Environment.GetEnvironmentVariable("AUTH_USERNAME")))
|
||||
options["auth-username"] = System.Environment.GetEnvironmentVariable("AUTH_USERNAME");
|
||||
|
||||
|
||||
var showDeletionErrors = verboseErrors;
|
||||
Duplicati.Library.Utility.TempFile.RemoveOldApplicationTempFiles((path, ex) =>
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2015, The Duplicati Team
|
||||
// Copyright (C) 2015, The Duplicati Team
|
||||
// http://www.duplicati.com, info@duplicati.com
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
|
||||
@@ -268,14 +268,14 @@ namespace Duplicati.CommandLine.RecoveryTool
|
||||
{
|
||||
private const int LOOKUP_TABLE_SIZE = 2048;
|
||||
|
||||
private CompressedFileMRUCache m_cache;
|
||||
private int m_hashsize;
|
||||
private int m_blocksize;
|
||||
private readonly CompressedFileMRUCache m_cache;
|
||||
private readonly int m_hashsize;
|
||||
private readonly int m_blocksize;
|
||||
private Stream m_indexfile;
|
||||
private List<string> m_lookup = new List<string>();
|
||||
private List<long> m_offsets = new List<long>();
|
||||
private byte[] m_linebuf = new byte[128];
|
||||
private byte[] m_newline = Environment.NewLine.Select(x => (byte)x).ToArray();
|
||||
private readonly List<string> m_lookup = new List<string>();
|
||||
private readonly List<long> m_offsets = new List<long>();
|
||||
private readonly byte[] m_linebuf = new byte[128];
|
||||
private readonly byte[] m_newline = Environment.NewLine.Select(x => (byte)x).ToArray();
|
||||
|
||||
public HashLookupHelper(string indexfile, CompressedFileMRUCache cache, int blocksize, int hashsize)
|
||||
{
|
||||
@@ -432,7 +432,7 @@ namespace Duplicati.CommandLine.RecoveryTool
|
||||
private Dictionary<string, Library.Interface.ICompression> m_lookup = new Dictionary<string, Duplicati.Library.Interface.ICompression>();
|
||||
private Dictionary<string, Stream> m_streams = new Dictionary<string, Stream>();
|
||||
private List<string> m_mru = new List<string>();
|
||||
private Dictionary<string, string> m_options;
|
||||
private readonly Dictionary<string, string> m_options;
|
||||
|
||||
private const int MAX_OPEN_ARCHIVES = 20;
|
||||
|
||||
|
||||
@@ -22,9 +22,9 @@ namespace Duplicati.CommandLine.Strings {
|
||||
public static string ParametersFileOptionShort { get { return LC.L(@"Path to a file with parameters"); } }
|
||||
public static string UnhandledException(string message) { return LC.L(@"An error occured: {0}", message); }
|
||||
public static string UnhandledInnerException(string message) { return LC.L(@"The inner error message is: {0}", message); }
|
||||
public static string IncludeLong { get { return LC.L(@"Include files that match this filter. The special character * means any number of character, and the special character ? means any single character, use *.txt to include all files with a txt extension. Regular expressions are also supported and can be supplied by using hard braces, i.e. [.*\.txt]. Filter groups (which encapsulate a built-in set of well-known files and folders) can be specified by using curly braces, i.e. {Applications}."); } }
|
||||
public static string IncludeLong { get { return LC.L(@"Include files that match this filter. The special character * means any number of character, and the special character ? means any single character, use *.txt to include all files with a txt extension. Regular expressions are also supported and can be supplied by using hard braces, i.e. [.*\.txt]. Filter groups (which encapsulate a built-in set of well-known files and folders) can be specified by using curly braces, i.e. {{Applications}}."); } }
|
||||
public static string IncludeShort { get { return LC.L(@"Include files"); } }
|
||||
public static string ExcludeLong { get { return LC.L(@"Exclude files that match this filter. The special character * means any number of character, and the special character ? means any single character, use *.txt to exclude all files with a txt extension. Regular expressions are also supported and can be supplied by using hard braces, i.e. [.*\.txt]. Filter groups (which encapsulate a built-in set of well-known files and folders) can be specified by using curly braces, i.e. {TemporaryFiles}."); } }
|
||||
public static string ExcludeLong { get { return LC.L(@"Exclude files that match this filter. The special character * means any number of character, and the special character ? means any single character, use *.txt to exclude all files with a txt extension. Regular expressions are also supported and can be supplied by using hard braces, i.e. [.*\.txt]. Filter groups (which encapsulate a built-in set of well-known files and folders) can be specified by using curly braces, i.e. {{TemporaryFiles}}."); } }
|
||||
public static string ExcludeShort { get { return LC.L(@"Exclude files"); } }
|
||||
public static string ControlFilesOptionShort { get { return LC.L(@"If this option is used with a backup operation, it is interpreted as a list of files to add to the filesets. When used with list or restore, it will list or restore the control files instead of the normal files."); } }
|
||||
public static string ControlFilesOptionLong { get { return LC.L(@"Use control files"); } }
|
||||
|
||||
@@ -292,8 +292,10 @@ Duplicati provides information for debugging and logging purposes. By default, a
|
||||
If something needs to be retried (e.g. upload failed) this will cause an entry in the log file.
|
||||
--log-file = <path>
|
||||
The path to the log file e.g. "D:\duplicati\log.txt".
|
||||
--log-level = Profiling | Information | Warning | Error
|
||||
Specifies the log level.
|
||||
--log-file-log-level = Profiling | Verbose | Information | Warning | Error
|
||||
Specifies the log level to use for the log file.
|
||||
--console-log-level = Profiling | Verbose | Information | Warning | Error
|
||||
Specifies the log level to use for the console log.
|
||||
|
||||
|
||||
# =============================================================================
|
||||
|
||||
@@ -28,8 +28,8 @@ namespace Duplicati.GUI.TrayIcon
|
||||
{
|
||||
private class MenuItemWrapper : Duplicati.GUI.TrayIcon.IMenuItem
|
||||
{
|
||||
private NSMenuItem m_item;
|
||||
private Action m_callback;
|
||||
private readonly NSMenuItem m_item;
|
||||
private readonly Action m_callback;
|
||||
|
||||
public NSMenuItem MenuItem { get { return m_item; } }
|
||||
|
||||
@@ -93,11 +93,11 @@ namespace Duplicati.GUI.TrayIcon
|
||||
private static readonly string ICON_ERROR = ICON_PATH + "normal-error.png";
|
||||
|
||||
private NSStatusItem m_statusItem;
|
||||
private Dictionary<Duplicati.GUI.TrayIcon.TrayIcons, NSImage> m_images = new Dictionary<Duplicati.GUI.TrayIcon.TrayIcons, NSImage>();
|
||||
private readonly Dictionary<Duplicati.GUI.TrayIcon.TrayIcons, NSImage> m_images = new Dictionary<Duplicati.GUI.TrayIcon.TrayIcons, NSImage>();
|
||||
private NSApplication m_app;
|
||||
|
||||
// We need to keep the items around, otherwise the GC will destroy them and crash the app
|
||||
private List<Duplicati.GUI.TrayIcon.IMenuItem> m_keeper = new List<Duplicati.GUI.TrayIcon.IMenuItem>();
|
||||
private readonly List<Duplicati.GUI.TrayIcon.IMenuItem> m_keeper = new List<Duplicati.GUI.TrayIcon.IMenuItem>();
|
||||
|
||||
public override void Init(string[] args)
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Duplicati.GUI.TrayIcon
|
||||
/// </summary>
|
||||
internal class HostedInstanceKeeper : IDisposable
|
||||
{
|
||||
private System.Threading.Thread m_runner;
|
||||
private readonly System.Threading.Thread m_runner;
|
||||
private System.Exception m_runnerException = null;
|
||||
public event Action InstanceShutdown;
|
||||
|
||||
|
||||
@@ -38,10 +38,10 @@ namespace Duplicati.GUI.TrayIcon
|
||||
}
|
||||
}
|
||||
|
||||
private string m_apiUri;
|
||||
private string m_baseUri;
|
||||
private readonly string m_apiUri;
|
||||
private readonly string m_baseUri;
|
||||
private string m_password;
|
||||
private bool m_saltedpassword;
|
||||
private readonly bool m_saltedpassword;
|
||||
private string m_authtoken;
|
||||
private string m_xsrftoken;
|
||||
private static readonly System.Text.Encoding ENCODING = System.Text.Encoding.GetEncoding("utf-8");
|
||||
@@ -59,7 +59,7 @@ namespace Duplicati.GUI.TrayIcon
|
||||
private volatile bool m_shutdown = false;
|
||||
private volatile System.Threading.Thread m_requestThread;
|
||||
private volatile System.Threading.Thread m_pollThread;
|
||||
private System.Threading.AutoResetEvent m_waitLock;
|
||||
private readonly System.Threading.AutoResetEvent m_waitLock;
|
||||
|
||||
private readonly Dictionary<string, string> m_updateRequest;
|
||||
private readonly Dictionary<string, string> m_options;
|
||||
@@ -69,7 +69,7 @@ namespace Duplicati.GUI.TrayIcon
|
||||
public IServerStatus Status { get { return m_status; } }
|
||||
|
||||
private readonly object m_lock = new object();
|
||||
private Queue<BackgroundRequest> m_workQueue = new Queue<BackgroundRequest>();
|
||||
private readonly Queue<BackgroundRequest> m_workQueue = new Queue<BackgroundRequest>();
|
||||
|
||||
public HttpServerConnection(Uri server, string password, bool saltedpassword, Program.PasswordSource passwordSource, Dictionary<string, string> options)
|
||||
{
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Duplicati.GUI.TrayIcon
|
||||
private class MenuItemWrapper : Duplicati.GUI.TrayIcon.IMenuItem
|
||||
{
|
||||
|
||||
private RumpsRunner m_parent;
|
||||
private readonly RumpsRunner m_parent;
|
||||
|
||||
private string m_text;
|
||||
private MenuIcons m_icon;
|
||||
@@ -115,7 +115,7 @@ namespace Duplicati.GUI.TrayIcon
|
||||
private static readonly string ICON_RUNNING = ICON_PATH + "normal-running.png";
|
||||
private static readonly string ICON_ERROR = ICON_PATH + "normal-error.png";
|
||||
|
||||
private Dictionary<Duplicati.GUI.TrayIcon.TrayIcons, string> m_images = new Dictionary<Duplicati.GUI.TrayIcon.TrayIcons, string>();
|
||||
private readonly Dictionary<Duplicati.GUI.TrayIcon.TrayIcons, string> m_images = new Dictionary<Duplicati.GUI.TrayIcon.TrayIcons, string>();
|
||||
|
||||
private System.Diagnostics.Process m_rumpsProcess;
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ namespace Duplicati.GUI.TrayIcon
|
||||
public virtual IBrowserWindow ShowUrlInWindow(string url)
|
||||
{
|
||||
//Fallback is to just show the window in a browser
|
||||
Duplicati.Library.Utility.UrlUtillity.OpenURL(url, Program.BrowserCommand);
|
||||
Duplicati.Library.Utility.UrlUtility.OpenURL(url, Program.BrowserCommand);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ namespace Duplicati.GUI.TrayIcon.Windows
|
||||
{
|
||||
private class MenuItemWrapper : IMenuItem
|
||||
{
|
||||
private ToolStripItem m_menu;
|
||||
private Action m_callback;
|
||||
private readonly ToolStripItem m_menu;
|
||||
private readonly Action m_callback;
|
||||
|
||||
public ToolStripItem MenuItem { get { return m_menu; } }
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Duplicati.Library.AutoUpdater
|
||||
/// <summary>
|
||||
/// The stream to read from
|
||||
/// </summary>
|
||||
private System.IO.Stream m_stream;
|
||||
private readonly System.IO.Stream m_stream;
|
||||
|
||||
protected SignatureReadingStream()
|
||||
{
|
||||
|
||||
@@ -616,7 +616,7 @@ namespace Duplicati.Library.AutoUpdater
|
||||
if (string.IsNullOrWhiteSpace(relpath))
|
||||
continue;
|
||||
|
||||
if (IgnoreWebrootFolder && relpath.StartsWith("webroot", Library.Utility.Utility.ClientFilenameStringComparision))
|
||||
if (IgnoreWebrootFolder && relpath.StartsWith("webroot", Library.Utility.Utility.ClientFilenameStringComparison))
|
||||
continue;
|
||||
|
||||
FileEntry fe;
|
||||
@@ -624,7 +624,7 @@ namespace Duplicati.Library.AutoUpdater
|
||||
{
|
||||
var ignore = false;
|
||||
foreach (var c in ignores)
|
||||
if (ignore = relpath.StartsWith(c, Library.Utility.Utility.ClientFilenameStringComparision))
|
||||
if (ignore = relpath.StartsWith(c, Library.Utility.Utility.ClientFilenameStringComparison))
|
||||
break;
|
||||
|
||||
if (ignore)
|
||||
@@ -654,7 +654,7 @@ namespace Duplicati.Library.AutoUpdater
|
||||
|
||||
var filteredpaths = paths
|
||||
.Where(p => !string.IsNullOrWhiteSpace(p.Key) && !p.Key.EndsWith("/", StringComparison.Ordinal))
|
||||
.Where(p => !IgnoreWebrootFolder || !p.Key.StartsWith("webroot", Library.Utility.Utility.ClientFilenameStringComparision))
|
||||
.Where(p => !IgnoreWebrootFolder || !p.Key.StartsWith("webroot", Library.Utility.Utility.ClientFilenameStringComparison))
|
||||
.Select(p => p.Key)
|
||||
.ToList();
|
||||
|
||||
|
||||
@@ -45,14 +45,14 @@ namespace Duplicati.Library.Backend.AmazonCloudDrive
|
||||
private EndpointInfo m_endPointInfo;
|
||||
private ResourceModel m_curdir;
|
||||
|
||||
private string m_path;
|
||||
private string[] m_labels;
|
||||
private readonly string m_path;
|
||||
private readonly string[] m_labels;
|
||||
|
||||
private OAuthHelper m_oauth;
|
||||
private readonly OAuthHelper m_oauth;
|
||||
private Dictionary<string, string> m_filecache;
|
||||
private string m_userid;
|
||||
private readonly string m_userid;
|
||||
private DateTime m_waitUntil;
|
||||
private TimeSpan m_delayTimeSpan;
|
||||
private readonly TimeSpan m_delayTimeSpan;
|
||||
|
||||
private enum RemoteOperation
|
||||
{
|
||||
|
||||
@@ -35,12 +35,12 @@ namespace Duplicati.Library.Backend.Backblaze
|
||||
|
||||
private const int DEFAULT_PAGE_SIZE = 500;
|
||||
|
||||
private string m_bucketname;
|
||||
private string m_prefix;
|
||||
private string m_urlencodedprefix;
|
||||
private string m_bucketType;
|
||||
private int m_pagesize;
|
||||
private B2AuthHelper m_helper;
|
||||
private readonly string m_bucketname;
|
||||
private readonly string m_prefix;
|
||||
private readonly string m_urlencodedprefix;
|
||||
private readonly string m_bucketType;
|
||||
private readonly int m_pagesize;
|
||||
private readonly B2AuthHelper m_helper;
|
||||
private UploadUrlResponse m_uploadUrl;
|
||||
|
||||
private Dictionary<string, List<FileEntity>> m_filecache;
|
||||
|
||||
@@ -35,9 +35,9 @@ namespace Duplicati.Library.Backend.Box
|
||||
|
||||
private const int PAGE_SIZE = 200;
|
||||
|
||||
private BoxHelper m_oauth;
|
||||
private string m_path;
|
||||
private bool m_deleteFromTrash;
|
||||
private readonly BoxHelper m_oauth;
|
||||
private readonly string m_path;
|
||||
private readonly bool m_deleteFromTrash;
|
||||
|
||||
private string m_currentfolder;
|
||||
private Dictionary<string, string> m_filecache;
|
||||
|
||||
@@ -39,13 +39,13 @@ namespace Duplicati.Library.Backend
|
||||
|
||||
|
||||
private const int ITEM_LIST_LIMIT = 1000;
|
||||
private string m_username;
|
||||
private string m_password;
|
||||
private string m_path;
|
||||
private readonly string m_username;
|
||||
private readonly string m_password;
|
||||
private readonly string m_path;
|
||||
|
||||
private string m_storageUrl = null;
|
||||
private string m_authToken = null;
|
||||
private string m_authUrl;
|
||||
private readonly string m_authUrl;
|
||||
|
||||
private readonly byte[] m_copybuffer = new byte[Duplicati.Library.Utility.Utility.DEFAULT_BUFFER_SIZE];
|
||||
|
||||
|
||||
@@ -10,8 +10,9 @@ namespace Duplicati.Library.Backend
|
||||
private const string AUTHID_OPTION = "authid";
|
||||
private const int MAX_FILE_LIST = 10000;
|
||||
|
||||
private string m_path,m_accesToken;
|
||||
private DropboxHelper dbx;
|
||||
private readonly string m_accesToken;
|
||||
private readonly string m_path;
|
||||
private readonly DropboxHelper dbx;
|
||||
|
||||
public Dropbox()
|
||||
{
|
||||
|
||||
@@ -32,12 +32,12 @@ namespace Duplicati.Library.Backend
|
||||
private const string OPTION_MOVE_FILE = "use-move-for-put";
|
||||
private const string OPTION_FORCE_REAUTH = "force-smb-authentication";
|
||||
|
||||
private string m_path;
|
||||
private readonly string m_path;
|
||||
private string m_username;
|
||||
private string m_password;
|
||||
private bool m_moveFile;
|
||||
private readonly bool m_moveFile;
|
||||
private bool m_hasAutenticated;
|
||||
private bool m_forceReauth;
|
||||
private readonly bool m_forceReauth;
|
||||
|
||||
private readonly byte[] m_copybuffer = new byte[Duplicati.Library.Utility.Utility.DEFAULT_BUFFER_SIZE];
|
||||
|
||||
|
||||
+1
@@ -41,6 +41,7 @@
|
||||
<Compile Include="GoogleCommon.cs" />
|
||||
<Compile Include="GoogleDrive.cs" />
|
||||
<Compile Include="GCSConfig.cs" />
|
||||
<Compile Include="WebApi.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
|
||||
@@ -14,15 +14,69 @@
|
||||
// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
using System;
|
||||
using System;
|
||||
using Duplicati.Library.Interface;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Duplicati.Library.Backend.GoogleServices
|
||||
{
|
||||
public class GCSConfig : IWebModule
|
||||
namespace Duplicati.Library.Backend.GoogleServices
|
||||
{
|
||||
private const ConfigType DEFAULT_CONFIG_TYPE = ConfigType.Locations;
|
||||
private static readonly string DEFAULT_CONFIG_TYPE_STR = Enum.GetName(typeof(ConfigType), DEFAULT_CONFIG_TYPE);
|
||||
private const string KEY_CONFIGTYPE = "gcs-config";
|
||||
|
||||
public enum ConfigType
|
||||
{
|
||||
Locations,
|
||||
StorageClasses
|
||||
}
|
||||
public GCSConfig()
|
||||
{
|
||||
}
|
||||
private const ConfigType DEFAULT_CONFIG_TYPE = ConfigType.Locations;
|
||||
|
||||
#region IWebModule implementation
|
||||
|
||||
public System.Collections.Generic.IDictionary<string, string> Execute(System.Collections.Generic.IDictionary<string, string> options)
|
||||
{
|
||||
string k;
|
||||
options.TryGetValue(KEY_CONFIGTYPE, out k);
|
||||
if (string.IsNullOrWhiteSpace(k))
|
||||
k = DEFAULT_CONFIG_TYPE_STR;
|
||||
|
||||
ConfigType ct;
|
||||
if (!Enum.TryParse<ConfigType>(k, true, out ct))
|
||||
ct = DEFAULT_CONFIG_TYPE;
|
||||
|
||||
switch (ct)
|
||||
{
|
||||
case ConfigType.StorageClasses:
|
||||
return GoogleCloudStorage.GoogleCloudStorage.KNOWN_GCS_STORAGE_CLASSES.ToDictionary((x) => x.Key, (y) => y.Value);
|
||||
default:
|
||||
return GoogleCloudStorage.GoogleCloudStorage.KNOWN_GCS_LOCATIONS.ToDictionary((x) => x.Key, (y) => y.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public string Key { get { return "gcs-getconfig"; } }
|
||||
|
||||
public string DisplayName { get { return "Google Cloud Storage configuration module"; } }
|
||||
|
||||
public string Description { get { return "Exposes Google Cloud Storage configuration as a web module"; } }
|
||||
|
||||
|
||||
public System.Collections.Generic.IList<ICommandLineArgument> SupportedCommands
|
||||
{
|
||||
get
|
||||
{
|
||||
return new List<ICommandLineArgument>(new ICommandLineArgument[] {
|
||||
new CommandLineArgument(KEY_CONFIGTYPE, CommandLineArgument.ArgumentType.Enumeration, "The config to get", "Provides different config values", DEFAULT_CONFIG_TYPE_STR, Enum.GetNames(typeof(ConfigType)))
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ using System;
|
||||
using Duplicati.Library.Interface;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Web;
|
||||
using Duplicati.Library.Utility;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text;
|
||||
@@ -62,13 +61,13 @@ namespace Duplicati.Library.Backend.GoogleCloudStorage
|
||||
new KeyValuePair<string, string>("Nearline", "NEARLINE"),
|
||||
};
|
||||
|
||||
private string m_bucket;
|
||||
private string m_prefix;
|
||||
private string m_project;
|
||||
private OAuthHelper m_oauth;
|
||||
private readonly string m_bucket;
|
||||
private readonly string m_prefix;
|
||||
private readonly string m_project;
|
||||
private readonly OAuthHelper m_oauth;
|
||||
|
||||
private string m_location;
|
||||
private string m_storage_class;
|
||||
private readonly string m_location;
|
||||
private readonly string m_storage_class;
|
||||
public GoogleCloudStorage()
|
||||
{
|
||||
}
|
||||
@@ -97,9 +96,9 @@ namespace Duplicati.Library.Backend.GoogleCloudStorage
|
||||
|
||||
m_oauth = new OAuthHelper(authid, this.ProtocolKey);
|
||||
m_oauth.AutoAuthHeader = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private class ListBucketResponse
|
||||
{
|
||||
public string kind { get; set; }
|
||||
@@ -205,7 +204,8 @@ namespace Duplicati.Library.Backend.GoogleCloudStorage
|
||||
if (string.IsNullOrEmpty(m_project))
|
||||
throw new UserInformationException(Strings.GoogleCloudStorage.ProjectIDMissingError(PROJECT_OPTION), "GoogleCloudStorageMissingProjectID");
|
||||
|
||||
var data = System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new CreateBucketRequest() {
|
||||
var data = System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new CreateBucketRequest
|
||||
{
|
||||
name = m_bucket,
|
||||
location = m_location,
|
||||
storageClass = m_storage_class
|
||||
@@ -220,7 +220,7 @@ namespace Duplicati.Library.Backend.GoogleCloudStorage
|
||||
|
||||
var areq = new AsyncHttpRequest(req);
|
||||
|
||||
using(var rs = areq.GetRequestStream())
|
||||
using (var rs = areq.GetRequestStream())
|
||||
rs.Write(data, 0, data.Length);
|
||||
|
||||
m_oauth.ReadJSONResponse<BucketResourceItem>(areq);
|
||||
@@ -246,8 +246,8 @@ namespace Duplicati.Library.Backend.GoogleCloudStorage
|
||||
foreach (KeyValuePair<string, string> s in KNOWN_GCS_LOCATIONS)
|
||||
locations.AppendLine(string.Format("{0}: {1}", s.Key, s.Value));
|
||||
foreach (KeyValuePair<string, string> s in KNOWN_GCS_STORAGE_CLASSES)
|
||||
storageClasses.AppendLine(string.Format("{0}: {1}", s.Key, s.Value));
|
||||
|
||||
storageClasses.AppendLine(string.Format("{0}: {1}", s.Key, s.Value));
|
||||
|
||||
return new List<ICommandLineArgument>(new ICommandLineArgument[] {
|
||||
new CommandLineArgument(LOCATION_OPTION, CommandLineArgument.ArgumentType.String, Strings.GoogleCloudStorage.LocationDescriptionShort, Strings.GoogleCloudStorage.LocationDescriptionLong(locations.ToString())),
|
||||
new CommandLineArgument(STORAGECLASS_OPTION, CommandLineArgument.ArgumentType.String, Strings.GoogleCloudStorage.StorageclassDescriptionShort, Strings.GoogleCloudStorage.StorageclassDescriptionLong(locations.ToString())),
|
||||
@@ -276,8 +276,8 @@ namespace Duplicati.Library.Backend.GoogleCloudStorage
|
||||
var res = GoogleCommon.ChunckedUploadWithResume<BucketResourceItem, BucketResourceItem>(m_oauth, item, url, stream);
|
||||
|
||||
if (res == null)
|
||||
throw new Exception(string.Format("Upload succeeded, but no data was returned"));
|
||||
|
||||
throw new Exception("Upload succeeded, but no data was returned");
|
||||
|
||||
}
|
||||
|
||||
public void Get(string remotename, System.IO.Stream stream)
|
||||
@@ -288,8 +288,8 @@ namespace Duplicati.Library.Backend.GoogleCloudStorage
|
||||
var req = m_oauth.CreateRequest(url);
|
||||
var areq = new AsyncHttpRequest(req);
|
||||
|
||||
using(var resp = areq.GetResponse())
|
||||
using(var rs = areq.GetResponseStream())
|
||||
using (var resp = areq.GetResponse())
|
||||
using (var rs = areq.GetResponseStream())
|
||||
Library.Utility.Utility.CopyStream(rs, stream);
|
||||
}
|
||||
catch (WebException wex)
|
||||
@@ -304,7 +304,8 @@ namespace Duplicati.Library.Backend.GoogleCloudStorage
|
||||
|
||||
public void Rename(string oldname, string newname)
|
||||
{
|
||||
var data = System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new BucketResourceItem() {
|
||||
var data = System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new BucketResourceItem
|
||||
{
|
||||
name = m_prefix + newname,
|
||||
}));
|
||||
|
||||
@@ -315,7 +316,7 @@ namespace Duplicati.Library.Backend.GoogleCloudStorage
|
||||
req.ContentType = "application/json; charset=UTF-8";
|
||||
|
||||
var areq = new AsyncHttpRequest(req);
|
||||
using(var rs = areq.GetRequestStream())
|
||||
using (var rs = areq.GetRequestStream())
|
||||
rs.Write(data, 0, data.Length);
|
||||
|
||||
m_oauth.ReadJSONResponse<BucketResourceItem>(req);
|
||||
@@ -323,8 +324,8 @@ namespace Duplicati.Library.Backend.GoogleCloudStorage
|
||||
|
||||
#region IDisposable implementation
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -15,14 +15,18 @@
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using Duplicati.Library.Backend.GoogleServices;
|
||||
using Duplicati.Library.Interface;
|
||||
using Duplicati.Library.Utility;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using Newtonsoft.Json;
|
||||
using Duplicati.Library.Backend.GoogleServices;
|
||||
|
||||
using System.Text;
|
||||
|
||||
namespace Duplicati.Library.Backend.GoogleDrive
|
||||
{
|
||||
public class GoogleDrive : IBackend, IStreamingBackend, IQuotaEnabledBackend, IRenameEnabledBackend
|
||||
@@ -31,15 +35,13 @@ namespace Duplicati.Library.Backend.GoogleDrive
|
||||
private const string DISABLE_TEAMDRIVE_OPTION = "googledrive-disable-teamdrive";
|
||||
|
||||
private const string FOLDER_MIMETYPE = "application/vnd.google-apps.folder";
|
||||
private const string DRIVE_API_UPLOAD_URL = "https://www.googleapis.com/upload/drive/v2";
|
||||
private const string DRIVE_API_URL = "https://www.googleapis.com/drive/v2";
|
||||
|
||||
private readonly string m_path;
|
||||
private readonly bool m_useTeamDrive = true;
|
||||
|
||||
private string m_path;
|
||||
private bool m_useTeamDrive = true;
|
||||
|
||||
private OAuthHelper m_oauth;
|
||||
private readonly OAuthHelper m_oauth;
|
||||
private string m_currentFolderId;
|
||||
private Dictionary<string, GoogleDriveFolderItem[]> m_filecache;
|
||||
private readonly Dictionary<string, GoogleDriveFolderItem[]> m_filecache;
|
||||
|
||||
public GoogleDrive()
|
||||
{
|
||||
@@ -66,26 +68,30 @@ namespace Duplicati.Library.Backend.GoogleDrive
|
||||
|
||||
private string GetFolderId(string path, bool autocreate = false)
|
||||
{
|
||||
var curparent = GetAboutInfo().rootFolderId;
|
||||
var curdisplay = "/";
|
||||
var curparent = GetAboutInfo().rootFolderId;
|
||||
var curdisplay = new StringBuilder("/");
|
||||
|
||||
foreach(var p in path.Split(new char[] {'/'}, StringSplitOptions.RemoveEmptyEntries))
|
||||
foreach (var p in path.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var res = ListFolder(curparent, true, p).ToArray();
|
||||
|
||||
if (res.Length == 0)
|
||||
{
|
||||
if (!autocreate)
|
||||
throw new FolderMissingException();
|
||||
|
||||
curparent = CreateFolder(p, curparent).id;
|
||||
}
|
||||
else if (res.Length > 1)
|
||||
throw new UserInformationException(Strings.GoogleDrive.MultipleEntries(p, curdisplay), "GoogleDriveMultipleEntries");
|
||||
else
|
||||
curparent = res[0].id;
|
||||
|
||||
curdisplay += p + "/";
|
||||
var res = ListFolder(curparent, true, p).ToArray();
|
||||
|
||||
if (res.Length == 0)
|
||||
{
|
||||
if (!autocreate)
|
||||
throw new FolderMissingException();
|
||||
|
||||
curparent = CreateFolder(p, curparent).id;
|
||||
}
|
||||
else if (res.Length > 1)
|
||||
{
|
||||
throw new UserInformationException(Strings.GoogleDrive.MultipleEntries(p, curdisplay.ToString()), "GoogleDriveMultipleEntries");
|
||||
}
|
||||
else
|
||||
{
|
||||
curparent = res[0].id;
|
||||
}
|
||||
|
||||
curdisplay.Append(p).Append("/");
|
||||
}
|
||||
|
||||
return curparent;
|
||||
@@ -110,17 +116,17 @@ namespace Duplicati.Library.Backend.GoogleDrive
|
||||
if (entries != null)
|
||||
return entries;
|
||||
|
||||
var list = ListFolder(CurrentFolderId, false, remotename).ToArray();
|
||||
entries = ListFolder(CurrentFolderId, false, remotename).ToArray();
|
||||
|
||||
if (list == null || list.Length == 0)
|
||||
if (entries == null || entries.Length == 0)
|
||||
{
|
||||
if (throwMissingException)
|
||||
throw new FileMissingException();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
return m_filecache[remotename] = list;
|
||||
|
||||
return m_filecache[remotename] = entries;
|
||||
}
|
||||
|
||||
private static string EscapeTitleEntries(string title)
|
||||
@@ -141,27 +147,32 @@ namespace Duplicati.Library.Backend.GoogleDrive
|
||||
GoogleDriveFolderItem[] files;
|
||||
m_filecache.TryGetValue(remotename, out files);
|
||||
|
||||
string fileid = null;
|
||||
string fileId = null;
|
||||
if (files != null)
|
||||
{
|
||||
if (files.Length == 1)
|
||||
fileid = files[0].id;
|
||||
fileId = files[0].id;
|
||||
else
|
||||
Delete(remotename);
|
||||
}
|
||||
|
||||
var isUpdate = !string.IsNullOrWhiteSpace(fileid);
|
||||
var isUpdate = !string.IsNullOrWhiteSpace(fileId);
|
||||
|
||||
var values = new NameValueCollection {
|
||||
{ WebApi.GoogleDrive.QueryParam.UploadType,
|
||||
WebApi.GoogleDrive.QueryValue.Resumable } };
|
||||
|
||||
var url = isUpdate ?
|
||||
string.Format("{0}/files/{1}?uploadType=resumable", DRIVE_API_UPLOAD_URL, Library.Utility.Uri.UrlPathEncode(fileid)) :
|
||||
string.Format("{0}/files?uploadType=resumable", DRIVE_API_UPLOAD_URL);
|
||||
WebApi.GoogleDrive.FileUploadUrl(Library.Utility.Uri.UrlPathEncode(fileId), values) :
|
||||
WebApi.GoogleDrive.FileUploadUrl(values);
|
||||
|
||||
var item = new GoogleDriveFolderItem() {
|
||||
var item = new GoogleDriveFolderItem
|
||||
{
|
||||
title = remotename,
|
||||
description = remotename,
|
||||
mimeType = "application/octet-stream",
|
||||
labels = new GoogleDriveFolderItemLabels { hidden = true },
|
||||
parents = new GoogleDriveParentReference[] { new GoogleDriveParentReference() { id = CurrentFolderId } }
|
||||
parents = new GoogleDriveParentReference[] { new GoogleDriveParentReference { id = CurrentFolderId } }
|
||||
};
|
||||
|
||||
var res = GoogleCommon.ChunckedUploadWithResume<GoogleDriveFolderItem, GoogleDriveFolderItem>(m_oauth, item, url, stream, isUpdate ? "PUT" : "POST");
|
||||
@@ -172,7 +183,6 @@ namespace Duplicati.Library.Backend.GoogleDrive
|
||||
m_filecache.Clear();
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Get(string remotename, System.IO.Stream stream)
|
||||
@@ -181,12 +191,15 @@ namespace Duplicati.Library.Backend.GoogleDrive
|
||||
if (m_filecache.Count == 0)
|
||||
foreach (var file in List()) { /* Enumerate the full listing */ }
|
||||
|
||||
var fileid = GetFileEntries(remotename).OrderByDescending(x => x.createdDate).First().id;
|
||||
var fileId = GetFileEntries(remotename).OrderByDescending(x => x.createdDate).First().id;
|
||||
|
||||
var req = m_oauth.CreateRequest(string.Format("{0}/files/{1}?alt=media{2}", DRIVE_API_URL, fileid, m_useTeamDrive ? "&supportsTeamDrives=true" : string.Empty));
|
||||
var url = WebApi.GoogleDrive.FileQueryUrl(fileId, new NameValueCollection{
|
||||
{ WebApi.GoogleDrive.QueryParam.Alt, WebApi.GoogleDrive.QueryValue.Media }
|
||||
});
|
||||
var req = m_oauth.CreateRequest(url);
|
||||
var areq = new AsyncHttpRequest(req);
|
||||
using(var resp = (HttpWebResponse)areq.GetResponse())
|
||||
using(var rs = areq.GetResponseStream())
|
||||
using (var resp = (HttpWebResponse)areq.GetResponse())
|
||||
using (var rs = areq.GetResponseStream())
|
||||
Duplicati.Library.Utility.Utility.CopyStream(rs, stream);
|
||||
}
|
||||
|
||||
@@ -247,7 +260,7 @@ namespace Duplicati.Library.Backend.GoogleDrive
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Put(string remotename, string filename)
|
||||
{
|
||||
using (System.IO.FileStream fs = System.IO.File.OpenRead(filename))
|
||||
@@ -264,11 +277,11 @@ namespace Duplicati.Library.Backend.GoogleDrive
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach(var fileid in from n in GetFileEntries(remotename) select n.id)
|
||||
foreach (var fileid in from n in GetFileEntries(remotename) select n.id)
|
||||
{
|
||||
var url = string.Format("{0}/files/{1}{2}", DRIVE_API_URL, Library.Utility.Uri.UrlPathEncode(fileid), m_useTeamDrive ? "?supportsTeamDrives=true" : string.Empty);
|
||||
|
||||
m_oauth.GetJSONData<object>(url, x => {
|
||||
var url = WebApi.GoogleDrive.FileQueryUrl(Library.Utility.Uri.UrlPathEncode(fileid), SupportsTeamDriveParam());
|
||||
m_oauth.GetJSONData<object>(url, x =>
|
||||
{
|
||||
x.Method = "DELETE";
|
||||
});
|
||||
}
|
||||
@@ -310,15 +323,16 @@ namespace Duplicati.Library.Backend.GoogleDrive
|
||||
}
|
||||
}
|
||||
|
||||
public System.Collections.Generic.IList<ICommandLineArgument> SupportedCommands
|
||||
{
|
||||
get {
|
||||
return new List<ICommandLineArgument>(new ICommandLineArgument[] {
|
||||
new CommandLineArgument(AUTHID_OPTION, CommandLineArgument.ArgumentType.Password, Strings.GoogleDrive.AuthidShort, Strings.GoogleDrive.AuthidLong(OAuthHelper.OAUTH_LOGIN_URL("googledrive"))),
|
||||
new CommandLineArgument(DISABLE_TEAMDRIVE_OPTION, CommandLineArgument.ArgumentType.Boolean, Strings.GoogleDrive.DisableTeamDriveShort, Strings.GoogleDrive.DisableTeamDriveLong),
|
||||
public System.Collections.Generic.IList<ICommandLineArgument> SupportedCommands => new List<ICommandLineArgument>(new ICommandLineArgument[] {
|
||||
new CommandLineArgument(AUTHID_OPTION,
|
||||
CommandLineArgument.ArgumentType.Password,
|
||||
Strings.GoogleDrive.AuthidShort,
|
||||
Strings.GoogleDrive.AuthidLong(OAuthHelper.OAUTH_LOGIN_URL("googledrive"))),
|
||||
new CommandLineArgument(DISABLE_TEAMDRIVE_OPTION,
|
||||
CommandLineArgument.ArgumentType.Boolean,
|
||||
Strings.GoogleDrive.DisableTeamDriveShort,
|
||||
Strings.GoogleDrive.DisableTeamDriveLong),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
@@ -348,8 +362,8 @@ namespace Duplicati.Library.Backend.GoogleDrive
|
||||
}
|
||||
|
||||
public string[] DNSName
|
||||
{
|
||||
get { return new string[] { new System.Uri(DRIVE_API_URL).Host, new System.Uri(DRIVE_API_UPLOAD_URL).Host }; }
|
||||
{
|
||||
get { return new string[] { new System.Uri(WebApi.GoogleDrive.Url.DRIVE).Host, new System.Uri(WebApi.GoogleDrive.Url.UPLOAD).Host }; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -365,21 +379,22 @@ namespace Duplicati.Library.Backend.GoogleDrive
|
||||
|
||||
var newfile = JsonConvert.DeserializeObject<GoogleDriveFolderItem>(JsonConvert.SerializeObject(files[0]));
|
||||
newfile.title = newname;
|
||||
newfile.parents = new GoogleDriveParentReference[] { new GoogleDriveParentReference() { id = CurrentFolderId } };
|
||||
newfile.parents = new GoogleDriveParentReference[] { new GoogleDriveParentReference { id = CurrentFolderId } };
|
||||
|
||||
var url = string.Format("{0}/files/{1}", DRIVE_API_UPLOAD_URL, Library.Utility.Uri.UrlPathEncode(files[0].id));
|
||||
var url = WebApi.GoogleDrive.FileQueryUrl(Library.Utility.Uri.UrlPathEncode(files[0].id));
|
||||
var data = System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(newfile));
|
||||
|
||||
var nf = m_oauth.GetJSONData<GoogleDriveFolderItem>(url, x => {
|
||||
var nf = m_oauth.GetJSONData<GoogleDriveFolderItem>(url, x =>
|
||||
{
|
||||
x.Method = "PUT";
|
||||
x.ContentLength = data.Length;
|
||||
x.ContentType = "application/json; charset=UTF-8";
|
||||
}, x => {
|
||||
|
||||
using(var rs = x.GetRequestStream())
|
||||
}, x =>
|
||||
{
|
||||
using (var rs = x.GetRequestStream())
|
||||
rs.Write(data, 0, data.Length);
|
||||
});
|
||||
|
||||
|
||||
m_filecache[newname] = new GoogleDriveFolderItem[] { nf };
|
||||
m_filecache.Remove(oldname);
|
||||
}
|
||||
@@ -397,9 +412,24 @@ namespace Duplicati.Library.Backend.GoogleDrive
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private NameValueCollection SupportsTeamDriveParam()
|
||||
{
|
||||
return m_useTeamDrive ? new NameValueCollection {
|
||||
{ WebApi.GoogleDrive.QueryParam.SupportsTeamDrive,
|
||||
WebApi.GoogleDrive.QueryValue.True }
|
||||
} : null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
private NameValueCollection IncludeTeamDriveParam()
|
||||
{
|
||||
return m_useTeamDrive ? new NameValueCollection {
|
||||
{ WebApi.GoogleDrive.QueryParam.IncludeTeamDrive,
|
||||
WebApi.GoogleDrive.QueryValue.True } } : null;
|
||||
}
|
||||
|
||||
private class GoogleDriveParentReference
|
||||
{
|
||||
@@ -470,40 +500,52 @@ namespace Duplicati.Library.Backend.GoogleDrive
|
||||
|
||||
private IEnumerable<GoogleDriveFolderItem> ListFolder(string parentfolder, bool? onlyFolders = null, string name = null)
|
||||
{
|
||||
var p = new string[] {
|
||||
var fileQuery = new string[] {
|
||||
string.IsNullOrEmpty(name) ? null : string.Format("title = '{0}'", EscapeTitleEntries(name)),
|
||||
onlyFolders == null ? null : string.Format("mimeType {0}= '{1}'", onlyFolders.Value ? "" : "!", FOLDER_MIMETYPE),
|
||||
string.Format("'{0}' in parents", EscapeTitleEntries(parentfolder))
|
||||
};
|
||||
|
||||
var url = string.Format("{0}/files?q={1}{2}", DRIVE_API_URL, Library.Utility.Uri.UrlEncode(string.Join(" and ", p.Where(x => x != null))), m_useTeamDrive ? "&supportsTeamDrives=true&includeTeamDriveItems=true" : string.Empty);
|
||||
var token = string.Empty;
|
||||
var queryParams = new NameValueCollection
|
||||
{
|
||||
{WebApi.GoogleDrive.QueryParam.File,
|
||||
Library.Utility.Uri.UrlEncode(string.Join(" and ", fileQuery.Where(x => x != null)))},
|
||||
};
|
||||
queryParams.Add(SupportsTeamDriveParam());
|
||||
queryParams.Add(IncludeTeamDriveParam());
|
||||
|
||||
do
|
||||
while (true)
|
||||
{
|
||||
var res = m_oauth.GetJSONData<GoogleDriveListResponse>(url + (string.IsNullOrWhiteSpace(token) ? "" : "&pageToken=" + Library.Utility.Uri.UrlEncode(token)));
|
||||
var url = WebApi.GoogleDrive.FileQueryUrl(queryParams);
|
||||
var res = m_oauth.GetJSONData<GoogleDriveListResponse>(url);
|
||||
foreach (var n in res.items)
|
||||
yield return n;
|
||||
|
||||
token = res.nextPageToken;
|
||||
} while (!string.IsNullOrWhiteSpace(token));
|
||||
var token = res.nextPageToken;
|
||||
if (string.IsNullOrWhiteSpace(token))
|
||||
break;
|
||||
|
||||
queryParams.Set(WebApi.GoogleDrive.QueryParam.PageToken, token);
|
||||
}
|
||||
}
|
||||
|
||||
private GoogleDriveAboutResponse GetAboutInfo()
|
||||
{
|
||||
var url = string.Format("{0}/about", DRIVE_API_URL);
|
||||
{
|
||||
var url = Library.Utility.Uri.UriBuilder(WebApi.GoogleDrive.Url.DRIVE, WebApi.GoogleDrive.Path.About);
|
||||
return m_oauth.GetJSONData<GoogleDriveAboutResponse>(url);
|
||||
}
|
||||
|
||||
private GoogleDriveFolderItem CreateFolder(string name, string parent)
|
||||
{
|
||||
var url = string.Format("{0}/files{1}", DRIVE_API_URL, m_useTeamDrive ? "?supportsTeamDrives=true" : string.Empty);
|
||||
var folder = new GoogleDriveFolderItem() {
|
||||
var url = WebApi.GoogleDrive.FileQueryUrl(SupportsTeamDriveParam());
|
||||
|
||||
var folder = new GoogleDriveFolderItem()
|
||||
{
|
||||
title = name,
|
||||
description = name,
|
||||
mimeType = FOLDER_MIMETYPE,
|
||||
labels = new GoogleDriveFolderItemLabels { hidden = true },
|
||||
parents = new GoogleDriveParentReference[] { new GoogleDriveParentReference() { id = parent } }
|
||||
parents = new GoogleDriveParentReference[] { new GoogleDriveParentReference { id = parent } }
|
||||
};
|
||||
|
||||
var data = System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(folder));
|
||||
@@ -514,13 +556,11 @@ namespace Duplicati.Library.Backend.GoogleDrive
|
||||
x.ContentType = "application/json; charset=UTF-8";
|
||||
x.ContentLength = data.Length;
|
||||
|
||||
}, req => {
|
||||
|
||||
using(var rs = req.GetRequestStream())
|
||||
}, req =>
|
||||
{
|
||||
using (var rs = req.GetRequestStream())
|
||||
rs.Write(data, 0, data.Length);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright (C) 2018, The Duplicati Team
|
||||
// http://www.duplicati.com, info@duplicati.com
|
||||
//
|
||||
// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace Duplicati.Library.Backend.WebApi
|
||||
{
|
||||
static class GoogleDrive
|
||||
{
|
||||
public static class Url
|
||||
{
|
||||
public const string DRIVE = "https://www.googleapis.com/drive/v2";
|
||||
public const string UPLOAD = "https://www.googleapis.com/upload/drive/v2";
|
||||
}
|
||||
|
||||
public static class Path
|
||||
{
|
||||
public const string File = "files";
|
||||
public const string About = "about";
|
||||
}
|
||||
|
||||
public static class QueryParam
|
||||
{
|
||||
public const string File = "q";
|
||||
public const string SupportsTeamDrive = "supportsTeamDrives";
|
||||
public const string IncludeTeamDrive = "includeTeamDriveItems";
|
||||
public const string PageToken = "pageToken";
|
||||
public const string UploadType = "uploadType";
|
||||
public const string Alt = "alt";
|
||||
}
|
||||
|
||||
public static class QueryValue
|
||||
{
|
||||
public const string True = "true";
|
||||
public const string Resumable = "resumable";
|
||||
public const string Media = "media";
|
||||
}
|
||||
|
||||
public static string FileQueryUrl(NameValueCollection values)
|
||||
{
|
||||
return Library.Utility.Uri.UriBuilder(Url.DRIVE, Path.File, values);
|
||||
}
|
||||
|
||||
public static string FileQueryUrl(string fileId, NameValueCollection values = null)
|
||||
{
|
||||
return Library.Utility.Uri.UriBuilder(Url.DRIVE, Library.Utility.Uri.ConcatPaths(Path.File, fileId), values);
|
||||
}
|
||||
|
||||
public static string FileUploadUrl(string fileId, NameValueCollection values)
|
||||
{
|
||||
return Library.Utility.Uri.UriBuilder(Url.UPLOAD, Library.Utility.Uri.ConcatPaths(Path.File, fileId), values);
|
||||
}
|
||||
|
||||
public static string FileUploadUrl(NameValueCollection values)
|
||||
{
|
||||
return Library.Utility.Uri.UriBuilder(Url.UPLOAD, Path.File, values);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ namespace Duplicati.Library.Backend.HubiC
|
||||
|
||||
private class OpenStackHelper : OpenStackStorage
|
||||
{
|
||||
private OAuthHelper m_helper;
|
||||
private readonly OAuthHelper m_helper;
|
||||
private HubiCAuthResponse m_token;
|
||||
|
||||
public OpenStackHelper(string authid, string url)
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace Duplicati.Library.Backend
|
||||
private readonly string m_url_device;
|
||||
private readonly string m_url;
|
||||
private readonly string m_url_upload;
|
||||
private System.Net.NetworkCredential m_userInfo;
|
||||
private readonly System.Net.NetworkCredential m_userInfo;
|
||||
private readonly byte[] m_copybuffer = new byte[Duplicati.Library.Utility.Utility.DEFAULT_BUFFER_SIZE];
|
||||
|
||||
public Jottacloud()
|
||||
|
||||
@@ -24,11 +24,11 @@ namespace Duplicati.Library.Backend.Mega
|
||||
{
|
||||
public class MegaBackend: IBackend, IStreamingBackend
|
||||
{
|
||||
private string m_username = null;
|
||||
private string m_password = null;
|
||||
private readonly string m_username = null;
|
||||
private readonly string m_password = null;
|
||||
private Dictionary<string, List<INode>> m_filecache;
|
||||
private INode m_currentFolder = null;
|
||||
private string m_prefix = null;
|
||||
private readonly string m_prefix = null;
|
||||
|
||||
private MegaApiClient m_client;
|
||||
|
||||
|
||||
@@ -140,9 +140,9 @@ namespace Duplicati.Library
|
||||
/// <returns>The deserialized JSON data.</returns>
|
||||
/// <param name="url">The remote URL</param>
|
||||
/// <param name="setup">A callback method that can be used to customize the request, e.g. by setting the method, content-type and headers.</param>
|
||||
/// <param name="setupreq">A callback method that can be used to submit data into the body of the request.</param>
|
||||
/// <param name="setupbodyreq">A callback method that can be used to submit data into the body of the request.</param>
|
||||
/// <typeparam name="T">The type of data to return.</typeparam>
|
||||
public virtual T GetJSONData<T>(string url, Action<HttpWebRequest> setup = null, Action<AsyncHttpRequest> setupreq = null)
|
||||
public virtual T GetJSONData<T>(string url, Action<HttpWebRequest> setup = null, Action<AsyncHttpRequest> setupbodyreq = null)
|
||||
{
|
||||
var req = CreateRequest(url);
|
||||
|
||||
@@ -151,8 +151,8 @@ namespace Duplicati.Library
|
||||
|
||||
var areq = new AsyncHttpRequest(req);
|
||||
|
||||
if (setupreq != null)
|
||||
setupreq(areq);
|
||||
if (setupbodyreq != null)
|
||||
setupbodyreq(areq);
|
||||
|
||||
return ReadJSONResponse<T>(areq);
|
||||
}
|
||||
|
||||
@@ -28,14 +28,14 @@ namespace Duplicati.Library.Backend
|
||||
|
||||
private static readonly string USER_AGENT = string.Format("Duplicati v{0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version);
|
||||
|
||||
private string m_rootfolder;
|
||||
private string m_prefix;
|
||||
private readonly string m_rootfolder;
|
||||
private readonly string m_prefix;
|
||||
private string m_userid;
|
||||
private WLID_FolderItem m_folderid;
|
||||
|
||||
private OAuthHelper m_oauth;
|
||||
private readonly OAuthHelper m_oauth;
|
||||
|
||||
private Dictionary<string, string> m_fileidCache = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
private readonly Dictionary<string, string> m_fileidCache = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private readonly byte[] m_copybuffer = new byte[Duplicati.Library.Utility.Utility.DEFAULT_BUFFER_SIZE];
|
||||
|
||||
|
||||
@@ -14,18 +14,65 @@
|
||||
// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
using System;
|
||||
using System;
|
||||
using Duplicati.Library.Interface;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Duplicati.Library.Backend.OpenStack
|
||||
{
|
||||
public class SwiftConfig : IWebModule
|
||||
namespace Duplicati.Library.Backend.OpenStack
|
||||
{
|
||||
{
|
||||
private const ConfigType DEFAULT_CONFIG_TYPE = ConfigType.Providers;
|
||||
private static readonly string DEFAULT_CONFIG_TYPE_STR = Enum.GetName(typeof(ConfigType), DEFAULT_CONFIG_TYPE);
|
||||
private const string KEY_CONFIGTYPE = "openstack-config";
|
||||
|
||||
public enum ConfigType
|
||||
{
|
||||
Providers,
|
||||
Versions,
|
||||
}
|
||||
public SwiftConfig()
|
||||
{
|
||||
private const ConfigType DEFAULT_CONFIG_TYPE = ConfigType.Providers;
|
||||
}
|
||||
|
||||
public System.Collections.Generic.IDictionary<string, string> Execute(System.Collections.Generic.IDictionary<string, string> options)
|
||||
{
|
||||
string k;
|
||||
options.TryGetValue(KEY_CONFIGTYPE, out k);
|
||||
if (string.IsNullOrWhiteSpace(k))
|
||||
k = DEFAULT_CONFIG_TYPE_STR;
|
||||
|
||||
ConfigType ct;
|
||||
if (!Enum.TryParse<ConfigType>(k, true, out ct))
|
||||
ct = DEFAULT_CONFIG_TYPE;
|
||||
|
||||
switch (ct)
|
||||
{
|
||||
case ConfigType.Versions:
|
||||
private const string KEY_CONFIGTYPE = "openstack-config";
|
||||
return OpenStack.OpenStackStorage.OPENSTACK_VERSIONS.ToDictionary((x) => x.Key, (y) => y.Value);
|
||||
default:
|
||||
return OpenStack.OpenStackStorage.KNOWN_OPENSTACK_PROVIDERS.ToDictionary((x) => x.Key, (y) => y.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public string Key { get { return "openstack-getconfig"; } }
|
||||
|
||||
public string DisplayName { get { return "OpenStack configuration module"; } }
|
||||
|
||||
public string Description { get { return "Exposes OpenStack configuration as a web module"; } }
|
||||
|
||||
|
||||
public System.Collections.Generic.IList<ICommandLineArgument> SupportedCommands
|
||||
{
|
||||
get
|
||||
{
|
||||
return new List<ICommandLineArgument>(new ICommandLineArgument[] {
|
||||
new CommandLineArgument(KEY_CONFIGTYPE, CommandLineArgument.ArgumentType.Enumeration, "The config to get", "Provides different config values", DEFAULT_CONFIG_TYPE_STR, Enum.GetNames(typeof(ConfigType)))
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ namespace Duplicati.Library.Backend.OpenStack
|
||||
new KeyValuePair<string, string>("Rackspace UK", "https://lon.identity.api.rackspacecloud.com/v2.0"),
|
||||
new KeyValuePair<string, string>("OVH Cloud Storage", "https://auth.cloud.ovh.net/v2.0"),
|
||||
new KeyValuePair<string, string>("Selectel Cloud Storage", "https://auth.selcdn.ru"),
|
||||
new KeyValuePair<string, string>("Memset Cloud Storage", "https://auth.storage.memset.com"),
|
||||
};
|
||||
|
||||
public static readonly KeyValuePair<string, string>[] OPENSTACK_VERSIONS = {
|
||||
|
||||
@@ -13,15 +13,33 @@
|
||||
//
|
||||
// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
using Duplicati.Library.Localization.Short;
|
||||
|
||||
namespace Duplicati.Library.Backend.Strings
|
||||
{
|
||||
namespace Duplicati.Library.Backend.Strings
|
||||
internal static class OpenStack {
|
||||
public static string Description { get { return LC.L(@"This backend can read and write data to Swift (OpenStack Object Storage). Supported format is ""openstack://container/folder""."); } }
|
||||
public static string DisplayName { get { return LC.L(@"OpenStack Simple Storage"); } }
|
||||
public static string MissingOptionError(string optionname) { return LC.L(@"Missing required option: {0}", optionname); }
|
||||
public static string PasswordOptionLong(string tenantnameoption) { return LC.L(@"The password used to connect to the server. This may also be supplied as the environment variable ""AUTH_PASSWORD"". If the password is supplied, --{0} must also be set", tenantnameoption); }
|
||||
public static string PasswordOptionShort { get { return LC.L(@"Supplies the password used to connect to the server"); } }
|
||||
public static string DomainnameOptionLong { get { return LC.L(@"The domain name of the user used to connect to the server."); } }
|
||||
public static string DomainnameOptionShort { get { return LC.L(@"Supplies the domain used to connect to the server"); } }
|
||||
public static string UsernameOptionLong { get { return LC.L(@"The username used to connect to the server. This may also be supplied as the environment variable ""AUTH_USERNAME""."); } }
|
||||
public static string UsernameOptionShort { get { return LC.L(@"Supplies the username used to connect to the server"); } }
|
||||
public static string DisplayName { get { return LC.L(@"OpenStack Simple Storage"); } }
|
||||
public static string TenantnameOptionLong { get { return LC.L(@"The Tenant Name is commonly the paying user account name. This option must be supplied when authenticating with a password, but is not required when using an API key."); } }
|
||||
public static string TenantnameOptionShort { get { return LC.L(@"Supplies the Tenant Name used to connect to the server"); } }
|
||||
public static string ApikeyOptionLong { get { return LC.L(@"The API key can be used to connect without supplying a password and tenant ID with some providers."); } }
|
||||
public static string ApikeyOptionShort { get { return LC.L(@"Supplies the API key used to connect to the server"); } }
|
||||
public static string AuthuriOptionLong(string providers) { return LC.L(@"The authentication URL is used to authenticate the user and find the storage service. The URL commonly ends with ""/v2.0"". Known providers are: {0}{1}", System.Environment.NewLine, providers); }
|
||||
public static string AuthuriOptionShort { get { return LC.L(@"Supplies the authentication URL"); } }
|
||||
public static string VersionOptionLong { get { return LC.L(@"The keystone API version to use, valid values are 'v2' and 'v3'."); } }
|
||||
public static string VersionOptionShort { get { return LC.L(@"The keystone API version to use"); } }
|
||||
public static string PasswordOptionLong(string tenantnameoption) { return LC.L(@"The password used to connect to the server. This may also be supplied as the environment variable ""AUTH_PASSWORD"". If the password is supplied, --{0} must also be set", tenantnameoption); }
|
||||
public static string RegionOptionLong { get { return LC.L(@"This option is only used when creating a container, and is used to indicate where the container should be placed. Consult your provider for a list of valid regions, or leave empty for the default region."); } }
|
||||
public static string RegionOptionShort { get { return LC.L(@"Supplies the region used for creating a container"); } }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,316 +1,319 @@
|
||||
#region Disclaimer / License
|
||||
// Copyright (C) 2015, The Duplicati Team
|
||||
// http://www.duplicati.com, info@duplicati.com
|
||||
//
|
||||
// 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.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
using Duplicati.Library.Interface;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
namespace Duplicati.Library.Backend
|
||||
{
|
||||
public class Rclone : IBackend
|
||||
{
|
||||
private const string OPTION_LOCAL_REPO = "rclone-local-repository";
|
||||
private const string OPTION_REMOTE_REPO = "rclone-remote-repository";
|
||||
private const string OPTION_REMOTE_PATH = "rclone-remote-path";
|
||||
private const string OPTION_RCLONE = "rclone-option";
|
||||
private const string OPTION_RCLONE_EXECUTABLE = "rclone-executable";
|
||||
private const string RCLONE_ERROR_DIRECTORY_NOT_FOUND = "directory not found";
|
||||
private const string RCLONE_ERROR_CONFIG_NOT_FOUND = "didn't find section in config file";
|
||||
|
||||
private string local_repo;
|
||||
private string remote_repo;
|
||||
private string remote_path;
|
||||
private string opt_rclone;
|
||||
private string rclone_executable;
|
||||
|
||||
public Rclone()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Rclone(string url, Dictionary<string, string> options)
|
||||
{
|
||||
var uri = new Utility.Uri(url);
|
||||
|
||||
remote_repo = uri.Host;
|
||||
remote_path = uri.Path;
|
||||
|
||||
|
||||
local_repo = "local";
|
||||
opt_rclone = "";
|
||||
rclone_executable = "rclone";
|
||||
/*should check here if program is installed */
|
||||
|
||||
if (options.ContainsKey(OPTION_LOCAL_REPO))
|
||||
local_repo = options[OPTION_LOCAL_REPO];
|
||||
if (options.ContainsKey(OPTION_REMOTE_REPO))
|
||||
remote_repo = options[OPTION_REMOTE_REPO];
|
||||
if (options.ContainsKey(OPTION_REMOTE_PATH))
|
||||
remote_path = options[OPTION_REMOTE_PATH];
|
||||
if (options.ContainsKey(OPTION_RCLONE))
|
||||
opt_rclone = options[OPTION_RCLONE];
|
||||
if (options.ContainsKey(OPTION_RCLONE_EXECUTABLE))
|
||||
rclone_executable = options[OPTION_RCLONE_EXECUTABLE];
|
||||
#if DEBUG
|
||||
Console.WriteLine(string.Format("Constructor {0}: {1}:{2} {3}", local_repo, remote_repo, remote_path, opt_rclone));
|
||||
#endif
|
||||
}
|
||||
|
||||
#region IBackendInterface Members
|
||||
|
||||
public string DisplayName
|
||||
{
|
||||
get { return Strings.Rclone.DisplayName; }
|
||||
}
|
||||
|
||||
public string ProtocolKey
|
||||
{
|
||||
get { return "rclone"; }
|
||||
}
|
||||
|
||||
public bool SupportsStreaming
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
private string RcloneCommandExecuter(String command, String arguments)
|
||||
{
|
||||
StringBuilder outputBuilder = new StringBuilder();
|
||||
StringBuilder errorBuilder = new StringBuilder();
|
||||
Process process;
|
||||
|
||||
ProcessStartInfo psi = new ProcessStartInfo
|
||||
{
|
||||
Arguments = String.Format("{0} {1}", arguments, opt_rclone),
|
||||
CreateNoWindow = true,
|
||||
FileName = command,
|
||||
RedirectStandardError = true,
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardOutput = true,
|
||||
UseShellExecute = false,
|
||||
WindowStyle = ProcessWindowStyle.Hidden
|
||||
};
|
||||
|
||||
#if DEBUG
|
||||
Console.Error.WriteLine(String.Format("command executing: {0} {1}", psi.FileName, psi.Arguments));
|
||||
#endif
|
||||
process = new Process
|
||||
{
|
||||
StartInfo = psi,
|
||||
// enable raising events because Process does not raise events by default
|
||||
EnableRaisingEvents = true
|
||||
};
|
||||
// attach the event handler for OutputDataReceived before starting the process
|
||||
process.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler
|
||||
(
|
||||
delegate (object sender, System.Diagnostics.DataReceivedEventArgs e)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(e.Data))
|
||||
{
|
||||
#if DEBUG
|
||||
// Console.Error.WriteLine(String.Format("output {0}", e.Data));
|
||||
#endif
|
||||
// append the new data to the data already read-in
|
||||
outputBuilder.Append(e.Data);
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
process.ErrorDataReceived += new System.Diagnostics.DataReceivedEventHandler
|
||||
(
|
||||
delegate (object sender, System.Diagnostics.DataReceivedEventArgs e)
|
||||
{
|
||||
|
||||
if (!String.IsNullOrEmpty(e.Data))
|
||||
{
|
||||
#if DEBUG
|
||||
Console.Error.WriteLine(String.Format("error {0}", e.Data));
|
||||
#endif
|
||||
errorBuilder.Append(e.Data);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// start the process
|
||||
// then begin asynchronously reading the output
|
||||
// then wait for the process to exit
|
||||
// then cancel asynchronously reading the output
|
||||
process.Start();
|
||||
process.BeginOutputReadLine();
|
||||
process.BeginErrorReadLine();
|
||||
process.WaitForExit();
|
||||
process.CancelOutputRead();
|
||||
process.CancelErrorRead();
|
||||
|
||||
if (errorBuilder.ToString().Contains(RCLONE_ERROR_DIRECTORY_NOT_FOUND))
|
||||
{
|
||||
throw new FolderMissingException(errorBuilder.ToString());
|
||||
}
|
||||
|
||||
if (errorBuilder.ToString().Contains(RCLONE_ERROR_CONFIG_NOT_FOUND))
|
||||
{
|
||||
throw new Exception(String.Format("Missing config file? {0}", errorBuilder.ToString()));
|
||||
}
|
||||
|
||||
if (errorBuilder.Length > 0) {
|
||||
throw new Exception(errorBuilder.ToString());
|
||||
}
|
||||
Console.Error.WriteLine(errorBuilder.ToString());
|
||||
return outputBuilder.ToString();
|
||||
}
|
||||
|
||||
|
||||
public IEnumerable<IFileEntry> List()
|
||||
{
|
||||
JArray files;
|
||||
String str_result;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
str_result = RcloneCommandExecuter(rclone_executable, String.Format("lsjson {0}:{1}", remote_repo, remote_path));
|
||||
// this will give an error if the executable does not exist.
|
||||
}
|
||||
|
||||
catch (FolderMissingException ex)
|
||||
{
|
||||
throw new FolderMissingException(ex);
|
||||
}
|
||||
|
||||
using (JsonReader jsonReader = new JsonTextReader(new StringReader(str_result)))
|
||||
{
|
||||
//no date parsing by JArray needed, will be parsed later
|
||||
jsonReader.DateParseHandling = DateParseHandling.None;
|
||||
var array = JArray.Load(jsonReader);
|
||||
|
||||
foreach (JObject item in array)
|
||||
{
|
||||
#if DEBUG
|
||||
Console.Error.WriteLine(item.ToString());
|
||||
#endif
|
||||
FileEntry fe = new FileEntry(
|
||||
item.GetValue("Name").Value<string>(),
|
||||
item.GetValue("Size").Value<long>(),
|
||||
DateTime.Parse(item.GetValue("ModTime").Value<string>()),
|
||||
DateTime.Parse(item.GetValue("ModTime").Value<string>())
|
||||
)
|
||||
{
|
||||
IsFolder = item.GetValue("IsDir").Value<bool>()
|
||||
};
|
||||
yield return fe;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Put(string remotename, string filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
RcloneCommandExecuter(rclone_executable, String.Format("copyto {0}:{1} {2}:{3}/{4}", local_repo, filename, remote_repo, remote_path, remotename));
|
||||
}
|
||||
catch (FolderMissingException ex)
|
||||
{
|
||||
throw new FileMissingException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void Get(string remotename, string filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
RcloneCommandExecuter(rclone_executable, String.Format("copyto {2}:{3}/{4} {0}:{1}", local_repo, filename, remote_repo, remote_path, remotename));
|
||||
}
|
||||
catch (FolderMissingException ex) {
|
||||
throw new FileMissingException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void Delete(string remotename)
|
||||
{
|
||||
//this will actually delete the folder if remotename is a folder...
|
||||
// Will give a "directory not found" error if the file does not exist, need to change that to a missing file exception
|
||||
try
|
||||
{
|
||||
RcloneCommandExecuter(rclone_executable, String.Format("delete {0}:{1}/{2}", remote_repo, remote_path, remotename));
|
||||
}
|
||||
catch (FolderMissingException ex) {
|
||||
throw new FileMissingException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public IList<ICommandLineArgument> SupportedCommands
|
||||
{
|
||||
get
|
||||
{
|
||||
return new List<ICommandLineArgument>(new ICommandLineArgument[] {
|
||||
new CommandLineArgument(OPTION_LOCAL_REPO, CommandLineArgument.ArgumentType.String, Strings.Rclone.RcloneLocalRepoShort, Strings.Rclone.RcloneLocalRepoLong, "local"),
|
||||
new CommandLineArgument(OPTION_REMOTE_REPO, CommandLineArgument.ArgumentType.String, Strings.Rclone.RcloneRemoteRepoShort, Strings.Rclone.RcloneRemoteRepoLong, "remote"),
|
||||
new CommandLineArgument(OPTION_REMOTE_PATH, CommandLineArgument.ArgumentType.String, Strings.Rclone.RcloneRemotePathShort, Strings.Rclone.RcloneRemotePathLong, "backup"),
|
||||
new CommandLineArgument(OPTION_RCLONE, CommandLineArgument.ArgumentType.String, Strings.Rclone.RcloneOptionRcloneShort, Strings.Rclone.RcloneOptionRcloneLong, ""),
|
||||
new CommandLineArgument(OPTION_RCLONE_EXECUTABLE, CommandLineArgument.ArgumentType.String, Strings.Rclone.RcloneExecutableShort, Strings.Rclone.RcloneExecutableLong, "rclone")
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return Strings.Rclone.Description;
|
||||
}
|
||||
#region Disclaimer / License
|
||||
// Copyright (C) 2015, The Duplicati Team
|
||||
// http://www.duplicati.com, info@duplicati.com
|
||||
//
|
||||
// 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.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
using Duplicati.Library.Interface;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
namespace Duplicati.Library.Backend
|
||||
{
|
||||
public class Rclone : IBackend
|
||||
{
|
||||
private const string OPTION_LOCAL_REPO = "rclone-local-repository";
|
||||
private const string OPTION_REMOTE_REPO = "rclone-remote-repository";
|
||||
private const string OPTION_REMOTE_PATH = "rclone-remote-path";
|
||||
private const string OPTION_RCLONE = "rclone-option";
|
||||
private const string OPTION_RCLONE_EXECUTABLE = "rclone-executable";
|
||||
private const string RCLONE_ERROR_DIRECTORY_NOT_FOUND = "directory not found";
|
||||
private const string RCLONE_ERROR_CONFIG_NOT_FOUND = "didn't find section in config file";
|
||||
|
||||
private readonly string local_repo;
|
||||
private readonly string remote_repo;
|
||||
private readonly string remote_path;
|
||||
private readonly string opt_rclone;
|
||||
private readonly string rclone_executable;
|
||||
|
||||
public Rclone()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string[] DNSName
|
||||
{
|
||||
get { return new string[] { remote_repo }; }
|
||||
public Rclone(string url, Dictionary<string, string> options)
|
||||
{
|
||||
var uri = new Utility.Uri(url);
|
||||
|
||||
remote_repo = uri.Host;
|
||||
remote_path = uri.Path;
|
||||
|
||||
|
||||
local_repo = "local";
|
||||
opt_rclone = "";
|
||||
rclone_executable = "rclone";
|
||||
/*should check here if program is installed */
|
||||
|
||||
if (options.ContainsKey(OPTION_LOCAL_REPO))
|
||||
local_repo = options[OPTION_LOCAL_REPO];
|
||||
if (options.ContainsKey(OPTION_REMOTE_REPO))
|
||||
remote_repo = options[OPTION_REMOTE_REPO];
|
||||
if (options.ContainsKey(OPTION_REMOTE_PATH))
|
||||
remote_path = options[OPTION_REMOTE_PATH];
|
||||
if (options.ContainsKey(OPTION_RCLONE))
|
||||
opt_rclone = options[OPTION_RCLONE];
|
||||
if (options.ContainsKey(OPTION_RCLONE_EXECUTABLE))
|
||||
rclone_executable = options[OPTION_RCLONE_EXECUTABLE];
|
||||
#if DEBUG
|
||||
Console.WriteLine(string.Format("Constructor {0}: {1}:{2} {3}", local_repo, remote_repo, remote_path, opt_rclone));
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Test()
|
||||
{
|
||||
this.TestList();
|
||||
}
|
||||
|
||||
public void CreateFolder()
|
||||
{
|
||||
RcloneCommandExecuter(rclone_executable, String.Format("mkdir {0}:{1}", remote_repo, remote_path));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#region IBackendInterface Members
|
||||
|
||||
public string DisplayName
|
||||
{
|
||||
get { return Strings.Rclone.DisplayName; }
|
||||
}
|
||||
|
||||
public string ProtocolKey
|
||||
{
|
||||
get { return "rclone"; }
|
||||
}
|
||||
|
||||
public bool SupportsStreaming
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
private string RcloneCommandExecuter(String command, String arguments)
|
||||
{
|
||||
StringBuilder outputBuilder = new StringBuilder();
|
||||
StringBuilder errorBuilder = new StringBuilder();
|
||||
Process process;
|
||||
|
||||
ProcessStartInfo psi = new ProcessStartInfo
|
||||
{
|
||||
Arguments = String.Format("{0} {1}", arguments, opt_rclone),
|
||||
CreateNoWindow = true,
|
||||
FileName = command,
|
||||
RedirectStandardError = true,
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardOutput = true,
|
||||
UseShellExecute = false,
|
||||
WindowStyle = ProcessWindowStyle.Hidden
|
||||
};
|
||||
|
||||
#if DEBUG
|
||||
Console.Error.WriteLine(String.Format("command executing: {0} {1}", psi.FileName, psi.Arguments));
|
||||
#endif
|
||||
process = new Process
|
||||
{
|
||||
StartInfo = psi,
|
||||
// enable raising events because Process does not raise events by default
|
||||
EnableRaisingEvents = true
|
||||
};
|
||||
// attach the event handler for OutputDataReceived before starting the process
|
||||
process.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler
|
||||
(
|
||||
delegate (object sender, System.Diagnostics.DataReceivedEventArgs e)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(e.Data))
|
||||
{
|
||||
#if DEBUG
|
||||
// Console.Error.WriteLine(String.Format("output {0}", e.Data));
|
||||
#endif
|
||||
// append the new data to the data already read-in
|
||||
outputBuilder.Append(e.Data);
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
process.ErrorDataReceived += new System.Diagnostics.DataReceivedEventHandler
|
||||
(
|
||||
delegate (object sender, System.Diagnostics.DataReceivedEventArgs e)
|
||||
{
|
||||
|
||||
if (!String.IsNullOrEmpty(e.Data))
|
||||
{
|
||||
#if DEBUG
|
||||
Console.Error.WriteLine(String.Format("error {0}", e.Data));
|
||||
#endif
|
||||
errorBuilder.Append(e.Data);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// start the process
|
||||
// then begin asynchronously reading the output
|
||||
// then wait for the process to exit
|
||||
// then cancel asynchronously reading the output
|
||||
process.Start();
|
||||
process.BeginOutputReadLine();
|
||||
process.BeginErrorReadLine();
|
||||
process.WaitForExit();
|
||||
process.CancelOutputRead();
|
||||
process.CancelErrorRead();
|
||||
|
||||
if (errorBuilder.ToString().Contains(RCLONE_ERROR_DIRECTORY_NOT_FOUND))
|
||||
{
|
||||
throw new FolderMissingException(errorBuilder.ToString());
|
||||
}
|
||||
|
||||
if (errorBuilder.ToString().Contains(RCLONE_ERROR_CONFIG_NOT_FOUND))
|
||||
{
|
||||
throw new Exception(String.Format("Missing config file? {0}", errorBuilder.ToString()));
|
||||
}
|
||||
|
||||
if (errorBuilder.Length > 0) {
|
||||
throw new Exception(errorBuilder.ToString());
|
||||
}
|
||||
Console.Error.WriteLine(errorBuilder.ToString());
|
||||
return outputBuilder.ToString();
|
||||
}
|
||||
|
||||
|
||||
public IEnumerable<IFileEntry> List()
|
||||
{
|
||||
String str_result;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
str_result = RcloneCommandExecuter(rclone_executable, String.Format("lsjson {0}:{1}", remote_repo, remote_path));
|
||||
// this will give an error if the executable does not exist.
|
||||
}
|
||||
|
||||
catch (FolderMissingException ex)
|
||||
{
|
||||
throw new FolderMissingException(ex);
|
||||
}
|
||||
|
||||
using (JsonReader jsonReader = new JsonTextReader(new StringReader(str_result)))
|
||||
{
|
||||
//no date parsing by JArray needed, will be parsed later
|
||||
jsonReader.DateParseHandling = DateParseHandling.None;
|
||||
var array = JArray.Load(jsonReader);
|
||||
|
||||
foreach (JObject item in array)
|
||||
{
|
||||
#if DEBUG
|
||||
Console.Error.WriteLine(item.ToString());
|
||||
#endif
|
||||
FileEntry fe = new FileEntry(
|
||||
item.GetValue("Name").Value<string>(),
|
||||
item.GetValue("Size").Value<long>(),
|
||||
DateTime.Parse(item.GetValue("ModTime").Value<string>()),
|
||||
DateTime.Parse(item.GetValue("ModTime").Value<string>())
|
||||
)
|
||||
{
|
||||
IsFolder = item.GetValue("IsDir").Value<bool>()
|
||||
};
|
||||
yield return fe;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Put(string remotename, string filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
RcloneCommandExecuter(rclone_executable, String.Format("copyto {0}:{1} {2}:{3}/{4}", local_repo, filename, remote_repo, remote_path, remotename));
|
||||
}
|
||||
catch (FolderMissingException ex)
|
||||
{
|
||||
throw new FileMissingException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void Get(string remotename, string filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
RcloneCommandExecuter(rclone_executable, String.Format("copyto {2}:{3}/{4} {0}:{1}", local_repo, filename, remote_repo, remote_path, remotename));
|
||||
}
|
||||
catch (FolderMissingException ex) {
|
||||
throw new FileMissingException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void Delete(string remotename)
|
||||
{
|
||||
//this will actually delete the folder if remotename is a folder...
|
||||
// Will give a "directory not found" error if the file does not exist, need to change that to a missing file exception
|
||||
try
|
||||
{
|
||||
RcloneCommandExecuter(rclone_executable, String.Format("delete {0}:{1}/{2}", remote_repo, remote_path, remotename));
|
||||
}
|
||||
catch (FolderMissingException ex) {
|
||||
throw new FileMissingException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public IList<ICommandLineArgument> SupportedCommands
|
||||
{
|
||||
get
|
||||
{
|
||||
return new List<ICommandLineArgument>(new ICommandLineArgument[] {
|
||||
new CommandLineArgument(OPTION_LOCAL_REPO, CommandLineArgument.ArgumentType.String, Strings.Rclone.RcloneLocalRepoShort, Strings.Rclone.RcloneLocalRepoLong, "local"),
|
||||
new CommandLineArgument(OPTION_REMOTE_REPO, CommandLineArgument.ArgumentType.String, Strings.Rclone.RcloneRemoteRepoShort, Strings.Rclone.RcloneRemoteRepoLong, "remote"),
|
||||
new CommandLineArgument(OPTION_REMOTE_PATH, CommandLineArgument.ArgumentType.String, Strings.Rclone.RcloneRemotePathShort, Strings.Rclone.RcloneRemotePathLong, "backup"),
|
||||
new CommandLineArgument(OPTION_RCLONE, CommandLineArgument.ArgumentType.String, Strings.Rclone.RcloneOptionRcloneShort, Strings.Rclone.RcloneOptionRcloneLong, ""),
|
||||
new CommandLineArgument(OPTION_RCLONE_EXECUTABLE, CommandLineArgument.ArgumentType.String, Strings.Rclone.RcloneExecutableShort, Strings.Rclone.RcloneExecutableLong, "rclone")
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return Strings.Rclone.Description;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public string[] DNSName
|
||||
{
|
||||
get { return new string[] { remote_repo }; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void Test()
|
||||
{
|
||||
this.TestList();
|
||||
}
|
||||
|
||||
public void CreateFolder()
|
||||
{
|
||||
RcloneCommandExecuter(rclone_executable, String.Format("mkdir {0}:{1}", remote_repo, remote_path));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,8 +126,8 @@ namespace Duplicati.Library.Backend
|
||||
}
|
||||
}
|
||||
|
||||
private string m_bucket;
|
||||
private string m_prefix;
|
||||
private readonly string m_bucket;
|
||||
private readonly string m_prefix;
|
||||
|
||||
public const string DEFAULT_S3_HOST = "s3.amazonaws.com";
|
||||
public const string S3_EU_REGION_NAME = "eu-west-1";
|
||||
|
||||
@@ -37,18 +37,18 @@ namespace Duplicati.Library.Backend
|
||||
public const string SSH_TIMEOUT_OPTION = "ssh-operation-timeout";
|
||||
public const string SSH_KEEPALIVE_OPTION = "ssh-keepalive";
|
||||
|
||||
Dictionary<string, string> m_options;
|
||||
readonly Dictionary<string, string> m_options;
|
||||
|
||||
private string m_server;
|
||||
private string m_path;
|
||||
private string m_username;
|
||||
private string m_password;
|
||||
private string m_fingerprint;
|
||||
private bool m_fingerprintallowall;
|
||||
private TimeSpan m_operationtimeout;
|
||||
private TimeSpan m_keepaliveinterval;
|
||||
private readonly string m_server;
|
||||
private readonly string m_path;
|
||||
private readonly string m_username;
|
||||
private readonly string m_password;
|
||||
private readonly string m_fingerprint;
|
||||
private readonly bool m_fingerprintallowall;
|
||||
private readonly TimeSpan m_operationtimeout;
|
||||
private readonly TimeSpan m_keepaliveinterval;
|
||||
|
||||
private int m_port = 22;
|
||||
private readonly int m_port = 22;
|
||||
|
||||
private SftpClient m_con;
|
||||
|
||||
|
||||
@@ -54,15 +54,15 @@ namespace Duplicati.Library.Backend
|
||||
#region [Variables and constants declarations]
|
||||
|
||||
/// <summary> Auth-stripped HTTPS-URI as passed to constructor. </summary>
|
||||
private Utility.Uri m_orgUrl;
|
||||
private readonly Utility.Uri m_orgUrl;
|
||||
/// <summary> Server relative path to backup folder. </summary>
|
||||
private string m_serverRelPath;
|
||||
private readonly string m_serverRelPath;
|
||||
/// <summary> User's credentials to create client context </summary>
|
||||
private System.Net.ICredentials m_userInfo;
|
||||
/// <summary> Flag indicating to move files to recycler on deletion. </summary>
|
||||
private bool m_deleteToRecycler = false;
|
||||
private readonly bool m_deleteToRecycler = false;
|
||||
/// <summary> Flag indicating to use UploadBinaryDirect. </summary>
|
||||
private bool m_useBinaryDirectMode = false;
|
||||
private readonly bool m_useBinaryDirectMode = false;
|
||||
|
||||
/// <summary> URL to SharePoint web. Will be determined from m_orgUri on first use. </summary>
|
||||
private string m_spWebUrl;
|
||||
@@ -70,10 +70,10 @@ namespace Duplicati.Library.Backend
|
||||
private SP.ClientContext m_spContext;
|
||||
|
||||
/// <summary> The chunk size for uploading files. </summary>
|
||||
private int m_fileChunkSize = 4 << 20; // Default: 4MB
|
||||
private readonly int m_fileChunkSize = 4 << 20; // Default: 4MB
|
||||
|
||||
/// <summary> The chunk size for uploading files. </summary>
|
||||
private int m_useContextTimeoutMs = -1; // default: do not touch original setting
|
||||
private readonly int m_useContextTimeoutMs = -1; // default: do not touch original setting
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -666,12 +666,14 @@ namespace Duplicati.Library.Backend
|
||||
string[] folderNames = m_serverRelPath.Substring(0, m_serverRelPath.Length - 1).Split('/');
|
||||
folderNames = Array.ConvertAll(folderNames, fold => System.Net.WebUtility.UrlDecode(fold));
|
||||
var spfolders = new SP.Folder[folderNames.Length];
|
||||
string folderRelPath = "";
|
||||
StringBuilder relativePathBuilder = new StringBuilder();
|
||||
int fi = 0;
|
||||
for (; fi < folderNames.Length; fi++)
|
||||
{
|
||||
folderRelPath += System.Web.HttpUtility.UrlPathEncode(folderNames[fi]) + "/";
|
||||
if (fi < pathLengthToWeb) continue;
|
||||
relativePathBuilder.Append(System.Web.HttpUtility.UrlPathEncode(folderNames[fi])).Append("/");
|
||||
if (fi < pathLengthToWeb) continue;
|
||||
|
||||
string folderRelPath = relativePathBuilder.ToString();
|
||||
var folder = ctx.Web.GetFolderByServerRelativeUrl(folderRelPath);
|
||||
spfolders[fi] = folder;
|
||||
ctx.Load(folder, f => f.Exists);
|
||||
|
||||
@@ -15,11 +15,11 @@ namespace Duplicati.Library.Backend.Sia
|
||||
private const string SIA_TARGETPATH = "sia-targetpath";
|
||||
private const string SIA_REDUNDANCY = "sia-redundancy";
|
||||
|
||||
private string m_apihost;
|
||||
private int m_apiport;
|
||||
private string m_targetpath;
|
||||
private float m_redundancy;
|
||||
private System.Net.NetworkCredential m_user;
|
||||
private readonly string m_apihost;
|
||||
private readonly int m_apiport;
|
||||
private readonly string m_targetpath;
|
||||
private readonly float m_redundancy;
|
||||
private readonly System.Net.NetworkCredential m_user;
|
||||
|
||||
public Sia() {
|
||||
|
||||
|
||||
@@ -29,8 +29,8 @@ namespace Duplicati.Library.Backend
|
||||
{
|
||||
public class TahoeBackend : IBackend, IStreamingBackend
|
||||
{
|
||||
private string m_url;
|
||||
private bool m_useSSL = false;
|
||||
private readonly string m_url;
|
||||
private readonly bool m_useSSL = false;
|
||||
private readonly byte[] m_copybuffer = new byte[Duplicati.Library.Utility.Utility.DEFAULT_BUFFER_SIZE];
|
||||
|
||||
private class TahoeEl
|
||||
|
||||
@@ -26,18 +26,18 @@ namespace Duplicati.Library.Backend
|
||||
{
|
||||
public class WEBDAV : IBackend, IStreamingBackend
|
||||
{
|
||||
private System.Net.NetworkCredential m_userInfo;
|
||||
private string m_url;
|
||||
private string m_path;
|
||||
private string m_sanitizedUrl;
|
||||
private string m_reverseProtocolUrl;
|
||||
private string m_rawurl;
|
||||
private string m_rawurlPort;
|
||||
private string m_dnsName;
|
||||
private bool m_useIntegratedAuthentication = false;
|
||||
private bool m_forceDigestAuthentication = false;
|
||||
private bool m_useSSL = false;
|
||||
private string m_debugPropfindFile = null;
|
||||
private readonly System.Net.NetworkCredential m_userInfo;
|
||||
private readonly string m_url;
|
||||
private readonly string m_path;
|
||||
private readonly string m_sanitizedUrl;
|
||||
private readonly string m_reverseProtocolUrl;
|
||||
private readonly string m_rawurl;
|
||||
private readonly string m_rawurlPort;
|
||||
private readonly string m_dnsName;
|
||||
private readonly bool m_useIntegratedAuthentication = false;
|
||||
private readonly bool m_forceDigestAuthentication = false;
|
||||
private readonly bool m_useSSL = false;
|
||||
private readonly string m_debugPropfindFile = null;
|
||||
private readonly byte[] m_copybuffer = new byte[Duplicati.Library.Utility.Utility.DEFAULT_BUFFER_SIZE];
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace Duplicati.Library.Compression
|
||||
/// <summary>
|
||||
/// This property indicates reading or writing access mode of the file archive.
|
||||
/// </summary>
|
||||
ArchiveMode m_mode;
|
||||
readonly ArchiveMode m_mode;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of bytes expected to be written after the stream is disposed
|
||||
@@ -126,17 +126,17 @@ namespace Duplicati.Library.Compression
|
||||
/// <summary>
|
||||
/// The compression level applied when the hint does not indicate incompressible
|
||||
/// </summary>
|
||||
private SharpCompress.Compressors.Deflate.CompressionLevel m_defaultCompressionLevel;
|
||||
private readonly SharpCompress.Compressors.Deflate.CompressionLevel m_defaultCompressionLevel;
|
||||
|
||||
/// <summary>
|
||||
/// The compression level applied when the hint does not indicate incompressible
|
||||
/// </summary>
|
||||
private CompressionType m_compressionType;
|
||||
private readonly CompressionType m_compressionType;
|
||||
|
||||
/// <summary>
|
||||
/// A flag indicating if zip64 is in use
|
||||
/// </summary>
|
||||
private bool m_usingZip64;
|
||||
private readonly bool m_usingZip64;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor, used to read file extension and supported commands
|
||||
@@ -306,9 +306,9 @@ namespace Duplicati.Library.Compression
|
||||
var q = m_entryDict.Values.AsEnumerable();
|
||||
if (!string.IsNullOrEmpty(prefix))
|
||||
q = q.Where(x =>
|
||||
x.Key.StartsWith(prefix, Duplicati.Library.Utility.Utility.ClientFilenameStringComparision)
|
||||
x.Key.StartsWith(prefix, Duplicati.Library.Utility.Utility.ClientFilenameStringComparison)
|
||||
||
|
||||
x.Key.Replace('\\', '/').StartsWith(prefix, Duplicati.Library.Utility.Utility.ClientFilenameStringComparision)
|
||||
x.Key.Replace('\\', '/').StartsWith(prefix, Duplicati.Library.Utility.Utility.ClientFilenameStringComparison)
|
||||
);
|
||||
|
||||
return q.Select(x => new KeyValuePair<string, long>(x.Key, x.Size)).ToArray();
|
||||
|
||||
@@ -174,7 +174,7 @@ namespace Duplicati.Library.Compression
|
||||
if (m_reader == null)
|
||||
throw new InvalidOperationException(Strings.SevenZipCompression.NoReaderError);
|
||||
|
||||
StringComparison sc = Library.Utility.Utility.ClientFilenameStringComparision;
|
||||
StringComparison sc = Library.Utility.Utility.ClientFilenameStringComparison;
|
||||
|
||||
return
|
||||
from n in m_reader.GetFiles(m_archive)
|
||||
@@ -222,8 +222,8 @@ namespace Duplicati.Library.Compression
|
||||
|
||||
private sealed class WriterEntry : ManagedLzma.LZMA.Master.SevenZip.IArchiveWriterEntry
|
||||
{
|
||||
private string mName;
|
||||
private DateTime? mTimestamp;
|
||||
private readonly string mName;
|
||||
private readonly DateTime? mTimestamp;
|
||||
|
||||
internal WriterEntry(string name, DateTime? timestamp)
|
||||
{
|
||||
|
||||
@@ -138,10 +138,10 @@ namespace Duplicati.Library.DynamicLoader
|
||||
/// <summary>
|
||||
/// The static instance used to access backend information
|
||||
/// </summary>
|
||||
private static BackendLoaderSub _backendLoader = new BackendLoaderSub();
|
||||
private static readonly BackendLoaderSub _backendLoader = new BackendLoaderSub();
|
||||
|
||||
#region Public static API
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of loaded backends, the instances can be used to extract interface information, not used to interact with the backend.
|
||||
/// </summary>
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace Duplicati.Library.DynamicLoader
|
||||
/// <summary>
|
||||
/// The static instance used to access compression module information
|
||||
/// </summary>
|
||||
private static CompressionLoaderSub _compressionLoader = new CompressionLoaderSub();
|
||||
private static readonly CompressionLoaderSub _compressionLoader = new CompressionLoaderSub();
|
||||
|
||||
#region Public static API
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace Duplicati.Library.DynamicLoader
|
||||
/// <summary>
|
||||
/// The static instance used to access encryption module information
|
||||
/// </summary>
|
||||
private static EncryptionLoaderSub _encryptionLoader = new EncryptionLoaderSub();
|
||||
private static readonly EncryptionLoaderSub _encryptionLoader = new EncryptionLoaderSub();
|
||||
|
||||
#region Public static API
|
||||
|
||||
|
||||
@@ -94,17 +94,17 @@ namespace Duplicati.Library.Encryption
|
||||
/// <summary>
|
||||
/// The PGP program to use, should be with absolute path
|
||||
/// </summary>
|
||||
private string m_programpath = "gpg";
|
||||
private readonly string m_programpath = "gpg";
|
||||
|
||||
/// <summary>
|
||||
/// Commandline switches for encryption
|
||||
/// </summary>
|
||||
private string m_encryption_args;
|
||||
private readonly string m_encryption_args;
|
||||
|
||||
/// <summary>
|
||||
/// Commandline switches for decryption
|
||||
/// </summary>
|
||||
private string m_decryption_args;
|
||||
private readonly string m_decryption_args;
|
||||
|
||||
/// <summary>
|
||||
/// The key used for cryptographic operations
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Duplicati.Library.Localization
|
||||
/// <summary>
|
||||
/// The previous context
|
||||
/// </summary>
|
||||
private object m_prev;
|
||||
private readonly object m_prev;
|
||||
|
||||
/// <summary>
|
||||
/// Flag to prevent double dispose
|
||||
|
||||
@@ -110,7 +110,7 @@ namespace Duplicati.Library.Localization
|
||||
/// </summary>
|
||||
public static ILocalizationService Get(CultureInfo ci)
|
||||
{
|
||||
if (ci == CultureInfo.InvariantCulture)
|
||||
if (ci.Equals(CultureInfo.InvariantCulture))
|
||||
return InvariantService;
|
||||
|
||||
ILocalizationService service;
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Duplicati.Library.Localization
|
||||
/// <summary>
|
||||
/// The catalog containing the translations
|
||||
/// </summary>
|
||||
private ICatalog catalog = new Catalog();
|
||||
private readonly ICatalog catalog = new Catalog();
|
||||
|
||||
/// <summary>
|
||||
/// The environment variable used to locate MO files
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Duplicati.Library.Localization.Short
|
||||
/// <summary>
|
||||
/// The instance for translation
|
||||
/// </summary>
|
||||
private static ILocalizationService LS = LocalizationService.Invariant;
|
||||
private static readonly ILocalizationService LS = LocalizationService.Invariant;
|
||||
|
||||
/// <summary>
|
||||
/// Localizes the string similar to how string.Format works
|
||||
@@ -172,7 +172,7 @@ namespace Duplicati.Library.Localization.Short
|
||||
/// <summary>
|
||||
/// The instance for translation
|
||||
/// </summary>
|
||||
private static ILocalizationService LS = LocalizationService.Installed;
|
||||
private static readonly ILocalizationService LS = LocalizationService.Installed;
|
||||
|
||||
/// <summary>
|
||||
/// Localizes the string similar to how string.Format works
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Duplicati.Library.Logging
|
||||
/// </summary>
|
||||
private static readonly string LOGTAG = "Timer";
|
||||
|
||||
private DateTime m_begin;
|
||||
private readonly DateTime m_begin;
|
||||
private string m_operation;
|
||||
private readonly string m_logtag;
|
||||
private readonly string m_logid;
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Duplicati.Library.Main
|
||||
{
|
||||
private class AsyncDownloadedFile : IAsyncDownloadedFile
|
||||
{
|
||||
private Exception m_exception;
|
||||
private readonly Exception m_exception;
|
||||
private Library.Utility.TempFile m_file;
|
||||
|
||||
public string Name { get; private set; }
|
||||
@@ -53,9 +53,9 @@ namespace Duplicati.Library.Main
|
||||
}
|
||||
}
|
||||
|
||||
private IList<IRemoteVolume> m_volumes;
|
||||
private readonly IList<IRemoteVolume> m_volumes;
|
||||
private BackendManager.IDownloadWaitHandle m_handle;
|
||||
private BackendManager m_backend;
|
||||
private readonly BackendManager m_backend;
|
||||
private int m_index;
|
||||
private AsyncDownloadedFile m_current;
|
||||
|
||||
@@ -129,8 +129,8 @@ namespace Duplicati.Library.Main
|
||||
}
|
||||
}
|
||||
|
||||
private IList<IRemoteVolume> m_volumes;
|
||||
private BackendManager m_backend;
|
||||
private readonly IList<IRemoteVolume> m_volumes;
|
||||
private readonly BackendManager m_backend;
|
||||
|
||||
public AsyncDownloader(IList<IRemoteVolume> volumes, BackendManager backend)
|
||||
{
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace Duplicati.Library.Main
|
||||
/// <summary>
|
||||
/// The event that is signaled once the operation is complete or has failed
|
||||
/// </summary>
|
||||
private System.Threading.ManualResetEvent DoneEvent;
|
||||
private readonly System.Threading.ManualResetEvent DoneEvent;
|
||||
|
||||
public FileEntryItem(OperationType operation, string remotefilename, Tuple<IndexVolumeWriter, FileEntryItem> indexfile = null)
|
||||
{
|
||||
@@ -245,10 +245,10 @@ namespace Duplicati.Library.Main
|
||||
private class DatabaseCollector
|
||||
{
|
||||
private readonly object m_dbqueuelock = new object();
|
||||
private LocalDatabase m_database;
|
||||
private System.Threading.Thread m_callerThread;
|
||||
private readonly LocalDatabase m_database;
|
||||
private readonly System.Threading.Thread m_callerThread;
|
||||
private List<IDbEntry> m_dbqueue;
|
||||
private IBackendWriter m_stats;
|
||||
private readonly IBackendWriter m_stats;
|
||||
|
||||
private interface IDbEntry { }
|
||||
|
||||
@@ -349,15 +349,15 @@ namespace Duplicati.Library.Main
|
||||
}
|
||||
|
||||
private readonly BlockingQueue<FileEntryItem> m_queue;
|
||||
private Options m_options;
|
||||
private readonly Options m_options;
|
||||
private volatile Exception m_lastException;
|
||||
private Library.Interface.IEncryption m_encryption;
|
||||
private readonly Library.Interface.IEncryption m_encryption;
|
||||
private readonly object m_encryptionLock = new object();
|
||||
private Library.Interface.IBackend m_backend;
|
||||
private string m_backendurl;
|
||||
private IBackendWriter m_statwriter;
|
||||
private readonly string m_backendurl;
|
||||
private readonly IBackendWriter m_statwriter;
|
||||
private System.Threading.Thread m_thread;
|
||||
private BasicResults m_taskControl;
|
||||
private readonly BasicResults m_taskControl;
|
||||
private readonly DatabaseCollector m_db;
|
||||
|
||||
// Cache these
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Duplicati.Library.Main
|
||||
/// <summary>
|
||||
/// The parsed type-safe version of the commandline options
|
||||
/// </summary>
|
||||
private Options m_options;
|
||||
private readonly Options m_options;
|
||||
/// <summary>
|
||||
/// The destination for all output messages during execution
|
||||
/// </summary>
|
||||
@@ -59,7 +59,7 @@ namespace Duplicati.Library.Main
|
||||
/// <summary>
|
||||
/// Holds various keys that need to be reset after running the task
|
||||
/// </summary>
|
||||
private Dictionary<string, string> m_resetKeys = new Dictionary<string, string>();
|
||||
private readonly Dictionary<string, string> m_resetKeys = new Dictionary<string, string>();
|
||||
|
||||
/// <summary>
|
||||
/// The thread priority to reset to
|
||||
@@ -222,7 +222,7 @@ namespace Duplicati.Library.Main
|
||||
//Sanity check for multiple inclusions of the same folder
|
||||
for (int i = 0; i < sources.Count; i++)
|
||||
for (int j = 0; j < sources.Count; j++)
|
||||
if (i != j && sources[i].StartsWith(sources[j], Library.Utility.Utility.ClientFilenameStringComparision) && sources[i].EndsWith(System.IO.Path.DirectorySeparatorChar.ToString(), Library.Utility.Utility.ClientFilenameStringComparision))
|
||||
if (i != j && sources[i].StartsWith(sources[j], Library.Utility.Utility.ClientFilenameStringComparison) && sources[i].EndsWith(System.IO.Path.DirectorySeparatorChar.ToString(), Library.Utility.Utility.ClientFilenameStringComparison))
|
||||
{
|
||||
if (filter != null)
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Duplicati.Library.Main
|
||||
/// <summary>
|
||||
/// The list of log targets to handle
|
||||
/// </summary>
|
||||
private List<Tuple<ILogDestination, LogMessageType, Library.Utility.IFilter>> m_targets = new List<Tuple<ILogDestination, LogMessageType, Library.Utility.IFilter>>();
|
||||
private readonly List<Tuple<ILogDestination, LogMessageType, Library.Utility.IFilter>> m_targets = new List<Tuple<ILogDestination, LogMessageType, Library.Utility.IFilter>>();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:Duplicati.Library.Main.ControllerMultiLogTarget"/> class.
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Duplicati.Library.Main
|
||||
/// <summary>
|
||||
/// The lookup table
|
||||
/// </summary>
|
||||
private SortedList<string, T>[] m_lookup;
|
||||
private readonly SortedList<string, T>[] m_lookup;
|
||||
/// <summary>
|
||||
/// The number of entries in the table
|
||||
/// </summary>
|
||||
|
||||
@@ -211,7 +211,7 @@ namespace Duplicati.Library.Main.Database
|
||||
public Tuple<string, object[]> GetFilelistWhereClause(DateTime time, long[] versions, IEnumerable<KeyValuePair<long, DateTime>> filesetslist = null, bool singleTimeMatch = false)
|
||||
{
|
||||
var filesets = (filesetslist ?? this.FilesetTimes).ToArray();
|
||||
string query = "";
|
||||
StringBuilder query = new StringBuilder();
|
||||
var args = new List<object>();
|
||||
if (time.Ticks > 0 || (versions != null && versions.Length > 0))
|
||||
{
|
||||
@@ -220,45 +220,44 @@ namespace Duplicati.Library.Main.Database
|
||||
{
|
||||
if (time.Kind == DateTimeKind.Unspecified)
|
||||
throw new Exception("Invalid DateTime given, must be either local or UTC");
|
||||
|
||||
query += singleTimeMatch ? @" ""Timestamp"" = ?" : @" ""Timestamp"" <= ?";
|
||||
|
||||
query.Append(singleTimeMatch ? @" ""Timestamp"" = ?" : @" ""Timestamp"" <= ?");
|
||||
// Make sure the resolution is the same (i.e. no milliseconds)
|
||||
args.Add(NormalizeDateTimeToEpochSeconds(time));
|
||||
hasTime = true;
|
||||
}
|
||||
|
||||
|
||||
if (versions != null && versions.Length > 0)
|
||||
{
|
||||
var qs = "";
|
||||
StringBuilder qs = new StringBuilder();
|
||||
|
||||
foreach (var v in versions)
|
||||
{
|
||||
if (v >= 0 && v < filesets.Length)
|
||||
{
|
||||
args.Add(filesets[v].Key);
|
||||
qs += "?,";
|
||||
qs.Append("?,");
|
||||
}
|
||||
else
|
||||
Logging.Log.WriteWarningMessage(LOGTAG, "SkipInvalidVersion", null, "Skipping invalid version: {0}", v);
|
||||
}
|
||||
|
||||
|
||||
if (qs.Length > 0)
|
||||
{
|
||||
qs = qs.Substring(0, qs.Length - 1);
|
||||
|
||||
if (hasTime)
|
||||
query += " OR ";
|
||||
|
||||
query += @" ""ID"" IN (" + qs + ")";
|
||||
query.Append(" OR ");
|
||||
|
||||
query.Append(@" ""ID"" IN (" + qs.ToString(0, qs.Length - 1) + ")");
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(query))
|
||||
query = " WHERE " + query;
|
||||
|
||||
if (query.Length > 0)
|
||||
{
|
||||
query.Insert(0, " WHERE ");
|
||||
}
|
||||
}
|
||||
|
||||
return new Tuple<string, object[]>(query, args.ToArray());
|
||||
return new Tuple<string, object[]>(query.ToString(), args.ToArray());
|
||||
}
|
||||
|
||||
public long GetRemoteVolumeID(string file, System.Data.IDbTransaction transaction = null)
|
||||
@@ -562,8 +561,8 @@ namespace Duplicati.Library.Main.Database
|
||||
|
||||
protected class TemporaryTransactionWrapper : IDisposable
|
||||
{
|
||||
private System.Data.IDbTransaction m_parent;
|
||||
private bool m_isTemporary;
|
||||
private readonly System.Data.IDbTransaction m_parent;
|
||||
private readonly bool m_isTemporary;
|
||||
|
||||
public TemporaryTransactionWrapper(System.Data.IDbConnection connection, System.Data.IDbTransaction transaction)
|
||||
{
|
||||
@@ -605,7 +604,7 @@ namespace Duplicati.Library.Main.Database
|
||||
|
||||
private class LocalFileEntry : ILocalFileEntry
|
||||
{
|
||||
private System.Data.IDataReader m_reader;
|
||||
private readonly System.Data.IDataReader m_reader;
|
||||
public LocalFileEntry(System.Data.IDataReader reader)
|
||||
{
|
||||
m_reader = reader;
|
||||
@@ -850,8 +849,8 @@ ON
|
||||
{
|
||||
private class BlocklistHashEnumerator : IEnumerator<string>
|
||||
{
|
||||
private System.Data.IDataReader m_reader;
|
||||
private BlocklistHashEnumerable m_parent;
|
||||
private readonly System.Data.IDataReader m_reader;
|
||||
private readonly BlocklistHashEnumerable m_parent;
|
||||
private string m_path = null;
|
||||
private bool m_first = true;
|
||||
private string m_current = null;
|
||||
@@ -913,7 +912,7 @@ ON
|
||||
}
|
||||
}
|
||||
|
||||
private System.Data.IDataReader m_reader;
|
||||
private readonly System.Data.IDataReader m_reader;
|
||||
|
||||
public BlocklistHashEnumerable(System.Data.IDataReader reader)
|
||||
{
|
||||
@@ -1143,8 +1142,8 @@ ORDER BY
|
||||
public class FilteredFilenameTable : IDisposable
|
||||
{
|
||||
public string Tablename { get; private set; }
|
||||
private System.Data.IDbConnection m_connection;
|
||||
|
||||
private readonly System.Data.IDbConnection m_connection;
|
||||
|
||||
public FilteredFilenameTable(System.Data.IDbConnection connection, Library.Utility.IFilter filter, System.Data.IDbTransaction transaction)
|
||||
{
|
||||
m_connection = connection;
|
||||
|
||||
@@ -69,12 +69,7 @@ namespace Duplicati.Library.Main.Database
|
||||
{
|
||||
cmd.Transaction = transaction;
|
||||
|
||||
var q = "";
|
||||
foreach(var n in toDelete)
|
||||
if (q.Length == 0)
|
||||
q = "?";
|
||||
else
|
||||
q += ",?";
|
||||
string q = String.Join(",", Enumerable.Repeat("?", toDelete.Length));
|
||||
|
||||
//First we remove unwanted entries
|
||||
var deleted = cmd.ExecuteNonQuery(@"DELETE FROM ""Fileset"" WHERE ""Timestamp"" IN (" + q + @") ", toDelete.Select(x => NormalizeDateTimeToEpochSeconds(x)).Cast<object>().ToArray());
|
||||
@@ -175,20 +170,20 @@ namespace Duplicati.Library.Main.Database
|
||||
|
||||
private class CompactReport : ICompactReport
|
||||
{
|
||||
private IEnumerable<VolumeUsage> m_report;
|
||||
private IEnumerable<VolumeUsage> m_cleandelete;
|
||||
private IEnumerable<VolumeUsage> m_wastevolumes;
|
||||
private IEnumerable<VolumeUsage> m_smallvolumes;
|
||||
private readonly IEnumerable<VolumeUsage> m_report;
|
||||
private readonly IEnumerable<VolumeUsage> m_cleandelete;
|
||||
private readonly IEnumerable<VolumeUsage> m_wastevolumes;
|
||||
private readonly IEnumerable<VolumeUsage> m_smallvolumes;
|
||||
|
||||
private readonly long m_deletablevolumes;
|
||||
private readonly long m_wastedspace;
|
||||
private readonly long m_smallspace;
|
||||
private readonly long m_fullsize;
|
||||
private readonly long m_smallvolumecount;
|
||||
|
||||
private long m_deletablevolumes;
|
||||
private long m_wastedspace;
|
||||
private long m_smallspace;
|
||||
private long m_fullsize;
|
||||
private long m_smallvolumecount;
|
||||
|
||||
private long m_wastethreshold;
|
||||
private long m_volsize;
|
||||
private long m_maxsmallfilecount;
|
||||
private readonly long m_wastethreshold;
|
||||
private readonly long m_volsize;
|
||||
private readonly long m_maxsmallfilecount;
|
||||
|
||||
public CompactReport(long volsize, long wastethreshold, long smallfilesize, long maxsmallfilecount, IEnumerable<VolumeUsage> report)
|
||||
{
|
||||
|
||||
@@ -89,7 +89,7 @@ namespace Duplicati.Library.Main.Database
|
||||
|
||||
private class StorageHelper : IStorageHelper
|
||||
{
|
||||
private System.Data.IDbConnection m_connection;
|
||||
private readonly System.Data.IDbConnection m_connection;
|
||||
private System.Data.IDbTransaction m_transaction;
|
||||
|
||||
private System.Data.IDbCommand m_insertPreviousElementCommand;
|
||||
|
||||
@@ -56,9 +56,9 @@ namespace Duplicati.Library.Main.Database
|
||||
|
||||
private class FileSets : IFileSets
|
||||
{
|
||||
private System.Data.IDbConnection m_connection;
|
||||
private readonly System.Data.IDbConnection m_connection;
|
||||
private string m_tablename;
|
||||
private KeyValuePair<long, DateTime>[] m_filesets;
|
||||
private readonly KeyValuePair<long, DateTime>[] m_filesets;
|
||||
|
||||
public FileSets(LocalListDatabase owner, DateTime time, long[] versions)
|
||||
{
|
||||
@@ -94,7 +94,7 @@ namespace Duplicati.Library.Main.Database
|
||||
|
||||
private class Fileversion : IFileversion
|
||||
{
|
||||
private System.Data.IDataReader m_reader;
|
||||
private readonly System.Data.IDataReader m_reader;
|
||||
public string Path { get; private set; }
|
||||
public bool More { get; private set; }
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace Duplicati.Library.Main.Database
|
||||
private readonly System.Data.IDbConnection m_connection;
|
||||
private readonly System.Data.IDbTransaction m_transaction;
|
||||
private readonly string m_tablename;
|
||||
private LocalPurgeDatabase m_parentdb;
|
||||
private readonly LocalPurgeDatabase m_parentdb;
|
||||
|
||||
public long ParentID { get; private set; }
|
||||
public long RemovedFileCount { get; private set; }
|
||||
|
||||
@@ -49,23 +49,23 @@ namespace Duplicati.Library.Main.Database
|
||||
}
|
||||
}
|
||||
|
||||
private System.Data.IDbCommand m_insertFileCommand;
|
||||
private System.Data.IDbCommand m_insertFilesetEntryCommand;
|
||||
private System.Data.IDbCommand m_insertMetadatasetCommand;
|
||||
private System.Data.IDbCommand m_insertBlocksetCommand;
|
||||
private System.Data.IDbCommand m_insertBlocklistHashCommand;
|
||||
private System.Data.IDbCommand m_updateBlockVolumeCommand;
|
||||
private System.Data.IDbCommand m_insertBlockset;
|
||||
private System.Data.IDbCommand m_insertSmallBlockset;
|
||||
private System.Data.IDbCommand m_findBlocksetCommand;
|
||||
private System.Data.IDbCommand m_findMetadatasetCommand;
|
||||
private System.Data.IDbCommand m_findFilesetCommand;
|
||||
private System.Data.IDbCommand m_findblocklisthashCommand;
|
||||
private System.Data.IDbCommand m_findHashBlockCommand;
|
||||
private System.Data.IDbCommand m_insertBlockCommand;
|
||||
private System.Data.IDbCommand m_insertDuplicateBlockCommand;
|
||||
private readonly System.Data.IDbCommand m_insertFileCommand;
|
||||
private readonly System.Data.IDbCommand m_insertFilesetEntryCommand;
|
||||
private readonly System.Data.IDbCommand m_insertMetadatasetCommand;
|
||||
private readonly System.Data.IDbCommand m_insertBlocksetCommand;
|
||||
private readonly System.Data.IDbCommand m_insertBlocklistHashCommand;
|
||||
private readonly System.Data.IDbCommand m_updateBlockVolumeCommand;
|
||||
private readonly System.Data.IDbCommand m_insertBlockset;
|
||||
private readonly System.Data.IDbCommand m_insertSmallBlockset;
|
||||
private readonly System.Data.IDbCommand m_findBlocksetCommand;
|
||||
private readonly System.Data.IDbCommand m_findMetadatasetCommand;
|
||||
private readonly System.Data.IDbCommand m_findFilesetCommand;
|
||||
private readonly System.Data.IDbCommand m_findblocklisthashCommand;
|
||||
private readonly System.Data.IDbCommand m_findHashBlockCommand;
|
||||
private readonly System.Data.IDbCommand m_insertBlockCommand;
|
||||
private readonly System.Data.IDbCommand m_insertDuplicateBlockCommand;
|
||||
|
||||
private PathLookupHelper<PathEntryKeeper> m_filesetLookup;
|
||||
private readonly PathLookupHelper<PathEntryKeeper> m_filesetLookup;
|
||||
|
||||
private string m_tempblocklist;
|
||||
private string m_tempsmalllist;
|
||||
|
||||
@@ -71,8 +71,8 @@ namespace Duplicati.Library.Main.Database
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private System.Data.IDataReader m_rd;
|
||||
|
||||
private readonly System.Data.IDataReader m_rd;
|
||||
public bool Done { get; private set; }
|
||||
|
||||
public BlockWithSources(System.Data.IDataReader rd)
|
||||
@@ -135,11 +135,11 @@ namespace Duplicati.Library.Main.Database
|
||||
|
||||
private class MissingBlockList : IMissingBlockList
|
||||
{
|
||||
private System.Data.IDbConnection m_connection;
|
||||
private TemporaryTransactionWrapper m_transaction;
|
||||
private readonly System.Data.IDbConnection m_connection;
|
||||
private readonly TemporaryTransactionWrapper m_transaction;
|
||||
private System.Data.IDbCommand m_insertCommand;
|
||||
private string m_tablename;
|
||||
private string m_volumename;
|
||||
private readonly string m_volumename;
|
||||
|
||||
public MissingBlockList(string volumename, System.Data.IDbConnection connection, System.Data.IDbTransaction transaction)
|
||||
{
|
||||
|
||||
@@ -536,7 +536,7 @@ namespace Duplicati.Library.Main.Database
|
||||
|
||||
private class ExistingFile : IExistingFile
|
||||
{
|
||||
private System.Data.IDataReader m_reader;
|
||||
private readonly System.Data.IDataReader m_reader;
|
||||
|
||||
public ExistingFile(System.Data.IDataReader rd) { m_reader = rd; HasMore = true; }
|
||||
|
||||
@@ -549,7 +549,7 @@ namespace Duplicati.Library.Main.Database
|
||||
|
||||
private class ExistingFileBlock : IExistingFileBlock
|
||||
{
|
||||
private System.Data.IDataReader m_reader;
|
||||
private readonly System.Data.IDataReader m_reader;
|
||||
|
||||
public ExistingFileBlock(System.Data.IDataReader rd) { m_reader = rd; }
|
||||
|
||||
@@ -606,7 +606,7 @@ namespace Duplicati.Library.Main.Database
|
||||
{
|
||||
private class BlockSource : IBlockSource
|
||||
{
|
||||
private System.Data.IDataReader m_reader;
|
||||
private readonly System.Data.IDataReader m_reader;
|
||||
public BlockSource(System.Data.IDataReader rd) { m_reader = rd; }
|
||||
|
||||
public string Path { get { return m_reader.ConvertValueToString(6); } }
|
||||
@@ -615,7 +615,7 @@ namespace Duplicati.Library.Main.Database
|
||||
public bool IsMetadata { get { return false; } }
|
||||
}
|
||||
|
||||
private System.Data.IDataReader m_reader;
|
||||
private readonly System.Data.IDataReader m_reader;
|
||||
public BlockDescriptor(System.Data.IDataReader rd) { m_reader = rd; HasMore = true; }
|
||||
|
||||
private string TargetPath { get { return m_reader.ConvertValueToString(0); } }
|
||||
@@ -645,7 +645,7 @@ namespace Duplicati.Library.Main.Database
|
||||
}
|
||||
}
|
||||
|
||||
private System.Data.IDataReader m_reader;
|
||||
private readonly System.Data.IDataReader m_reader;
|
||||
public LocalBlockSource(System.Data.IDataReader rd) { m_reader = rd; HasMore = true; }
|
||||
|
||||
public string TargetPath { get { return m_reader.ConvertValueToString(0); } }
|
||||
@@ -756,12 +756,12 @@ namespace Duplicati.Library.Main.Database
|
||||
|
||||
private class FilesAndMetadata : IFilesAndMetadata
|
||||
{
|
||||
private string m_tmptable;
|
||||
private string m_filetablename;
|
||||
private string m_blocktablename;
|
||||
private long m_blocksize;
|
||||
private readonly string m_tmptable;
|
||||
private readonly string m_filetablename;
|
||||
private readonly string m_blocktablename;
|
||||
private readonly long m_blocksize;
|
||||
|
||||
private System.Data.IDbConnection m_connection;
|
||||
private readonly System.Data.IDbConnection m_connection;
|
||||
|
||||
public FilesAndMetadata(System.Data.IDbConnection connection, string filetablename, string blocktablename, long blocksize, BlockVolumeReader curvolume)
|
||||
{
|
||||
@@ -805,7 +805,7 @@ namespace Duplicati.Library.Main.Database
|
||||
{
|
||||
private class PatchBlock : IPatchBlock
|
||||
{
|
||||
private System.Data.IDataReader m_reader;
|
||||
private readonly System.Data.IDataReader m_reader;
|
||||
public PatchBlock(System.Data.IDataReader rd) { m_reader = rd; }
|
||||
|
||||
public long Offset { get { return m_reader.ConvertValueToInt64(2); } }
|
||||
@@ -813,7 +813,7 @@ namespace Duplicati.Library.Main.Database
|
||||
public string Key { get { return m_reader.ConvertValueToString(4); } }
|
||||
}
|
||||
|
||||
private System.Data.IDataReader m_reader;
|
||||
private readonly System.Data.IDataReader m_reader;
|
||||
public VolumePatch(System.Data.IDataReader rd) { m_reader = rd; HasMore = true; }
|
||||
|
||||
public string Path { get { return m_reader.ConvertValueToString(0); } }
|
||||
@@ -1017,8 +1017,8 @@ namespace Duplicati.Library.Main.Database
|
||||
private System.Data.IDbCommand m_statUpdateCommand;
|
||||
private bool m_hasUpdates = false;
|
||||
|
||||
private string m_blocktablename;
|
||||
private string m_filetablename;
|
||||
private readonly string m_blocktablename;
|
||||
private readonly string m_filetablename;
|
||||
|
||||
public System.Data.IDbTransaction Transaction { get { return m_insertblockCommand.Transaction; } }
|
||||
|
||||
@@ -1212,17 +1212,17 @@ namespace Duplicati.Library.Main.Database
|
||||
{
|
||||
private class BlockEntry : IBlockEntry
|
||||
{
|
||||
private System.Data.IDataReader m_rd;
|
||||
private long m_blocksize;
|
||||
private readonly System.Data.IDataReader m_rd;
|
||||
private readonly long m_blocksize;
|
||||
public BlockEntry(System.Data.IDataReader rd, long blocksize) { m_rd = rd; m_blocksize = blocksize; }
|
||||
public long Offset { get { return m_rd.GetInt64(3) * m_blocksize; } }
|
||||
public long Index { get { return m_rd.GetInt64(3); } }
|
||||
public long Size { get { return m_rd.GetInt64(5); } }
|
||||
public string Hash { get { return m_rd.GetString(4); } }
|
||||
}
|
||||
|
||||
private System.Data.IDataReader m_rd;
|
||||
private long m_blocksize;
|
||||
|
||||
private readonly System.Data.IDataReader m_rd;
|
||||
private readonly long m_blocksize;
|
||||
public FastSource(System.Data.IDataReader rd, long blocksize) { m_rd = rd; m_blocksize = blocksize; MoreData = true; }
|
||||
public bool MoreData { get; private set; }
|
||||
public string TargetPath { get { return m_rd.GetValue(0).ToString(); } }
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace Duplicati.Library.Main.Database
|
||||
var hotIx = Math.Min(m_lookup.Count, paths.Length) - 1;
|
||||
while (hotIx >= 0)
|
||||
{
|
||||
if (path.StartsWith(m_lookup[hotIx].Key, Duplicati.Library.Utility.Utility.ClientFilenameStringComparision))
|
||||
if (path.StartsWith(m_lookup[hotIx].Key, Duplicati.Library.Utility.Utility.ClientFilenameStringComparison))
|
||||
{
|
||||
c = m_lookup[hotIx].Value;
|
||||
|
||||
|
||||
@@ -202,12 +202,13 @@ namespace Duplicati.Library.Main
|
||||
|
||||
public static string GenerateRandomName()
|
||||
{
|
||||
var backupname = "";
|
||||
var rnd = new Random();
|
||||
for(var i = 0; i < 10; i++)
|
||||
backupname += (char)rnd.Next('A', 'Z' + 1);
|
||||
|
||||
return backupname;
|
||||
|
||||
System.Text.StringBuilder backupName = new System.Text.StringBuilder();
|
||||
for (var i = 0; i < 10; i++)
|
||||
backupName.Append(rnd.Next('A', 'Z' + 1));
|
||||
|
||||
return backupName.ToString();
|
||||
}
|
||||
|
||||
public static bool IsDatabasePathInUse(string path)
|
||||
@@ -220,7 +221,7 @@ namespace Duplicati.Library.Main
|
||||
if (!System.IO.File.Exists(file))
|
||||
return false;
|
||||
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<List<BackendEntry>>(System.IO.File.ReadAllText(file, System.Text.Encoding.UTF8)).Any(x => string.Equals(path, x.Databasepath, Library.Utility.Utility.ClientFilenameStringComparision));
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<List<BackendEntry>>(System.IO.File.ReadAllText(file, System.Text.Encoding.UTF8)).Any(x => string.Equals(path, x.Databasepath, Library.Utility.Utility.ClientFilenameStringComparison));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Duplicati.Library.Main.Operation.Backup
|
||||
internal class FlushRequest : IUploadRequest
|
||||
{
|
||||
public Task<long> LastWriteSizeAync { get { return m_tcs.Task; } }
|
||||
private TaskCompletionSource<long> m_tcs = new TaskCompletionSource<long>();
|
||||
private readonly TaskCompletionSource<long> m_tcs = new TaskCompletionSource<long>();
|
||||
public void SetFlushed(long size)
|
||||
{
|
||||
m_tcs.TrySetResult(size);
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Duplicati.Library.Main.Operation.Backup
|
||||
/// </summary>
|
||||
internal class BackupDatabase : DatabaseCommon
|
||||
{
|
||||
private LocalBackupDatabase m_database;
|
||||
private readonly LocalBackupDatabase m_database;
|
||||
|
||||
public class FileEntryData
|
||||
{
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Duplicati.Library.Main.Operation.Backup
|
||||
/// </summary>
|
||||
internal class BackupStatsCollector : StatsCollector
|
||||
{
|
||||
private BackupResults m_res;
|
||||
private readonly BackupResults m_res;
|
||||
|
||||
public BackupStatsCollector(BackupResults res)
|
||||
: base(res.BackendWriter)
|
||||
|
||||
@@ -143,7 +143,7 @@ namespace Duplicati.Library.Main.Operation.Backup
|
||||
var isDirectory = s[s.Length - 1] == System.IO.Path.DirectorySeparatorChar;
|
||||
if (isDirectory)
|
||||
{
|
||||
while (pathstack.Count > 0 && !s.StartsWith(pathstack.Peek().Path, Library.Utility.Utility.ClientFilenameStringComparision))
|
||||
while (pathstack.Count > 0 && !s.StartsWith(pathstack.Peek().Path, Library.Utility.Utility.ClientFilenameStringComparison))
|
||||
{
|
||||
var e = pathstack.Pop();
|
||||
if (e.AnyEntries || pathstack.Count == 0)
|
||||
@@ -158,7 +158,7 @@ namespace Duplicati.Library.Main.Operation.Backup
|
||||
Logging.Log.WriteVerboseMessage(FILTER_LOGTAG, "ExcludingEmptyFolder", "Excluding empty folder {0}", e.Path);
|
||||
}
|
||||
|
||||
if (pathstack.Count == 0 || s.StartsWith(pathstack.Peek().Path, Library.Utility.Utility.ClientFilenameStringComparision))
|
||||
if (pathstack.Count == 0 || s.StartsWith(pathstack.Peek().Path, Library.Utility.Utility.ClientFilenameStringComparison))
|
||||
{
|
||||
pathstack.Push(new DirectoryStackEntry() { Path = s });
|
||||
continue;
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Duplicati.Library.Main.Operation
|
||||
private static readonly string LOGTAG = Logging.Log.LogTagFromType<BackupHandler>();
|
||||
|
||||
private readonly Options m_options;
|
||||
private string m_backendurl;
|
||||
private readonly string m_backendurl;
|
||||
|
||||
private LocalBackupDatabase m_database;
|
||||
private System.Data.IDbTransaction m_transaction;
|
||||
@@ -56,7 +56,7 @@ namespace Duplicati.Library.Main.Operation
|
||||
private Library.Utility.IFilter m_filter;
|
||||
private Library.Utility.IFilter m_sourceFilter;
|
||||
|
||||
private BackupResults m_result;
|
||||
private readonly BackupResults m_result;
|
||||
|
||||
public BackupHandler(string backendurl, Options options, BackupResults results)
|
||||
{
|
||||
|
||||
@@ -156,13 +156,13 @@ namespace Duplicati.Library.Main.Operation.Common
|
||||
}
|
||||
|
||||
|
||||
private DatabaseCommon m_database;
|
||||
private readonly DatabaseCommon m_database;
|
||||
private IBackend m_backend;
|
||||
private Options m_options;
|
||||
private string m_backendurl;
|
||||
private readonly Options m_options;
|
||||
private readonly string m_backendurl;
|
||||
private bool m_uploadSuccess;
|
||||
private StatsCollector m_stats;
|
||||
private ITaskReader m_taskreader;
|
||||
private readonly StatsCollector m_stats;
|
||||
private readonly ITaskReader m_taskreader;
|
||||
|
||||
public BackendHandler(Options options, string backendUrl, DatabaseCommon database, StatsCollector stats, ITaskReader taskreader)
|
||||
: base()
|
||||
|
||||
@@ -29,8 +29,8 @@ namespace Duplicati.Library.Main.Operation
|
||||
/// </summary>
|
||||
private static readonly string LOGTAG = Logging.Log.LogTagFromType<CreateBugReportHandler>();
|
||||
private string m_targetpath;
|
||||
private Options m_options;
|
||||
private CreateLogDatabaseResults m_result;
|
||||
private readonly Options m_options;
|
||||
private readonly CreateLogDatabaseResults m_result;
|
||||
|
||||
public CreateBugReportHandler(string targetpath, Options options, CreateLogDatabaseResults result)
|
||||
{
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Duplicati.Library.Main.Operation
|
||||
/// </summary>
|
||||
private static readonly string LOGTAG_RETENTION = LOGTAG + ":RetentionPolicy";
|
||||
|
||||
private DeleteResults m_result;
|
||||
private readonly DeleteResults m_result;
|
||||
protected string m_backendurl;
|
||||
protected Options m_options;
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@ namespace Duplicati.Library.Main.Operation
|
||||
{
|
||||
internal class ListAffected
|
||||
{
|
||||
private Options m_options;
|
||||
private ListAffectedResults m_result;
|
||||
private readonly Options m_options;
|
||||
private readonly ListAffectedResults m_result;
|
||||
|
||||
public ListAffected(Options options, ListAffectedResults result)
|
||||
{
|
||||
|
||||
@@ -29,9 +29,9 @@ namespace Duplicati.Library.Main.Operation
|
||||
/// </summary>
|
||||
private static readonly string LOGTAG = Logging.Log.LogTagFromType(typeof(ListChangesHandler));
|
||||
|
||||
private string m_backendurl;
|
||||
private Options m_options;
|
||||
private ListChangesResults m_result;
|
||||
private readonly string m_backendurl;
|
||||
private readonly Options m_options;
|
||||
private readonly ListChangesResults m_result;
|
||||
|
||||
public ListChangesHandler(string backend, Options options, ListChangesResults result)
|
||||
{
|
||||
|
||||
@@ -23,9 +23,9 @@ namespace Duplicati.Library.Main.Operation
|
||||
{
|
||||
internal class ListControlFilesHandler
|
||||
{
|
||||
private Options m_options;
|
||||
private string m_backendurl;
|
||||
private ListResults m_result;
|
||||
private readonly Options m_options;
|
||||
private readonly string m_backendurl;
|
||||
private readonly ListResults m_result;
|
||||
|
||||
public ListControlFilesHandler(string backendurl, Options options, ListResults result)
|
||||
{
|
||||
|
||||
@@ -13,9 +13,9 @@ namespace Duplicati.Library.Main.Operation
|
||||
/// </summary>
|
||||
private static readonly string LOGTAG = Logging.Log.LogTagFromType<ListFilesHandler>();
|
||||
|
||||
private string m_backendurl;
|
||||
private Options m_options;
|
||||
private ListResults m_result;
|
||||
private readonly string m_backendurl;
|
||||
private readonly Options m_options;
|
||||
private readonly ListResults m_result;
|
||||
|
||||
public ListFilesHandler(string backend, Options options, ListResults result)
|
||||
{
|
||||
|
||||
@@ -14,9 +14,9 @@ namespace Duplicati.Library.Main.Operation
|
||||
/// </summary>
|
||||
private static readonly string LOGTAG = Logging.Log.LogTagFromType<RecreateDatabaseHandler>();
|
||||
|
||||
private string m_backendurl;
|
||||
private Options m_options;
|
||||
private RecreateDatabaseResults m_result;
|
||||
private readonly string m_backendurl;
|
||||
private readonly Options m_options;
|
||||
private readonly RecreateDatabaseResults m_result;
|
||||
|
||||
public delegate IEnumerable<KeyValuePair<long, IParsedVolume>> NumberedFilterFilelistDelegate(IEnumerable<IParsedVolume> filelist);
|
||||
public delegate void BlockVolumePostProcessor(string volumename,BlockVolumeReader reader);
|
||||
|
||||
@@ -14,9 +14,9 @@ namespace Duplicati.Library.Main.Operation
|
||||
/// The tag used for logging
|
||||
/// </summary>
|
||||
private static readonly string LOGTAG = Logging.Log.LogTagFromType<RepairHandler>();
|
||||
private string m_backendurl;
|
||||
private Options m_options;
|
||||
private RepairResults m_result;
|
||||
private readonly string m_backendurl;
|
||||
private readonly Options m_options;
|
||||
private readonly RepairResults m_result;
|
||||
|
||||
public RepairHandler(string backend, Options options, RepairResults result)
|
||||
{
|
||||
|
||||
@@ -7,9 +7,9 @@ namespace Duplicati.Library.Main.Operation
|
||||
{
|
||||
internal class RestoreControlFilesHandler
|
||||
{
|
||||
private Options m_options;
|
||||
private string m_backendurl;
|
||||
private RestoreControlFilesResults m_result;
|
||||
private readonly Options m_options;
|
||||
private readonly string m_backendurl;
|
||||
private readonly RestoreControlFilesResults m_result;
|
||||
|
||||
public RestoreControlFilesHandler(string backendurl, Options options, RestoreControlFilesResults result)
|
||||
{
|
||||
|
||||
@@ -15,10 +15,10 @@ namespace Duplicati.Library.Main.Operation
|
||||
/// </summary>
|
||||
private static readonly string LOGTAG = Logging.Log.LogTagFromType<RestoreHandler>();
|
||||
|
||||
private string m_backendurl;
|
||||
private Options m_options;
|
||||
private readonly string m_backendurl;
|
||||
private readonly Options m_options;
|
||||
private byte[] m_blockbuffer;
|
||||
private RestoreResults m_result;
|
||||
private readonly RestoreResults m_result;
|
||||
private static readonly Snapshots.ISystemIO m_systemIO = Duplicati.Library.Utility.Utility.IsClientLinux ? (Snapshots.ISystemIO)new Snapshots.SystemIOLinux() : (Snapshots.ISystemIO)new Snapshots.SystemIOWindows();
|
||||
private static readonly string DIRSEP = System.IO.Path.DirectorySeparatorChar.ToString();
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ namespace Duplicati.Library.Main.Operation
|
||||
private static readonly string LOGTAG = Logging.Log.LogTagFromType<TestHandler>();
|
||||
|
||||
private readonly Options m_options;
|
||||
private string m_backendurl;
|
||||
private TestResults m_results;
|
||||
private readonly string m_backendurl;
|
||||
private readonly TestResults m_results;
|
||||
|
||||
public TestHandler(string backendurl, Options options, TestResults results)
|
||||
{
|
||||
|
||||
@@ -8,8 +8,8 @@ namespace Duplicati.Library.Main.Operation
|
||||
{
|
||||
internal class VacuumHandler
|
||||
{
|
||||
private Options m_options;
|
||||
private VacuumResult m_result;
|
||||
private readonly Options m_options;
|
||||
private readonly VacuumResult m_result;
|
||||
|
||||
public VacuumHandler(Options options, VacuumResult result)
|
||||
{
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Duplicati.Library.Interface;
|
||||
using Duplicati.Library.Utility;
|
||||
|
||||
@@ -739,8 +738,8 @@ namespace Duplicati.Library.Main
|
||||
{
|
||||
if (!m_options.ContainsKey("tempdir") || string.IsNullOrEmpty(m_options["tempdir"]))
|
||||
return System.IO.Path.GetTempPath();
|
||||
else
|
||||
return m_options["tempdir"];
|
||||
|
||||
return m_options["tempdir"];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -202,7 +202,7 @@ namespace Duplicati.Library.Main
|
||||
protected Queue<DbMessage> m_dbqueue;
|
||||
|
||||
private TaskControlState m_controlState = TaskControlState.Run;
|
||||
private System.Threading.ManualResetEvent m_pauseEvent = new System.Threading.ManualResetEvent(true);
|
||||
private readonly System.Threading.ManualResetEvent m_pauseEvent = new System.Threading.ManualResetEvent(true);
|
||||
|
||||
public virtual ParsedResultType ParsedResult
|
||||
{
|
||||
@@ -863,7 +863,7 @@ namespace Duplicati.Library.Main
|
||||
|
||||
public override OperationMode MainOperation { get { return OperationMode.Test; } }
|
||||
public IEnumerable<KeyValuePair<string, IEnumerable<KeyValuePair<TestEntryStatus, string>>>> Verifications { get { return m_verifications; } }
|
||||
private List<KeyValuePair<string, IEnumerable<KeyValuePair<TestEntryStatus, string>>>> m_verifications = new List<KeyValuePair<string, IEnumerable<KeyValuePair<TestEntryStatus, string>>>>();
|
||||
private readonly List<KeyValuePair<string, IEnumerable<KeyValuePair<TestEntryStatus, string>>>> m_verifications = new List<KeyValuePair<string, IEnumerable<KeyValuePair<TestEntryStatus, string>>>>();
|
||||
|
||||
public KeyValuePair<string, IEnumerable<KeyValuePair<TestEntryStatus, string>>> AddResult(string volume, IEnumerable<KeyValuePair<TestEntryStatus, string>> changes)
|
||||
{
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Duplicati.Library.Main.Volumes
|
||||
{
|
||||
private class BlocklistHashEnumerator : IEnumerator<string>
|
||||
{
|
||||
private JsonReader m_reader;
|
||||
private readonly JsonReader m_reader;
|
||||
private string m_current;
|
||||
private bool m_firstReset = true;
|
||||
private bool m_done = false;
|
||||
@@ -73,7 +73,7 @@ namespace Duplicati.Library.Main.Volumes
|
||||
}
|
||||
}
|
||||
|
||||
private JsonReader m_reader;
|
||||
private readonly JsonReader m_reader;
|
||||
public BlocklistHashEnumerable(JsonReader reader)
|
||||
{
|
||||
m_reader = reader;
|
||||
@@ -103,7 +103,7 @@ namespace Duplicati.Library.Main.Volumes
|
||||
public long Blocksize { get; private set; }
|
||||
public IEnumerable<string> BlocklistHashes { get; private set; }
|
||||
public IEnumerable<string> MetaBlocklistHashes { get; private set; }
|
||||
private JsonReader m_reader;
|
||||
private readonly JsonReader m_reader;
|
||||
|
||||
public FileEntry(JsonReader reader)
|
||||
{
|
||||
@@ -221,7 +221,7 @@ namespace Duplicati.Library.Main.Volumes
|
||||
}
|
||||
}
|
||||
|
||||
private ICompression m_compression;
|
||||
private readonly ICompression m_compression;
|
||||
private FileEntry m_current;
|
||||
private StreamReader m_stream;
|
||||
private JsonReader m_reader;
|
||||
@@ -302,7 +302,7 @@ namespace Duplicati.Library.Main.Volumes
|
||||
}
|
||||
}
|
||||
|
||||
private ICompression m_compression;
|
||||
private readonly ICompression m_compression;
|
||||
public FileEntryEnumerable(ICompression compression)
|
||||
{
|
||||
m_compression = compression;
|
||||
@@ -323,7 +323,7 @@ namespace Duplicati.Library.Main.Volumes
|
||||
{
|
||||
private class ControlFileEnumerator : IEnumerator<KeyValuePair<string, Stream>>
|
||||
{
|
||||
private ICompression m_compression;
|
||||
private readonly ICompression m_compression;
|
||||
private string[] m_files;
|
||||
private long m_index;
|
||||
private KeyValuePair<string, Stream>? m_current;
|
||||
@@ -365,7 +365,7 @@ namespace Duplicati.Library.Main.Volumes
|
||||
}
|
||||
}
|
||||
|
||||
private ICompression m_compression;
|
||||
private readonly ICompression m_compression;
|
||||
public ControlFileEnumerable(ICompression compression)
|
||||
{
|
||||
m_compression = compression;
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Duplicati.Library.Main.Volumes
|
||||
public class FilesetVolumeWriter : VolumeWriterBase
|
||||
{
|
||||
private StreamWriter m_streamwriter;
|
||||
private JsonWriter m_writer;
|
||||
private readonly JsonWriter m_writer;
|
||||
private long m_filecount;
|
||||
private long m_foldercount;
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Duplicati.Library.Main.Volumes
|
||||
|
||||
private class IndexBlockVolumeEnumerable : IEnumerable<IIndexBlockVolume>
|
||||
{
|
||||
private ICompression m_compression;
|
||||
private readonly ICompression m_compression;
|
||||
|
||||
public IndexBlockVolumeEnumerable(ICompression compression)
|
||||
{
|
||||
@@ -41,8 +41,8 @@ namespace Duplicati.Library.Main.Volumes
|
||||
{
|
||||
private class BlockEnumerator : IEnumerator<KeyValuePair<string, long>>
|
||||
{
|
||||
private ICompression m_compression;
|
||||
private string m_filename;
|
||||
private readonly ICompression m_compression;
|
||||
private readonly string m_filename;
|
||||
private KeyValuePair<string, long>? m_current;
|
||||
private System.IO.StreamReader m_stream;
|
||||
private JsonReader m_reader;
|
||||
@@ -139,8 +139,8 @@ namespace Duplicati.Library.Main.Volumes
|
||||
}
|
||||
}
|
||||
|
||||
private ICompression m_compression;
|
||||
private string m_filename;
|
||||
private readonly ICompression m_compression;
|
||||
private readonly string m_filename;
|
||||
private BlockEnumerator m_enumerator;
|
||||
|
||||
public BlockEnumerable(ICompression compression, string filename)
|
||||
@@ -173,8 +173,8 @@ namespace Duplicati.Library.Main.Volumes
|
||||
|
||||
private class IndexBlockVolume : IIndexBlockVolume
|
||||
{
|
||||
private ICompression m_compression;
|
||||
private string m_filename;
|
||||
private readonly ICompression m_compression;
|
||||
private readonly string m_filename;
|
||||
private long? m_length;
|
||||
private string m_hash;
|
||||
private BlockEnumerable m_blocks;
|
||||
@@ -231,7 +231,7 @@ namespace Duplicati.Library.Main.Volumes
|
||||
}
|
||||
}
|
||||
|
||||
private ICompression m_compression;
|
||||
private readonly ICompression m_compression;
|
||||
private IndexBlockVolume m_current;
|
||||
private string[] m_files;
|
||||
private long m_index;
|
||||
@@ -284,8 +284,8 @@ namespace Duplicati.Library.Main.Volumes
|
||||
|
||||
private class IndexBlocklistEnumerable : IEnumerable<IIndexBlocklist>
|
||||
{
|
||||
private ICompression m_compression;
|
||||
private long m_hashsize;
|
||||
private readonly ICompression m_compression;
|
||||
private readonly long m_hashsize;
|
||||
|
||||
public IndexBlocklistEnumerable(ICompression compression, long hashsize)
|
||||
{
|
||||
@@ -297,10 +297,10 @@ namespace Duplicati.Library.Main.Volumes
|
||||
{
|
||||
private class IndexBlocklist : IIndexBlocklist
|
||||
{
|
||||
private ICompression m_compression;
|
||||
private string m_filename;
|
||||
private long m_size;
|
||||
private long m_hashsize;
|
||||
private readonly ICompression m_compression;
|
||||
private readonly string m_filename;
|
||||
private readonly long m_size;
|
||||
private readonly long m_hashsize;
|
||||
|
||||
public IndexBlocklist(ICompression compression, string filename, long size, long hashsize)
|
||||
{
|
||||
@@ -333,11 +333,11 @@ namespace Duplicati.Library.Main.Volumes
|
||||
}
|
||||
}
|
||||
|
||||
private ICompression m_compression;
|
||||
private readonly ICompression m_compression;
|
||||
private long m_index;
|
||||
private KeyValuePair<string, long>[] m_files;
|
||||
private IndexBlocklist m_current;
|
||||
private long m_hashsize;
|
||||
private readonly long m_hashsize;
|
||||
|
||||
public IndexBlocklistEnumerator(ICompression compression, long hashsize)
|
||||
{
|
||||
@@ -386,7 +386,7 @@ namespace Duplicati.Library.Main.Volumes
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.GetEnumerator(); }
|
||||
}
|
||||
|
||||
private long m_hashsize;
|
||||
private readonly long m_hashsize;
|
||||
|
||||
public IndexVolumeReader(ICompression compression, Options options, long hashsize)
|
||||
: base(compression, options)
|
||||
|
||||
@@ -59,11 +59,11 @@ namespace Duplicati.Library.Snapshots
|
||||
/// <summary>
|
||||
/// The path that is mapped to the drive
|
||||
/// </summary>
|
||||
private string m_targetPath;
|
||||
private readonly string m_targetPath;
|
||||
/// <summary>
|
||||
/// A value indicating if the shell should be notified of changes
|
||||
/// </summary>
|
||||
private bool m_shellBroadcast;
|
||||
private readonly bool m_shellBroadcast;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the drive that this mapping represents
|
||||
|
||||
@@ -89,7 +89,7 @@ namespace Duplicati.Library.Snapshots
|
||||
/// Enumerated Hyper-V guests
|
||||
/// </summary>
|
||||
public List<HyperVGuest> Guests { get { return m_Guests; } }
|
||||
private List<HyperVGuest> m_Guests;
|
||||
private readonly List<HyperVGuest> m_Guests;
|
||||
|
||||
public HyperVUtility()
|
||||
{
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace Duplicati.Library.Snapshots
|
||||
/// Enumerated MS SQL DBs
|
||||
/// </summary>
|
||||
public List<MSSQLDB> DBs { get { return m_DBs; } }
|
||||
private List<MSSQLDB> m_DBs;
|
||||
private readonly List<MSSQLDB> m_DBs;
|
||||
|
||||
public MSSQLUtility()
|
||||
{
|
||||
|
||||
@@ -153,7 +153,7 @@ namespace Duplicati.Library.Snapshots
|
||||
{
|
||||
if (r.UsnRecord.Usn >= minUsn
|
||||
&& (reason == ChangeReason.Any || (MapChangeReason(r.UsnRecord.Reason) & reason) != 0)
|
||||
&& (r.FullPath.Equals(sourceFileOrFolder, Utility.Utility.ClientFilenameStringComparision)
|
||||
&& (r.FullPath.Equals(sourceFileOrFolder, Utility.Utility.ClientFilenameStringComparison)
|
||||
|| isFolder && Utility.Utility.IsPathBelowFolder(r.FullPath, sourceFileOrFolder)))
|
||||
{
|
||||
yield return Tuple.Create(r.FullPath,
|
||||
@@ -242,7 +242,7 @@ namespace Duplicati.Library.Snapshots
|
||||
{
|
||||
private readonly IReadOnlyCollection<byte> m_entryData;
|
||||
private readonly IntPtr m_bufferPointer;
|
||||
private GCHandle m_bufferHandle;
|
||||
private readonly GCHandle m_bufferHandle;
|
||||
private long m_offset;
|
||||
|
||||
public RecordEnumeratorImpl(IReadOnlyCollection<byte> entryData)
|
||||
|
||||
@@ -387,7 +387,7 @@ namespace Duplicati.Library.Snapshots
|
||||
|
||||
foreach (var folder in volumeData.Folders)
|
||||
{
|
||||
if (path.Equals(folder, Utility.Utility.ClientFilenameStringComparision))
|
||||
if (path.Equals(folder, Utility.Utility.ClientFilenameStringComparison))
|
||||
return true; // do not append from previous set, already scanned
|
||||
|
||||
if (Utility.Utility.IsPathBelowFolder(path, folder))
|
||||
|
||||
@@ -392,7 +392,7 @@ namespace Duplicati.Library.Snapshots
|
||||
|
||||
foreach (var kvp in m_volumeReverseMap)
|
||||
{
|
||||
if (snapshotPath.StartsWith(kvp.Key, Utility.Utility.ClientFilenameStringComparision))
|
||||
if (snapshotPath.StartsWith(kvp.Key, Utility.Utility.ClientFilenameStringComparison))
|
||||
return Path.Combine(kvp.Value, snapshotPath.Substring(kvp.Key.Length));
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Duplicati.Library.Utility
|
||||
/// <summary>
|
||||
/// The <see cref="System.Net.HttpWebRequest"/> method being wrapped
|
||||
/// </summary>
|
||||
private WebRequest m_request;
|
||||
private readonly WebRequest m_request;
|
||||
/// <summary>
|
||||
/// The current internal state of the object
|
||||
/// </summary>
|
||||
@@ -37,7 +37,7 @@ namespace Duplicati.Library.Utility
|
||||
/// <summary>
|
||||
/// The activity timeout value
|
||||
/// </summary>
|
||||
private int m_activity_timeout = (int)TimeSpan.FromSeconds(30).TotalMilliseconds;
|
||||
private readonly int m_activity_timeout = (int)TimeSpan.FromSeconds(30).TotalMilliseconds;
|
||||
|
||||
/// <summary>
|
||||
/// List of valid states
|
||||
@@ -186,13 +186,13 @@ namespace Duplicati.Library.Utility
|
||||
/// </summary>
|
||||
private class AsyncWrapper
|
||||
{
|
||||
private IAsyncResult m_async = null;
|
||||
private readonly IAsyncResult m_async = null;
|
||||
private Stream m_stream = null;
|
||||
private WebResponse m_response = null;
|
||||
private AsyncHttpRequest m_owner;
|
||||
private readonly AsyncHttpRequest m_owner;
|
||||
private Exception m_exception = null;
|
||||
private ManualResetEvent m_event = new ManualResetEvent(false);
|
||||
private bool m_isRequest;
|
||||
private readonly ManualResetEvent m_event = new ManualResetEvent(false);
|
||||
private readonly bool m_isRequest;
|
||||
private bool m_timedout = false;
|
||||
|
||||
public AsyncWrapper(AsyncHttpRequest owner, bool isRequest)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user