diff --git a/Duplicati/Library/Main/Options.cs b/Duplicati/Library/Main/Options.cs index 06b4dc3b3..00faf6981 100644 --- a/Duplicati/Library/Main/Options.cs +++ b/Duplicati/Library/Main/Options.cs @@ -1,2077 +1,2077 @@ -#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.Linq; -using System.Collections.Generic; -using Duplicati.Library.Interface; -using Duplicati.Library.Utility; -using System.Globalization; - -namespace Duplicati.Library.Main -{ - /// - /// A class for keeping all Duplicati options in one place, - /// and provide typesafe access to the options - /// - public class Options - { - private const string DEFAULT_BLOCK_HASH_ALGORITHM = "SHA256"; - private const string DEFAULT_FILE_HASH_ALGORITHM = "SHA256"; - - /// - /// The default block size - /// - private const string DEFAULT_BLOCKSIZE = "100kb"; - - /// - /// The default size of the read-ahead buffer - /// - private const string DEFAULT_READ_BUFFER_SIZE = "5mb"; - - /// - /// The default threshold value - /// - private const long DEFAULT_THRESHOLD = 25; - - /// - /// The default value for maximum number of small files - /// - private const long DEFAULT_SMALL_FILE_MAX_COUNT = 20; - - /// - /// Default size of volumes - /// - private const string DEFAULT_VOLUME_SIZE = "50mb"; - - /// - /// Default value for keep-versions - /// - private const int DEFAULT_KEEP_VERSIONS = 0; - - /// - /// The default threshold for purging log data - /// - private const string DEFAULT_LOG_RETENTION = "30D"; - - /// - /// The default number of compressor instances - /// - private readonly int DEFAULT_COMPRESSORS = Math.Max(1, Environment.ProcessorCount / 2); - - /// - /// The default number of hasher instances - /// - private readonly int DEFAULT_BLOCK_HASHERS = Math.Max(1, Environment.ProcessorCount / 2); - - /// - /// The default threshold for warning about coming close to quota - /// - private const int DEFAULT_QUOTA_WARNING_THRESHOLD = 10; - - /// - /// An enumeration that describes the supported strategies for an optimization - /// - public enum OptimizationStrategy - { - /// - /// The optimization feature is created if possible, but silently ignored if it fails - /// - Auto, - /// - /// The optimization feature is created if possible, but an error is logged if it fails - /// - On, - /// - /// The optimization feature is deactivated - /// - Off, - /// - /// The optimization feature is created, and the backup is aborted if it fails - /// - Required - } - - /// - /// The possible settings for the symlink strategy - /// - public enum SymlinkStrategy - { - /// - /// Store information about the symlink - /// - Store, - - /// - /// Treat symlinks as normal files or folders - /// - Follow, - - /// - /// Ignore all symlinks - /// - Ignore - } - - /// - /// The possible settings for the hardlink strategy - /// - public enum HardlinkStrategy - { - /// - /// Process only the first hardlink - /// - First, - - /// - /// Process all hardlinks - /// - All, - - /// - /// Ignore all hardlinks - /// - None - } - - /// - /// The possible settings for index file usage - /// - public enum IndexFileStrategy - { - /// - /// Disables usage of index files - /// - None, - - /// - /// Stores only block lookup information in the index files - /// - Lookup, - - /// - /// Stores both block lookup and block lists in the index files - /// - Full - - } - - private static string[] GetSupportedHashes() - { - var r = new List(); - foreach (var h in new string[] { "SHA1", "MD5", "SHA256", "SHA384", "SHA512" }) - { - try - { - var p = System.Security.Cryptography.HashAlgorithm.Create(h); - if (p != null) - r.Add(h); - } - catch - { - } - } - - return r.ToArray(); - } - - private static readonly string DEFAULT_COMPRESSED_EXTENSION_FILE = System.IO.Path.Combine(Duplicati.Library.AutoUpdater.UpdaterManager.InstalledBaseDir, "default_compressed_extensions.txt"); - - /// - /// Lock that protects the options collection - /// - protected readonly object m_lock = new object(); - - protected Dictionary m_options; - - protected List> m_loadedModules = new List>(); - - /// - /// Lookup table for compression hints - /// - private Dictionary m_compressionHints; - - public Options(Dictionary options) - { - m_options = options; - } - - public Dictionary RawOptions { get { return m_options; } } - - /// - /// Returns a list of strings that are not supported on the commandline as options, but used internally - /// - public static string[] InternalOptions - { - get - { - return new string[] { - "main-action" - }; - } - } - - /// - /// Returns a list of options that are intentionally duplicate - /// - public static string[] KnownDuplicates - { - get { return new string[] { "auth-password", "auth-username" }; } - } - - /// - /// A default backup name - /// - public static string DefaultBackupName - { - get - { - return System.IO.Path.GetFileNameWithoutExtension(Library.Utility.Utility.getEntryAssembly().Location); - } - } - - /// - /// Gets all supported commands - /// - public IList SupportedCommands - { - get - { - var lst = new List(new ICommandLineArgument[] { - new CommandLineArgument("dblock-size", CommandLineArgument.ArgumentType.Size, Strings.Options.DblocksizeShort, Strings.Options.DblocksizeLong, DEFAULT_VOLUME_SIZE), - new CommandLineArgument("auto-cleanup", CommandLineArgument.ArgumentType.Boolean, Strings.Options.AutocleanupShort, Strings.Options.AutocleanupLong, "false"), - new CommandLineArgument("unittest-mode", CommandLineArgument.ArgumentType.Boolean, Strings.Options.UnittestmodeShort, Strings.Options.UnittestmodeLong, "false"), - - new CommandLineArgument("control-files", CommandLineArgument.ArgumentType.Path, Strings.Options.ControlfilesShort, Strings.Options.ControlfilesLong), - new CommandLineArgument("skip-file-hash-checks", CommandLineArgument.ArgumentType.Boolean, Strings.Options.SkipfilehashchecksShort, Strings.Options.SkipfilehashchecksLong, "false"), - new CommandLineArgument("dont-read-manifests", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DontreadmanifestsShort, Strings.Options.DontreadmanifestsLong, "false"), - new CommandLineArgument("restore-path", CommandLineArgument.ArgumentType.String, Strings.Options.RestorepathShort, Strings.Options.RestorepathLong), - new CommandLineArgument("time", CommandLineArgument.ArgumentType.Timespan, Strings.Options.TimeShort, Strings.Options.TimeLong, "now"), - new CommandLineArgument("version", CommandLineArgument.ArgumentType.String, Strings.Options.VersionShort, Strings.Options.VersionLong, ""), - new CommandLineArgument("all-versions", CommandLineArgument.ArgumentType.Boolean, Strings.Options.AllversionsShort, Strings.Options.AllversionsLong, "false"), - new CommandLineArgument("list-prefix-only", CommandLineArgument.ArgumentType.Boolean, Strings.Options.ListprefixonlyShort, Strings.Options.ListprefixonlyLong, "false"), - new CommandLineArgument("list-folder-contents", CommandLineArgument.ArgumentType.Boolean, Strings.Options.ListfoldercontentsShort, Strings.Options.ListfoldercontentsLong, "false"), - new CommandLineArgument("list-sets-only", CommandLineArgument.ArgumentType.Boolean, Strings.Options.ListsetsonlyShort, Strings.Options.ListsetsonlyLong, "false"), - new CommandLineArgument("disable-autocreate-folder", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisableautocreatefolderShort, Strings.Options.DisableautocreatefolderLong, "false"), - new CommandLineArgument("allow-missing-source", CommandLineArgument.ArgumentType.Boolean, Strings.Options.AllowmissingsourceShort, Strings.Options.AllowmissingsourceLong, "false"), - - new CommandLineArgument("disable-filetime-check", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisablefiletimecheckShort, Strings.Options.DisablefiletimecheckLong, "false"), - new CommandLineArgument("check-filetime-only", CommandLineArgument.ArgumentType.Boolean, Strings.Options.CheckfiletimeonlyShort, Strings.Options.CheckfiletimeonlyLong, "false"), - //new CommandLineArgument("disable-usn-diff-check", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisableusndiffcheckShort, Strings.Options.DisableusndiffcheckLong, "false"), - new CommandLineArgument("disable-time-tolerance", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisabletimetoleranceShort, Strings.Options.DisabletimetoleranceLong, "false"), - - new CommandLineArgument("tempdir", CommandLineArgument.ArgumentType.Path, Strings.Options.TempdirShort, Strings.Options.TempdirLong, System.IO.Path.GetTempPath()), - new CommandLineArgument("thread-priority", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.ThreadpriorityShort, Strings.Options.ThreadpriorityLong, "normal", null, new string[] {"highest", "high", "abovenormal", "normal", "belownormal", "low", "lowest", "idle" }), - - new CommandLineArgument("prefix", CommandLineArgument.ArgumentType.String, Strings.Options.PrefixShort, Strings.Options.PrefixLong, "duplicati"), - - new CommandLineArgument("passphrase", CommandLineArgument.ArgumentType.Password, Strings.Options.PassphraseShort, Strings.Options.PassphraseLong), - new CommandLineArgument("no-encryption", CommandLineArgument.ArgumentType.Boolean, Strings.Options.NoencryptionShort, Strings.Options.NoencryptionLong, "false"), - - new CommandLineArgument("number-of-retries", CommandLineArgument.ArgumentType.Integer, Strings.Options.NumberofretriesShort, Strings.Options.NumberofretriesLong, "5"), - new CommandLineArgument("retry-delay", CommandLineArgument.ArgumentType.Timespan, Strings.Options.RetrydelayShort, Strings.Options.RetrydelayLong, "10s"), - - new CommandLineArgument("synchronous-upload", CommandLineArgument.ArgumentType.Boolean, Strings.Options.SynchronousuploadShort, Strings.Options.SynchronousuploadLong, "false"), - new CommandLineArgument("asynchronous-upload-limit", CommandLineArgument.ArgumentType.Integer, Strings.Options.AsynchronousuploadlimitShort, Strings.Options.AsynchronousuploadlimitLong, "4"), - new CommandLineArgument("asynchronous-concurrent-upload-limit", CommandLineArgument.ArgumentType.Integer, Strings.Options.AsynchronousconcurrentuploadlimitShort, Strings.Options.AsynchronousconcurrentuploadlimitLong, "4"), - new CommandLineArgument("asynchronous-upload-folder", CommandLineArgument.ArgumentType.Path, Strings.Options.AsynchronousuploadfolderShort, Strings.Options.AsynchronousuploadfolderLong, System.IO.Path.GetTempPath()), - - new CommandLineArgument("disable-streaming-transfers", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisableStreamingShort, Strings.Options.DisableStreamingLong, "false"), - - new CommandLineArgument("throttle-upload", CommandLineArgument.ArgumentType.Size, Strings.Options.ThrottleuploadShort, Strings.Options.ThrottleuploadLong, "0kb"), - new CommandLineArgument("throttle-download", CommandLineArgument.ArgumentType.Size, Strings.Options.ThrottledownloadShort, Strings.Options.ThrottledownloadLong, "0kb"), - new CommandLineArgument("skip-files-larger-than", CommandLineArgument.ArgumentType.Size, Strings.Options.SkipfileslargerthanShort, Strings.Options.SkipfileslargerthanLong), - - new CommandLineArgument("upload-unchanged-backups", CommandLineArgument.ArgumentType.Boolean, Strings.Options.UploadUnchangedBackupsShort, Strings.Options.UploadUnchangedBackupsLong, "false"), - - new CommandLineArgument("snapshot-policy", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.SnapshotpolicyShort, Strings.Options.SnapshotpolicyLong, "off", null, Enum.GetNames(typeof(OptimizationStrategy))), - new CommandLineArgument("vss-exclude-writers", CommandLineArgument.ArgumentType.String, Strings.Options.VssexcludewritersShort, Strings.Options.VssexcludewritersLong, "{e8132975-6f93-4464-a53e-1050253ae220}"), - new CommandLineArgument("vss-use-mapping", CommandLineArgument.ArgumentType.Boolean, Strings.Options.VssusemappingShort, Strings.Options.VssusemappingLong, "false"), - new CommandLineArgument("usn-policy", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.UsnpolicyShort, Strings.Options.UsnpolicyLong, "off", null, Enum.GetNames(typeof(OptimizationStrategy))), - - new CommandLineArgument("encryption-module", CommandLineArgument.ArgumentType.String, Strings.Options.EncryptionmoduleShort, Strings.Options.EncryptionmoduleLong, "aes"), - new CommandLineArgument("compression-module", CommandLineArgument.ArgumentType.String, Strings.Options.CompressionmoduleShort, Strings.Options.CompressionmoduleLong, "zip"), - - new CommandLineArgument("enable-module", CommandLineArgument.ArgumentType.String, Strings.Options.EnablemoduleShort, Strings.Options.EnablemoduleLong), - new CommandLineArgument("disable-module", CommandLineArgument.ArgumentType.String, Strings.Options.DisablemoduleShort, Strings.Options.DisablemoduleLong), - - new CommandLineArgument("debug-output", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DebugoutputShort, Strings.Options.DebugoutputLong, "false"), - new CommandLineArgument("debug-retry-errors", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DebugretryerrorsShort, Strings.Options.DebugretryerrorsLong, "false"), - - new CommandLineArgument("log-file", CommandLineArgument.ArgumentType.Path, Strings.Options.LogfileShort, Strings.Options.LogfileLong), - new CommandLineArgument("log-file-log-level", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.LogfileloglevelShort, Strings.Options.LogfileloglevelShort, "Warning", null, Enum.GetNames(typeof(Duplicati.Library.Logging.LogMessageType))), - new CommandLineArgument("log-file-log-filter", CommandLineArgument.ArgumentType.String, Strings.Options.LogfilelogfiltersShort, Strings.Options.LogfilelogfiltersLong(System.IO.Path.PathSeparator.ToString()), null), - - new CommandLineArgument("console-log-level", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.ConsoleloglevelShort, Strings.Options.ConsoleloglevelShort, "Warning", null, Enum.GetNames(typeof(Duplicati.Library.Logging.LogMessageType))), - new CommandLineArgument("console-log-filter", CommandLineArgument.ArgumentType.String, Strings.Options.ConsolelogfiltersShort, Strings.Options.ConsolelogfiltersLong(System.IO.Path.PathSeparator.ToString()), null), - - new CommandLineArgument("log-level", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.LoglevelShort, Strings.Options.LoglevelLong, "Warning", null, Enum.GetNames(typeof(Duplicati.Library.Logging.LogMessageType)), Strings.Options.LogLevelDeprecated("log-file-log-level", "console-log-level")), - - new CommandLineArgument("profile-all-database-queries", CommandLineArgument.ArgumentType.Boolean, Strings.Options.ProfilealldatabasequeriesShort, Strings.Options.ProfilealldatabasequeriesLong, "false"), - - new CommandLineArgument("list-verify-uploads", CommandLineArgument.ArgumentType.Boolean, Strings.Options.ListverifyuploadsShort, Strings.Options.ListverifyuploadsShort, "false"), - new CommandLineArgument("allow-sleep", CommandLineArgument.ArgumentType.Boolean, Strings.Options.AllowsleepShort, Strings.Options.AllowsleepLong, "false"), - new CommandLineArgument("use-background-io-priority", CommandLineArgument.ArgumentType.Boolean, Strings.Options.UsebackgroundiopriorityShort, Strings.Options.UsebackgroundiopriorityLong, "false"), - new CommandLineArgument("no-connection-reuse", CommandLineArgument.ArgumentType.Boolean, Strings.Options.NoconnectionreuseShort, Strings.Options.NoconnectionreuseLong, "false"), - - new CommandLineArgument("quota-size", CommandLineArgument.ArgumentType.Size, Strings.Options.QuotasizeShort, Strings.Options.QuotasizeLong), - new CommandLineArgument("quota-warning-threshold", CommandLineArgument.ArgumentType.Integer, Strings.Options.QuotaWarningThresholdShort, Strings.Options.QuotaWarningThresholdLong, DEFAULT_QUOTA_WARNING_THRESHOLD.ToString()), - - new CommandLineArgument("symlink-policy", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.SymlinkpolicyShort, Strings.Options.SymlinkpolicyLong("store", "ignore", "follow"), Enum.GetName(typeof(SymlinkStrategy), SymlinkStrategy.Store), null, Enum.GetNames(typeof(SymlinkStrategy))), - new CommandLineArgument("hardlink-policy", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.HardlinkpolicyShort, Strings.Options.HardlinkpolicyLong("first", "all", "none"), Enum.GetName(typeof(HardlinkStrategy), HardlinkStrategy.All), null, Enum.GetNames(typeof(HardlinkStrategy))), - new CommandLineArgument("exclude-files-attributes", CommandLineArgument.ArgumentType.String, Strings.Options.ExcludefilesattributesShort, Strings.Options.ExcludefilesattributesLong(Enum.GetNames(typeof(System.IO.FileAttributes)))), - new CommandLineArgument("backup-name", CommandLineArgument.ArgumentType.String, Strings.Options.BackupnameShort, Strings.Options.BackupnameLong, DefaultBackupName), - new CommandLineArgument("compression-extension-file", CommandLineArgument.ArgumentType.Path, Strings.Options.CompressionextensionfileShort, Strings.Options.CompressionextensionfileLong(DEFAULT_COMPRESSED_EXTENSION_FILE), DEFAULT_COMPRESSED_EXTENSION_FILE), - - new CommandLineArgument("verbose", CommandLineArgument.ArgumentType.Boolean, Strings.Options.VerboseShort, Strings.Options.VerboseLong, "false", null, null, Strings.Options.VerboseDeprecated), - new CommandLineArgument("full-result", CommandLineArgument.ArgumentType.Boolean, Strings.Options.FullresultShort, Strings.Options.FullresultLong, "false"), - - new CommandLineArgument("overwrite", CommandLineArgument.ArgumentType.Boolean, Strings.Options.OverwriteShort, Strings.Options.OverwriteLong, "false"), - - new CommandLineArgument("dbpath", CommandLineArgument.ArgumentType.Path, Strings.Options.DbpathShort, Strings.Options.DbpathLong), - new CommandLineArgument("blocksize", CommandLineArgument.ArgumentType.Size, Strings.Options.BlocksizeShort, Strings.Options.BlocksizeLong, DEFAULT_BLOCKSIZE), - new CommandLineArgument("file-read-buffer-size", CommandLineArgument.ArgumentType.Size, Strings.Options.FilereadbuffersizeShort, Strings.Options.FilereadbuffersizeLong, "0kb"), - new CommandLineArgument("skip-metadata", CommandLineArgument.ArgumentType.Boolean, Strings.Options.SkipmetadataShort, Strings.Options.SkipmetadataLong, "false"), - new CommandLineArgument("restore-permissions", CommandLineArgument.ArgumentType.Boolean, Strings.Options.RestorepermissionsShort, Strings.Options.RestorepermissionsLong, "false"), - new CommandLineArgument("skip-restore-verification", CommandLineArgument.ArgumentType.Boolean, Strings.Options.SkiprestoreverificationShort, Strings.Options.SkiprestoreverificationLong, "false"), - new CommandLineArgument("disable-filepath-cache", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisablefilepathcacheShort, Strings.Options.DisablefilepathcacheLong, "true", null, null, Strings.Options.VerboseDeprecated), - new CommandLineArgument("use-block-cache", CommandLineArgument.ArgumentType.Boolean, Strings.Options.UseblockcacheShort, Strings.Options.UseblockcacheLong, "false"), - new CommandLineArgument("changed-files", CommandLineArgument.ArgumentType.Path, Strings.Options.ChangedfilesShort, Strings.Options.ChangedfilesLong), - new CommandLineArgument("deleted-files", CommandLineArgument.ArgumentType.Path, Strings.Options.DeletedfilesShort, Strings.Options.DeletedfilesLong("changed-files")), - new CommandLineArgument("disable-synthetic-filelist", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisablesyntheticfilelistShort, Strings.Options.DisablesyntehticfilelistLong, "false"), - - new CommandLineArgument("threshold", CommandLineArgument.ArgumentType.Integer, Strings.Options.ThresholdShort, Strings.Options.ThresholdLong, DEFAULT_THRESHOLD.ToString()), - new CommandLineArgument("index-file-policy", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.IndexfilepolicyShort, Strings.Options.IndexfilepolicyLong, IndexFileStrategy.Full.ToString(), null, Enum.GetNames(typeof(IndexFileStrategy))), - new CommandLineArgument("no-backend-verification", CommandLineArgument.ArgumentType.Boolean, Strings.Options.NobackendverificationShort, Strings.Options.NobackendverificationLong, "false"), - new CommandLineArgument("backup-test-samples", CommandLineArgument.ArgumentType.Integer, Strings.Options.BackendtestsamplesShort, Strings.Options.BackendtestsamplesLong("no-backend-verification"), "1"), - new CommandLineArgument("backup-test-percentage", CommandLineArgument.ArgumentType.Integer, Strings.Options.BackendtestpercentageShort, Strings.Options.BackendtestpercentageLong, "0"), - new CommandLineArgument("full-remote-verification", CommandLineArgument.ArgumentType.Boolean, Strings.Options.FullremoteverificationShort, Strings.Options.FullremoteverificationLong("no-backend-verification"), "false"), - new CommandLineArgument("dry-run", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DryrunShort, Strings.Options.DryrunLong, "false", new string[] { "dryrun" }), - - new CommandLineArgument("block-hash-algorithm", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.BlockhashalgorithmShort, Strings.Options.BlockhashalgorithmLong, DEFAULT_BLOCK_HASH_ALGORITHM, null, GetSupportedHashes()), - new CommandLineArgument("file-hash-algorithm", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.FilehashalgorithmShort, Strings.Options.FilehashalgorithmLong, DEFAULT_FILE_HASH_ALGORITHM, null, GetSupportedHashes()), - - new CommandLineArgument("no-auto-compact", CommandLineArgument.ArgumentType.Boolean, Strings.Options.NoautocompactShort, Strings.Options.NoautocompactLong, "false"), - new CommandLineArgument("small-file-size", CommandLineArgument.ArgumentType.Size, Strings.Options.SmallfilesizeShort, Strings.Options.SmallfilesizeLong), - new CommandLineArgument("small-file-max-count", CommandLineArgument.ArgumentType.Integer, Strings.Options.SmallfilemaxcountShort, Strings.Options.SmallfilemaxcountLong, DEFAULT_SMALL_FILE_MAX_COUNT.ToString()), - - new CommandLineArgument("patch-with-local-blocks", CommandLineArgument.ArgumentType.Boolean, Strings.Options.PatchwithlocalblocksShort, Strings.Options.PatchwithlocalblocksLong, "false"), - new CommandLineArgument("no-local-db", CommandLineArgument.ArgumentType.Boolean, Strings.Options.NolocaldbShort, Strings.Options.NolocaldbLong, "false"), - new CommandLineArgument("dont-compress-restore-paths", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DontcompressrestorepathsShort, Strings.Options.DontcompressrestorepathsLong, "false"), - - new CommandLineArgument("keep-versions", CommandLineArgument.ArgumentType.Integer, Strings.Options.KeepversionsShort, Strings.Options.KeepversionsLong, DEFAULT_KEEP_VERSIONS.ToString()), - new CommandLineArgument("keep-time", CommandLineArgument.ArgumentType.Timespan, Strings.Options.KeeptimeShort, Strings.Options.KeeptimeLong), - new CommandLineArgument("retention-policy", CommandLineArgument.ArgumentType.String, Strings.Options.RetentionPolicyShort, Strings.Options.RetentionPolicyLong), - new CommandLineArgument("upload-verification-file", CommandLineArgument.ArgumentType.Boolean, Strings.Options.UploadverificationfileShort, Strings.Options.UploadverificationfileLong, "false"), - new CommandLineArgument("allow-passphrase-change", CommandLineArgument.ArgumentType.Boolean, Strings.Options.AllowpassphrasechangeShort, Strings.Options.AllowpassphrasechangeLong, "false"), - new CommandLineArgument("no-local-blocks", CommandLineArgument.ArgumentType.Boolean, Strings.Options.NolocalblocksShort, Strings.Options.NolocalblocksLong, "false"), - new CommandLineArgument("full-block-verification", CommandLineArgument.ArgumentType.Boolean, Strings.Options.FullblockverificationShort, Strings.Options.FullblockverificationLong, "false"), - new CommandLineArgument("allow-full-removal", CommandLineArgument.ArgumentType.Boolean, Strings.Options.AllowfullremovalShort, Strings.Options.AllowfullremovalLong, "false"), - - new CommandLineArgument("log-retention", CommandLineArgument.ArgumentType.Timespan, Strings.Options.LogretentionShort, Strings.Options.LogretentionLong, DEFAULT_LOG_RETENTION), - - new CommandLineArgument("repair-only-paths", CommandLineArgument.ArgumentType.Boolean, Strings.Options.RepaironlypathsShort, Strings.Options.RepaironlypathsLong, "false"), - new CommandLineArgument("force-locale", CommandLineArgument.ArgumentType.String, Strings.Options.ForcelocaleShort, Strings.Options.ForcelocaleLong), - - new CommandLineArgument("disable-piped-streaming", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisablepipingShort, Strings.Options.DisablepipingLong, "false"), - - new CommandLineArgument("concurrency-max-threads", CommandLineArgument.ArgumentType.Integer, Strings.Options.ConcurrencymaxthreadsShort, Strings.Options.ConcurrencymaxthreadsLong, "0"), - new CommandLineArgument("concurrency-block-hashers", CommandLineArgument.ArgumentType.Integer, Strings.Options.ConcurrencyblockhashersShort, Strings.Options.ConcurrencyblockhashersLong, DEFAULT_BLOCK_HASHERS.ToString()), - new CommandLineArgument("concurrency-compressors", CommandLineArgument.ArgumentType.Integer, Strings.Options.ConcurrencycompressorsShort, Strings.Options.ConcurrencycompressorsLong, DEFAULT_COMPRESSORS.ToString()), - - new CommandLineArgument("auto-vacuum", CommandLineArgument.ArgumentType.Boolean, Strings.Options.AutoVacuumShort, Strings.Options.AutoVacuumLong, "false"), - new CommandLineArgument("disable-file-scanner", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisablefilescannerShort, Strings.Options.DisablefilescannerLong, "false"), - new CommandLineArgument("disable-filelist-consistency-checks", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisablefilelistconsistencychecksShort, Strings.Options.DisablefilelistconsistencychecksLong, "false"), - new CommandLineArgument("disable-on-battery", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisableOnBatteryShort, Strings.Options.DisableOnBatteryLong, "false"), - - new CommandLineArgument("exclude-empty-folders", CommandLineArgument.ArgumentType.Boolean, Strings.Options.ExcludeemptyfoldersShort, Strings.Options.ExcludeemptyfoldersLong, "false"), - new CommandLineArgument("ignore-filenames", CommandLineArgument.ArgumentType.Path, Strings.Options.IgnorefilenamesShort, Strings.Options.IgnorefilenamesLong), - new CommandLineArgument("restore-symlink-metadata", CommandLineArgument.ArgumentType.Boolean, Strings.Options.RestoresymlinkmetadataShort, Strings.Options.RestoresymlinkmetadataLong, "false"), - new CommandLineArgument("rebuild-missing-dblock-files", CommandLineArgument.ArgumentType.Boolean, Strings.Options.RebuildmissingdblockfilesShort, Strings.Options.RebuildmissingdblockfilesLong, "false"), - - new CommandLineArgument("auto-compact-interval", CommandLineArgument.ArgumentType.Timespan, Strings.Options.AutoCompactIntervalShort, Strings.Options.AutoCompactIntervalLong, "0m"), - new CommandLineArgument("auto-vacuum-interval", CommandLineArgument.ArgumentType.Timespan, Strings.Options.AutoVacuumIntervalShort, Strings.Options.AutoVacuumIntervalLong, "0m"), - }); - - return lst; - } - } - - /// - /// Gets or sets the current main action of the instance - /// - public OperationMode MainAction - { - get { return (OperationMode)Enum.Parse(typeof(OperationMode), m_options["main-action"]); } - set { m_options["main-action"] = value.ToString(); } - } - - /// - /// Gets the size of each volume in bytes - /// - public long VolumeSize - { - get - { - string volsize; - m_options.TryGetValue("dblock-size", out volsize); - if (string.IsNullOrEmpty(volsize)) - volsize = DEFAULT_VOLUME_SIZE; - -#if DEBUG - return Math.Max(1024 * 10, Library.Utility.Sizeparser.ParseSize(volsize, "mb")); -#else - return Math.Max(1024 * 1024, Library.Utility.Sizeparser.ParseSize(volsize, "mb")); -#endif - } - } - - /// - /// Gets the maximum size of a single file - /// - public long SkipFilesLargerThan - { - get - { - if (!m_options.ContainsKey("skip-files-larger-than") || string.IsNullOrEmpty(m_options["skip-files-larger-than"])) - return long.MaxValue; - else - return Library.Utility.Sizeparser.ParseSize(m_options["skip-files-larger-than"], "mb"); - } - } - - /// - /// A value indicating if orphan files are deleted automatically - /// - public bool AutoCleanup { get { return GetBool("auto-cleanup"); } } - - /// - /// A value indicating if we are running in unittest mode - /// - public bool UnittestMode { get { return GetBool("unittest-mode"); } } - - - /// - /// Gets a list of files to add to the signature volumes - /// - public string ControlFiles - { - get - { - string v; - m_options.TryGetValue("control-files", out v); - return v; - } - } - - /// - /// A value indicating if file hash checks are skipped - /// - public bool SkipFileHashChecks { get { return GetBool("skip-file-hash-checks"); } } - - /// - /// A value indicating if the manifest files are not read - /// - public bool DontReadManifests { get { return GetBool("dont-read-manifests"); } } - - /// - /// Gets the backup that should be restored - /// - public DateTime Time - { - get - { - if (!m_options.ContainsKey("time") || string.IsNullOrEmpty(m_options["time"])) - return new DateTime(0, DateTimeKind.Utc); - else - return Library.Utility.Timeparser.ParseTimeInterval(m_options["time"], DateTime.Now); - } - } - - /// - /// Gets the versions the restore or list operation is limited to - /// - public long[] Version - { - get - { - string v; - m_options.TryGetValue("version", out v); - if (string.IsNullOrEmpty(v)) - return null; - - var versions = v.Split(new char[]{','}, StringSplitOptions.RemoveEmptyEntries); - if (v.Length == 0) - return null; - - var res = new List(); - foreach(var n in versions) - if (n.Contains('-')) - { - //TODO: Throw errors if too many entries? - var parts = n.Split(new char[]{'-'}, StringSplitOptions.RemoveEmptyEntries).Select(x => Convert.ToInt64(x.Trim())).ToArray(); - for(var i = Math.Min(parts[0], parts[1]); i <= Math.Max(parts[0], parts[1]); i++) - res.Add(i); - } - else - res.Add(Convert.ToInt64(n)); - - return res.ToArray(); - } - } - - /// - /// A value indicating if all versions are listed - /// - public bool AllVersions { get { return GetBool("all-versions"); } } - - /// - /// A value indicating if only the largest common prefix is returned - /// - public bool ListPrefixOnly { get { return GetBool("list-prefix-only"); } } - - /// - /// A value indicating if only folder contents are returned - /// - public bool ListFolderContents { get { return GetBool("list-folder-contents"); } } - - /// - /// A value indicating that only filesets are returned - /// - public bool ListSetsOnly { get { return GetBool("list-sets-only"); } } - - /// - /// A value indicating if file time checks are skipped - /// - public bool DisableFiletimeCheck { get { return GetBool("disable-filetime-check"); } } - - /// - /// A value indicating if file time checks are skipped - /// - public bool CheckFiletimeOnly { get { return GetBool("check-filetime-only"); } } - - /// - /// A value indicating if USN numbers are used to get list of changed files - /// - //public bool DisableUSNDiffCheck { get { return GetBool("disable-usn-diff-check"); } } - - /// - /// A value indicating if time tolerance is disabled - /// - public bool DisableTimeTolerance { get { return GetBool("disable-time-tolerance"); } } - - /// - /// Gets a value indicating whether a temporary folder has been specified - /// - public bool HasTempDir { get { return m_options.ContainsKey("tempdir") && !string.IsNullOrEmpty(m_options["tempdir"]); } } - - /// - /// Gets the folder where temporary files are stored - /// - public string TempDir - { - get - { - if (!m_options.ContainsKey("tempdir") || string.IsNullOrEmpty(m_options["tempdir"])) - { - return Duplicati.Library.Utility.TempFolder.SystemTempPath; - } - - return m_options["tempdir"]; - } - } - - - /// - /// Gets a value indicating whether the user has forced the locale - /// - public bool HasForcedLocale { get { return m_options.ContainsKey("force-locale"); } } - - /// - /// Gets the forced locale for the current user - /// - public System.Globalization.CultureInfo ForcedLocale - { - get - { - if (!m_options.ContainsKey("force-locale")) - return System.Threading.Thread.CurrentThread.CurrentCulture; - else - { - var localestring = m_options["force-locale"]; - if (string.IsNullOrWhiteSpace(localestring)) - return System.Globalization.CultureInfo.InvariantCulture; - else - return new System.Globalization.CultureInfo(localestring); - } - } - } - - /// - /// Gets the process priority - /// - public string ThreadPriority - { - get - { - if (!m_options.ContainsKey("thread-priority") || string.IsNullOrEmpty(m_options["thread-priority"])) - return null; - else - return m_options["thread-priority"]; - } - } - - /// - /// A value indicating if missing folders should be created automatically - /// - public bool AutocreateFolders { get { return !GetBool("disable-autocreate-folder"); } } - - /// - /// Gets the backup prefix - /// - public string Prefix - { - get - { - string v; - m_options.TryGetValue("prefix", out v); - if (!string.IsNullOrEmpty(v)) - return v; - - return "duplicati"; - } - } - - /// - /// Gets the number of old backups to keep - /// - public int KeepVersions - { - get - { - string v; - m_options.TryGetValue("keep-versions", out v); - if (string.IsNullOrEmpty(v)) - return DEFAULT_KEEP_VERSIONS; - - return Math.Max(0, int.Parse(v)); - } - } - - /// - /// Gets the timelimit for removal - /// - public DateTime KeepTime - { - get - { - string v; - m_options.TryGetValue("keep-time", out v); - - if (string.IsNullOrEmpty(v)) - return new DateTime(0); - - TimeSpan tolerance = - this.DisableTimeTolerance ? - TimeSpan.FromSeconds(0) : - TimeSpan.FromSeconds(Math.Min(Library.Utility.Timeparser.ParseTimeSpan(v).TotalSeconds / 100, 60.0 * 60.0)); - - return Library.Utility.Timeparser.ParseTimeInterval(v, DateTime.Now, true) - tolerance; - } - } - - /// - /// Gets the time frames and intervals for the retention policy - /// - public List RetentionPolicy - { - get { - var retentionPolicyConfig = new List(); - - string v; - m_options.TryGetValue("retention-policy", out v); - if (string.IsNullOrEmpty(v)) { - return retentionPolicyConfig; - } - - var periodIntervalStrings = v.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - - foreach (var periodIntervalString in periodIntervalStrings) - { - retentionPolicyConfig.Add(RetentionPolicyValue.CreateFromString(periodIntervalString)); - } - - return retentionPolicyConfig; - } - } - - /// - /// Gets the encryption passphrase - /// - public string Passphrase - { - get - { - if (!m_options.ContainsKey("passphrase") || string.IsNullOrEmpty(m_options["passphrase"])) - return null; - else - return m_options["passphrase"]; - } - } - - /// - /// Helper method to set the default encryption mode based on the settings of the previous backup - /// - /// The encryption module used for the last entry - public void SetEncryptionModuleDefault(string lastSetting) - { - //If the encryption module was specified explicitly, don't change it - if (m_options.ContainsKey("no-encryption") || m_options.ContainsKey("encryption-module")) - return; - - if (string.IsNullOrEmpty(lastSetting)) - m_options["no-encryption"] = ""; - else - m_options["encryption-module"] = lastSetting; - } - - /// - /// A value indicating if backups are not encrypted - /// - public bool NoEncryption { get { return GetBool("no-encryption"); } } - - /// - /// Gets the module used for encryption - /// - public string EncryptionModule - { - get - { - //Disabled? - if (NoEncryption) - return null; - - //Specified? - if (m_options.ContainsKey("encryption-module")) - return m_options["encryption-module"]; - - return "aes"; - } - } - - /// - /// Helper method to set the default compression mode based on the settings of the previous backup - /// - /// The compression module used for the last entry - public void SetCompressionModuleDefault(string lastSetting) - { - //If a compression module is explicitly selected, don't change it - if (m_options.ContainsKey("compression-module")) - return; - - m_options["compression-module"] = lastSetting; - } - - /// - /// Gets the module used for compression - /// - public string CompressionModule - { - get - { - if (m_options.ContainsKey("compression-module")) - return m_options["compression-module"]; - else - return "zip"; - } - } - - - /// - /// Gets the number of time to retry transmission if it fails - /// - public int NumberOfRetries - { - get - { - if (!m_options.ContainsKey("number-of-retries") || string.IsNullOrEmpty(m_options["number-of-retries"])) - return 5; - else - { - int x = int.Parse(m_options["number-of-retries"]); - if (x < 0) - throw new UserInformationException("Invalid count for number-of-retries", "NumberOfRetriesInvalid"); - - return x; - } - } - } - - /// - /// A value indicating if backups are transmitted on a separate thread - /// - public bool SynchronousUpload { get { return Library.Utility.Utility.ParseBoolOption(m_options, "synchronous-upload"); } } - - /// - /// A value indicating if system is allowed to enter sleep power states during backup/restore - /// - public bool AllowSleep { get { return GetBool("allow-sleep"); } } - - /// - /// A value indicating if system should use the low-priority IO during backup/restore - /// - public bool UseBackgroundIOPriority { get { return GetBool("use-background-io-priority"); } } - - /// - /// A value indicating if use of the streaming interface is disallowed - /// - public bool DisableStreamingTransfers { get { return GetBool("disable-streaming-transfers"); } } - - /// - /// A value indicating if multithreaded pipes may be used for hashing and crypting on up-/downloads - /// - public bool DisablePipedStreaming { get { return GetBool("disable-piped-streaming"); } } - - /// - /// Gets the timelimit for removal - /// - public TimeSpan RetryDelay - { - get - { - if (!m_options.ContainsKey("retry-delay") || string.IsNullOrEmpty(m_options["retry-delay"])) - return new TimeSpan(TimeSpan.TicksPerSecond * 10); - else - return Library.Utility.Timeparser.ParseTimeSpan(m_options["retry-delay"]); - } - } - - /// - /// Gets the max upload speed in bytes pr. second - /// - public long MaxUploadPrSecond - { - get - { - lock(m_lock) - { - string v; - m_options.TryGetValue("throttle-upload", out v); - if (string.IsNullOrEmpty(v)) - return 0; - else - return Library.Utility.Sizeparser.ParseSize(v, "kb"); - } - } - set - { - lock (m_lock) - if (value <= 0) - m_options["throttle-upload"] = ""; - else - m_options["throttle-upload"] = value.ToString() + "b"; - } - } - - /// - /// Gets or sets the max download speed in bytes pr. second - /// - public long MaxDownloadPrSecond - { - get - { - lock (m_lock) - { - string v; - m_options.TryGetValue("throttle-download", out v); - if (string.IsNullOrEmpty(v)) - return 0; - else - return Library.Utility.Sizeparser.ParseSize(v, "kb"); - } - } - set - { - lock (m_lock) - if (value <= 0) - m_options["throttle-download"] = ""; - else - m_options["throttle-download"] = value.ToString() + "b"; - } - } - - /// - /// A value indicating if the backup is a full backup - /// - public bool AllowFullRemoval { get { return GetBool("allow-full-removal"); } } - - /// - /// A value indicating if debug output is enabled - /// - public bool DebugOutput { get { return GetBool("debug-output"); } } - - /// - /// A value indicating if unchanged backups are uploaded - /// - public bool UploadUnchangedBackups { get { return GetBool("upload-unchanged-backups"); } } - - /// - /// Gets a list of modules that should be loaded - /// - public string[] EnableModules - { - get - { - if (m_options.ContainsKey("enable-module")) - return m_options["enable-module"].Trim().ToLower(CultureInfo.InvariantCulture).Split(','); - else - return new string[0]; - } - } - - /// - /// Gets a list of modules that should not be loaded - /// - public string[] DisableModules - { - get - { - if (m_options.ContainsKey("disable-module")) - return m_options["disable-module"].Trim().ToLower(CultureInfo.InvariantCulture).Split(','); - else - return new string[0]; - } - } - - /// - /// Gets the snapshot strategy to use - /// - public OptimizationStrategy SnapShotStrategy - { - get - { - string strategy; - if (!m_options.TryGetValue("snapshot-policy", out strategy)) - strategy = ""; - - if (string.Equals(strategy, "on", StringComparison.OrdinalIgnoreCase)) - return OptimizationStrategy.On; - else if (string.Equals(strategy, "off", StringComparison.OrdinalIgnoreCase)) - return OptimizationStrategy.Off; - else if (string.Equals(strategy, "required", StringComparison.OrdinalIgnoreCase)) - return OptimizationStrategy.Required; - else if (string.Equals(strategy, "auto", StringComparison.OrdinalIgnoreCase)) - return OptimizationStrategy.Auto; - else - return OptimizationStrategy.Off; - } - } - - /// - /// Gets the symlink strategy to use - /// - public SymlinkStrategy SymlinkPolicy - { - get - { - string policy; - if (!m_options.TryGetValue("symlink-policy", out policy)) - policy = ""; - - SymlinkStrategy r; - if (!Enum.TryParse(policy, true, out r)) - r = SymlinkStrategy.Store; - - return r; - } - } - - /// - /// Gets the hardlink strategy to use - /// - public HardlinkStrategy HardlinkPolicy - { - get - { - string policy; - if (!m_options.TryGetValue("hardlink-policy", out policy)) - policy = ""; - - HardlinkStrategy r; - if (!Enum.TryParse(policy, true, out r)) - r = HardlinkStrategy.All; - - return r; - } - } - /// - /// Gets the update sequence number (USN) strategy to use - /// - public OptimizationStrategy UsnStrategy - { - get - { - string strategy; - if (!m_options.TryGetValue("usn-policy", out strategy)) - strategy = ""; - - if (string.Equals(strategy, "on", StringComparison.OrdinalIgnoreCase)) - return OptimizationStrategy.On; - else if (string.Equals(strategy, "off", StringComparison.OrdinalIgnoreCase)) - return OptimizationStrategy.Off; - else if (string.Equals(strategy, "required", StringComparison.OrdinalIgnoreCase)) - return OptimizationStrategy.Required; - else if (string.Equals(strategy, "auto", StringComparison.OrdinalIgnoreCase)) - return OptimizationStrategy.Auto; - else - return OptimizationStrategy.Off; - } - } - - /// - /// Gets the number of concurrent volume uploads allowed. Zero for unlimited. - /// - public int AsynchronousConcurrentUploadLimit - { - get - { - if (!m_options.TryGetValue("asynchronous-concurrent-upload-limit", out var value)) - value = null; - - if (string.IsNullOrEmpty(value)) - return 4; - else - return int.Parse(value); - } - } - - /// - /// Gets the number of volumes to create ahead of time when using async transfers, - /// a value of zero indicates no limit - /// - public long AsynchronousUploadLimit - { - get - { - string value; - if (!m_options.TryGetValue("asynchronous-upload-limit", out value)) - value = null; - - if (string.IsNullOrEmpty(value)) - return 4; - else - return long.Parse(value); - } - } - - /// - /// Gets the temporary folder to use for asyncronous transfers - /// - public string AsynchronousUploadFolder - { - get - { - string value; - if (!m_options.TryGetValue("asynchronous-upload-folder", out value)) - value = null; - - if (string.IsNullOrEmpty(value)) - return this.TempDir; - else - return value; - } - } - - /// - /// Gets the logfile filename - /// - public string Logfile - { - get - { - string value; - if (!m_options.TryGetValue("log-file", out value)) - value = null; - return value; - } - } - - /// - /// Gets the log-file detail level - /// - public Duplicati.Library.Logging.LogMessageType LogFileLoglevel - { - get - { - string value; - if (!m_options.TryGetValue("log-file-log-level", out value)) - value = null; - - if (string.IsNullOrWhiteSpace(value)) - if (!m_options.TryGetValue("log-level", out value)) - value = null; - - foreach (string s in Enum.GetNames(typeof(Duplicati.Library.Logging.LogMessageType))) - if (s.Equals(value, StringComparison.OrdinalIgnoreCase)) - return (Duplicati.Library.Logging.LogMessageType)Enum.Parse(typeof(Duplicati.Library.Logging.LogMessageType), s); - - return Duplicati.Library.Logging.LogMessageType.Warning; - } - } - - - - /// - /// Parses a log level string - /// - /// The log level enumeration value. - /// The string value to parse. - /// An optional fallback parsing value. - public static Logging.LogMessageType ParseLogLevel(string value, string backupvalue) - { - value = string.IsNullOrWhiteSpace(value) ? backupvalue : value; - foreach (string s in Enum.GetNames(typeof(Duplicati.Library.Logging.LogMessageType))) - if (s.Equals(value, StringComparison.OrdinalIgnoreCase)) - return (Duplicati.Library.Logging.LogMessageType)Enum.Parse(typeof(Duplicati.Library.Logging.LogMessageType), s); - - return Duplicati.Library.Logging.LogMessageType.Warning; - } - - /// - /// Gets the filter used for log-file messages. - /// - /// The log file filter. - public IFilter LogFileLogFilter - { - get - { - m_options.TryGetValue("log-file-log-filter", out var value); - return Library.Utility.FilterExpression.ParseLogFilter(value); - } - } - - /// - /// Gets the filter used for console messages. - /// - /// The log file filter. - public IFilter ConsoleLogFilter - { - get - { - m_options.TryGetValue("console-log-filter", out var value); - return Library.Utility.FilterExpression.ParseLogFilter(value); - } - } - - /// - /// Gets the console log detail level - /// - public Duplicati.Library.Logging.LogMessageType ConsoleLoglevel - { - get - { - string value; - if (!m_options.TryGetValue("console-log-level", out value)) - value = null; - - if (string.IsNullOrWhiteSpace(value)) - if (!m_options.TryGetValue("log-level", out value)) - value = null; - - foreach (string s in Enum.GetNames(typeof(Duplicati.Library.Logging.LogMessageType))) - if (s.Equals(value, StringComparison.OrdinalIgnoreCase)) - return (Duplicati.Library.Logging.LogMessageType)Enum.Parse(typeof(Duplicati.Library.Logging.LogMessageType), s); - - return Duplicati.Library.Logging.LogMessageType.Warning; - } - } - - /// - /// A value indicating if all database queries should be logged - /// - public bool ProfileAllDatabaseQueries { get { return GetBool("profile-all-database-queries"); } } - - /// - /// Gets the attribute filter used to exclude files and folders. - /// - public System.IO.FileAttributes FileAttributeFilter - { - get - { - System.IO.FileAttributes res = default(System.IO.FileAttributes); - string v; - if (!m_options.TryGetValue("exclude-files-attributes", out v)) - return res; - - foreach(string s in v.Split(new string[] {","}, StringSplitOptions.RemoveEmptyEntries)) - { - System.IO.FileAttributes f; - if (Enum.TryParse(s.Trim(), true, out f)) - res |= f; - } - - return res; - } - } - - /// - /// A value indicating if server uploads are verified by listing the folder contents - /// - public bool ListVerifyUploads { get { return GetBool("list-verify-uploads"); } } - - /// - /// A value indicating if connections cannot be re-used - /// - public bool NoConnectionReuse { get { return GetBool("no-connection-reuse"); } } - - /// - /// A value indicating if the returned value should not be truncated - /// - public bool FullResult { get { return GetBool("full-result"); } } - - /// - /// A value indicating restored files overwrite existing ones - /// - public bool Overwrite { get { return GetBool("overwrite"); } } - - /// - /// Gets the total size in bytes that the backend supports, returns -1 if there is no upper limit - /// - public long QuotaSize - { - get - { - if (!m_options.ContainsKey("quota-size") || string.IsNullOrEmpty(m_options["quota-size"])) - return -1; - else - return Library.Utility.Sizeparser.ParseSize(m_options["quota-size"], "mb"); - } - } - - /// - /// Gets the threshold at which a quota warning should be generated. - /// - /// - /// This is treated as a percentage, where a warning is given when the amount of free space is less than this percentage of the backup size. - /// - public int QuotaWarningThreshold - { - get - { - string tmp; - m_options.TryGetValue("quota-warning-threshold", out tmp); - if (string.IsNullOrEmpty(tmp)) - { - return DEFAULT_QUOTA_WARNING_THRESHOLD; - } - else - { - return int.Parse(tmp); - } - } - } - - /// - /// Gets the display name of the backup - /// - public string BackupName - { - get - { - string tmp; - m_options.TryGetValue("backup-name", out tmp); - if (string.IsNullOrEmpty(tmp)) - return DefaultBackupName; - else - return tmp; - } - set - { - m_options["backup-name"] = value; - } - } - - /// - /// Gets the path to the database - /// - public string Dbpath - { - get - { - string tmp; - m_options.TryGetValue("dbpath", out tmp); - return tmp; - } - set - { - m_options["dbpath"] = value; - } - } - - /// - /// Gets a value indicating whether a blocksize has been specified - /// - public bool HasBlocksize { get { return m_options.ContainsKey("blocksize") && !string.IsNullOrEmpty(m_options["blocksize"]); } } - - /// - /// Gets the size of file-blocks - /// - public int Blocksize - { - get - { - string tmp; - if (!m_options.TryGetValue("blocksize", out tmp)) - tmp = DEFAULT_BLOCKSIZE; - - long blocksize = Library.Utility.Sizeparser.ParseSize(tmp, "kb"); - if (blocksize > int.MaxValue || blocksize < 1024) - throw new ArgumentOutOfRangeException(nameof(blocksize), string.Format("The blocksize cannot be less than {0}, nor larger than {1}", 1024, int.MaxValue)); - - return (int)blocksize; - } - } - - /// - /// Cache for the block hash size value, to avoid creating new hash instances just to get the size - /// - private KeyValuePair m_cachedBlockHashSize; - - /// - /// Gets the size of the blockhash in bytes. - /// - /// The size of the blockhash. - public int BlockhashSize - { - get - { - if (m_cachedBlockHashSize.Key != BlockHashAlgorithm) - m_cachedBlockHashSize = new KeyValuePair(BlockHashAlgorithm, Duplicati.Library.Utility.HashAlgorithmHelper.Create(BlockHashAlgorithm).HashSize / 8); - - return m_cachedBlockHashSize.Value; - } - } - - /// - /// Gets the size the read-ahead buffer - /// - public long FileReadBufferSize - { - get - { - string tmp; - if (!m_options.TryGetValue("file-read-buffer-size", out tmp)) - tmp = DEFAULT_READ_BUFFER_SIZE; - - long t = Library.Utility.Sizeparser.ParseSize(tmp, "mb"); - return (int)t; - } - } - - /// - /// Gets a flag indicating if metadata for files and folders should be ignored - /// - public bool SkipMetadata - { - get { return Library.Utility.Utility.ParseBoolOption(m_options, "skip-metadata"); } - } - - /// - /// Gets a flag indicating if empty folders should be ignored - /// - public bool ExcludeEmptyFolders - { - get { return Library.Utility.Utility.ParseBoolOption(m_options, "exclude-empty-folders"); } - } - - /// - /// Gets a flag indicating if empty folders should be ignored - /// - public bool RestoreSymlinkMetadata - { - get { return Library.Utility.Utility.ParseBoolOption(m_options, "restore-symlink-metadata"); } - } - - /// - /// Gets a flag indicating if permissions should be restored - /// - public bool RestorePermissions - { - get { return Library.Utility.Utility.ParseBoolOption(m_options, "restore-permissions"); } - } - - - /// - /// Gets a flag indicating if file hashes are checked after a restore - /// - public bool PerformRestoredFileVerification - { - get { return !Library.Utility.Utility.ParseBoolOption(m_options, "skip-restore-verification"); } - } - - /// - /// Gets a flag indicating if synthetic filelist generation is disabled - /// - public bool DisableSyntheticFilelist - { - get { return Library.Utility.Utility.ParseBoolOption(m_options, "disable-synthetic-filelist"); } - } - - /// - /// Flag indicating if the in-memory block cache is used - /// - public bool UseBlockCache - { - get - { - return Library.Utility.Utility.ParseBoolOption(m_options, "use-block-cache"); - } - } - - - /// - /// Gets the compact threshold - /// - public long Threshold - { - get - { - string v; - m_options.TryGetValue("threshold", out v); - if (string.IsNullOrEmpty(v)) - return DEFAULT_THRESHOLD; - - return Convert.ToInt64(v); - } - } - - /// - /// Gets the size of small volumes - /// - public long SmallFileSize - { - get - { - string v; - m_options.TryGetValue("small-file-size", out v); - if (string.IsNullOrEmpty(v)) - return this.VolumeSize / 5; - - return Library.Utility.Sizeparser.ParseSize(v, "mb"); - } - } - - /// - /// Gets the maximum number of small volumes - /// - public long SmallFileMaxCount - { - get - { - string v; - m_options.TryGetValue("small-file-max-count", out v); - if (string.IsNullOrEmpty(v)) - return DEFAULT_SMALL_FILE_MAX_COUNT; - - return Convert.ToInt64(v); - } - } - - /// - /// List of files to check for changes - /// - public string[] ChangedFilelist - { - get - { - string v; - m_options.TryGetValue("changed-files", out v); - if (string.IsNullOrEmpty(v)) - return null; - - return v.Split(new char[] { System.IO.Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries); - } - } - - /// - /// List of files to mark as deleted - /// - public string[] DeletedFilelist - { - get - { - string v; - m_options.TryGetValue("deleted-files", out v); - if (string.IsNullOrEmpty(v)) - return null; - - return v.Split(new char[] { System.IO.Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries); - } - } - - /// - /// List of filenames that are used to exclude a folder - /// - public string[] IgnoreFilenames - { - get - { - string v; - m_options.TryGetValue("ignore-filenames", out v); - if (string.IsNullOrEmpty(v)) - return null; - - return v.Split(new char[] { System.IO.Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries); - } - } - /// - /// Alternate restore path - /// - public string Restorepath - { - get - { - string v; - m_options.TryGetValue("restore-path", out v); - return v; - } - } - - /// - /// Gets the index file usage method - /// - public IndexFileStrategy IndexfilePolicy - { - get - { - string strategy; - if (!m_options.TryGetValue("index-file-policy", out strategy)) - strategy = ""; - - IndexFileStrategy res; - if (!Enum.TryParse(strategy, true, out res)) - res = IndexFileStrategy.Full; - - return res; - } - } - - /// - /// Gets a flag indicating if the check for files on the remote storage should be omitted - /// - public bool NoBackendverification - { - get { return Library.Utility.Utility.ParseBoolOption(m_options, "no-backend-verification"); } - } - - /// - /// Gets the percentage of samples to test during a backup operation - /// - public long BackupTestPercentage - { - get - { - m_options.TryGetValue("backup-test-percentage", out string s); - if (string.IsNullOrEmpty(s)) - { - return 0; - } - - long percentage; - try - { - percentage = long.Parse(s); - } - catch (Exception ex) - { - throw new ArgumentException("The value provided for the backup-test-percentage option must lie between 0 and 100.", ex); - } - - if ((percentage < 0) || (percentage > 100)) - { - throw new ArgumentOutOfRangeException(nameof(percentage), "The value provided for the backup-test-percentage option must lie between 0 and 100."); - } - - return percentage; - } - } - - /// - /// Gets the number of samples to test during a backup operation - /// - public long BackupTestSampleCount - { - get - { - string s; - m_options.TryGetValue("backup-test-samples", out s); - if (string.IsNullOrEmpty(s)) - return 1; - - return long.Parse(s); - } - } - - /// - /// Gets a flag indicating if compacting should not be done automatically - /// - public bool NoAutoCompact - { - get { return Library.Utility.Utility.ParseBoolOption(m_options, "no-auto-compact"); } - } - - /// - /// Gets the minimum time that must elapse after last compaction before running next automatic compaction - /// - public TimeSpan AutoCompactInterval - { - get - { - if (!m_options.ContainsKey("auto-compact-interval") || string.IsNullOrEmpty(m_options["auto-compact-interval"])) - return TimeSpan.Zero; - else - return Library.Utility.Timeparser.ParseTimeSpan(m_options["auto-compact-interval"]); - } - } - - /// - /// Gets a flag indicating if compacting should not be done automatically - /// - public bool AllowMissingSource - { - get { return Library.Utility.Utility.ParseBoolOption(m_options, "allow-missing-source"); } - } - - /// - /// Gets a value indicating if a verification file should be uploaded after changing the remote store - /// - public bool UploadVerificationFile - { - get { return Library.Utility.Utility.ParseBoolOption(m_options, "upload-verification-file"); } - } - - /// - /// Gets a value indicating if a passphrase change is allowed - /// - public bool AllowPassphraseChange - { - get { return Library.Utility.Utility.ParseBoolOption(m_options, "allow-passphrase-change"); } - } - - /// - /// Gets a flag indicating if the current operation should merely output the changes - /// - public bool Dryrun - { - get - { - if (m_options.ContainsKey("dry-run")) - return Library.Utility.Utility.ParseBoolOption(m_options, "dry-run"); - else - return Library.Utility.Utility.ParseBoolOption(m_options, "dryrun"); - } - } - - /// - /// Gets a flag indicating if the current operation is intended to delete files older than a certain threshold - /// - public bool HasDeleteOlderThan - { - get { return m_options.ContainsKey("delete-older-than"); } - } - - /// - /// Gets a flag indicating if the current operation is intended to delete files older than a certain threshold - /// - public bool HasDeleteAllButN - { - get { return m_options.ContainsKey("delete-all-but-n") || m_options.ContainsKey("delete-all-but-n-full"); } - } - - - /// - /// Gets a flag indicating if the remote verification is deep - /// - public bool FullRemoteVerification - { - get { return Library.Utility.Utility.ParseBoolOption(m_options, "full-remote-verification"); } - } - - /// - /// The block hash algorithm to use - /// - public string BlockHashAlgorithm - { - get - { - string v; - m_options.TryGetValue("block-hash-algorithm", out v); - if (string.IsNullOrEmpty(v)) - return DEFAULT_BLOCK_HASH_ALGORITHM; - - return v; - } - } - - /// - /// The file hash algorithm to use - /// - public string FileHashAlgorithm - { - get - { - string v; - m_options.TryGetValue("file-hash-algorithm", out v); - if (string.IsNullOrEmpty(v)) - return DEFAULT_FILE_HASH_ALGORITHM; - - return v; - } - } - - /// - /// Gets a flag indicating if the current operation is intended to delete files older than a certain threshold - /// - public bool PatchWithLocalBlocks - { - get { return m_options.ContainsKey("patch-with-local-blocks"); } - } - - /// - /// Gets a value indicating whether local blocks usage should be skipped. - /// - /// true if no local blocks; otherwise, false. - public bool NoLocalBlocks - { - get { return Library.Utility.Utility.ParseBoolOption(m_options, "no-local-blocks"); } - } - - /// - /// Gets a flag indicating if the local database should not be used - /// - /// true if no local db is used; otherwise, false. - public bool NoLocalDb - { - get { return Library.Utility.Utility.ParseBoolOption(m_options, "no-local-db"); } - } - - /// - /// Gets a flag indicating if the local database should not be used - /// - /// true if no local db is used; otherwise, false. - public bool DontCompressRestorePaths - { - get { return Library.Utility.Utility.ParseBoolOption(m_options, "dont-compress-restore-paths"); } - } - - /// - /// Gets a flag indicating if block hashes are checked before being applied - /// - /// true if block hashes are checked; otherwise, false. - public bool FullBlockVerification - { - get { return Library.Utility.Utility.ParseBoolOption(m_options, "full-block-verification"); } - } - - /// - /// Gets a flag indicating if the repair process will only restore paths - /// - /// true if only paths are restored; otherwise, false. - public bool RepairOnlyPaths - { - get { return Library.Utility.Utility.ParseBoolOption(m_options, "repair-only-paths"); } - } - - /// - /// Gets a flag indicating whether the VACUUM operation should ever be run automatically. - /// - public bool AutoVacuum - { - get { return GetBool("auto-vacuum"); } - } - - /// - /// Gets the minimum time that must elapse after last vacuum before running next automatic vacuum - /// - public TimeSpan AutoVacuumInterval - { - get - { - if (!m_options.ContainsKey("auto-vacuum-interval") || string.IsNullOrEmpty(m_options["auto-vacuum-interval"])) - return TimeSpan.Zero; - else - return Library.Utility.Timeparser.ParseTimeSpan(m_options["auto-vacuum-interval"]); - } - } - - /// - /// Gets a flag indicating if the local filescanner should be disabled - /// - /// true if the filescanner should be disabled; otherwise, false. - public bool DisableFileScanner - { - get { return Library.Utility.Utility.ParseBoolOption(m_options, "disable-file-scanner"); } - } - - /// - /// Gets a flag indicating if the filelist consistency checks should be disabled - /// - /// true if the filelist consistency checks should be disabled; otherwise, false. - public bool DisableFilelistConsistencyChecks - { - get { return Library.Utility.Utility.ParseBoolOption(m_options, "disable-filelist-consistency-checks"); } - } - - /// - /// Gets a flag indicating whether the backup should be disabled when on battery power. - /// - /// true if the backup should be disabled when on battery power; otherwise, false. - public bool DisableOnBattery - { - get { return Library.Utility.Utility.ParseBoolOption(m_options, "disable-on-battery"); } - } - - /// - /// Gets a value indicating if missing dblock files are attempted created - /// - public bool RebuildMissingDblockFiles - { - get { return GetBool("rebuild-missing-dblock-files"); } - } - - /// - /// Gets the threshold for when log data should be cleaned - /// - public DateTime LogRetention - { - get - { - string pts; - if (!m_options.TryGetValue("log-retention", out pts)) - pts = DEFAULT_LOG_RETENTION; - - return Library.Utility.Timeparser.ParseTimeInterval(pts, DateTime.Now, true); - } - } - - - /// - /// Gets the number of concurrent threads - /// - public int ConcurrencyMaxThreads - { - get - { - string value; - if (!m_options.TryGetValue("concurrency-max-threads", out value)) - value = null; - - if (string.IsNullOrEmpty(value)) - return 0; - else - return int.Parse(value); - } - } - - /// - /// Gets the number of concurrent block hashers - /// - public int ConcurrencyBlockHashers - { - get - { - string value; - if (!m_options.TryGetValue("concurrency-block-hashers", out value)) - value = null; - - if (string.IsNullOrEmpty(value)) - return DEFAULT_BLOCK_HASHERS; - else - return Math.Max(1, int.Parse(value)); - } - } - - /// - /// Gets the number of concurrent block hashers - /// - public int ConcurrencyCompressors - { - get - { - string value; - if (!m_options.TryGetValue("concurrency-compressors", out value)) - value = null; - - if (string.IsNullOrEmpty(value)) - return DEFAULT_COMPRESSORS; - else - return Math.Max(1, int.Parse(value)); - } - } - - /// - /// Gets a lookup table with compression hints, the key is the file extension with the leading period - /// - public IDictionary CompressionHints - { - get - { - if (m_compressionHints == null) - { - var hints = new Dictionary(Library.Utility.Utility.ClientFilenameStringComparer); - - string file; - if (!m_options.TryGetValue("compression-extension-file", out file)) - file = DEFAULT_COMPRESSED_EXTENSION_FILE; - - if (!string.IsNullOrEmpty(file) && System.IO.File.Exists(file)) - foreach (var _line in Library.Utility.Utility.ReadFileWithDefaultEncoding(file).Split('\n')) - { - var line = _line.Trim(); - var lix = line.IndexOf(' '); - if (lix > 0) - line = line.Substring(0, lix); - if (line.Length >= 2 && line[0] == '.') - hints[line] = CompressionHint.Noncompressible; - } - - //Don't try again, if the file does not exist - m_compressionHints = hints; - } - - return m_compressionHints; - } - } - - /// - /// Gets a compression hint from a filename - /// - /// The filename to get the hint for - /// The compression hint - public CompressionHint GetCompressionHintFromFilename(string filename) - { - CompressionHint h; - if (!CompressionHints.TryGetValue(System.IO.Path.GetExtension(filename), out h)) - return CompressionHint.Default; - return h; - } - - /// - /// Gets a list of modules, the key indicates if they are loaded - /// - public List> LoadedModules { get { return m_loadedModules; } } - - /// - /// Helper method to extract boolean values. - /// If the option is not present, it it's value is false. - /// If the option is present it's value is true, unless the option's value is false, off or 0 - /// - /// The name of the option to read - /// The interpreted value of the option - private bool GetBool(string name) - { - return Library.Utility.Utility.ParseBoolOption(m_options, name); - } - - /// - /// Class for handling a single RententionPolicy timeframe-interval-pair - /// - public class RetentionPolicyValue - { - public readonly TimeSpan Timeframe; - public readonly TimeSpan Interval; - - public RetentionPolicyValue(TimeSpan timeframe, TimeSpan interval) - { - if (timeframe < TimeSpan.Zero) - { - throw new ArgumentOutOfRangeException(nameof(timeframe), string.Format("The timeframe cannot be negative: '{0}'", timeframe)); - } - if (interval < TimeSpan.Zero) - { - throw new ArgumentOutOfRangeException(nameof(interval), string.Format("The interval cannot be negative: '{0}'", interval)); - } - - this.Timeframe = timeframe; - this.Interval = interval; - } - - /// - /// Returns whether this is an unlimited timeframe or not - /// - /// - public Boolean IsUnlimtedTimeframe() - { - // Timeframes equal or bigger than the maximum TimeSpan effectivly represent an unlimited timeframe - return Timeframe >= TimeSpan.MaxValue; - } - - /// - /// Returns whether all versions in this timeframe should be kept or not - /// - /// - public Boolean IsKeepAllVersions() - { - /// Intervals between two versions that are equal or smaller than zero effectivly result in - /// all versions in that timeframe being kept. - return Interval <= TimeSpan.Zero; - } - - public override string ToString() - { - return (IsUnlimtedTimeframe() ? "Unlimited" : Timeframe.ToString()) + " / " + (IsKeepAllVersions() ? "Keep all" : Interval.ToString()); - } - - /// - /// Parses a string representation of a timeframe-interval-pair and returns a RentionPolicyValue object - /// - /// - public static RetentionPolicyValue CreateFromString(string rententionPolicyValueString) - { - var periodInterval = rententionPolicyValueString.Split(':'); - - TimeSpan timeframe; - // Timeframe "U" (= Unlimited) means: For unlimted time keep one version every X interval. - // So the timeframe has to span the maximum time possible. - if (String.Equals(periodInterval[0], "U", StringComparison.OrdinalIgnoreCase)) - { - timeframe = TimeSpan.MaxValue; - } - else - { - timeframe = Library.Utility.Timeparser.ParseTimeSpan(periodInterval[0]); - } - - TimeSpan interval; - // Interval "U" (= Unlimited) means: For period X keep all versions. - // So the interval between two versions has to be zero. - if (String.Equals(periodInterval[1], "U", StringComparison.OrdinalIgnoreCase)) - { - interval = TimeSpan.Zero; - } - else - { - interval = Library.Utility.Timeparser.ParseTimeSpan(periodInterval[1]); - } - - return new RetentionPolicyValue(timeframe, interval); - } - } - } -} +#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.Linq; +using System.Collections.Generic; +using Duplicati.Library.Interface; +using Duplicati.Library.Utility; +using System.Globalization; + +namespace Duplicati.Library.Main +{ + /// + /// A class for keeping all Duplicati options in one place, + /// and provide typesafe access to the options + /// + public class Options + { + private const string DEFAULT_BLOCK_HASH_ALGORITHM = "SHA256"; + private const string DEFAULT_FILE_HASH_ALGORITHM = "SHA256"; + + /// + /// The default block size + /// + private const string DEFAULT_BLOCKSIZE = "100kb"; + + /// + /// The default size of the read-ahead buffer + /// + private const string DEFAULT_READ_BUFFER_SIZE = "5mb"; + + /// + /// The default threshold value + /// + private const long DEFAULT_THRESHOLD = 25; + + /// + /// The default value for maximum number of small files + /// + private const long DEFAULT_SMALL_FILE_MAX_COUNT = 20; + + /// + /// Default size of volumes + /// + private const string DEFAULT_VOLUME_SIZE = "50mb"; + + /// + /// Default value for keep-versions + /// + private const int DEFAULT_KEEP_VERSIONS = 0; + + /// + /// The default threshold for purging log data + /// + private const string DEFAULT_LOG_RETENTION = "30D"; + + /// + /// The default number of compressor instances + /// + private readonly int DEFAULT_COMPRESSORS = Math.Max(1, Environment.ProcessorCount / 2); + + /// + /// The default number of hasher instances + /// + private readonly int DEFAULT_BLOCK_HASHERS = Math.Max(1, Environment.ProcessorCount / 2); + + /// + /// The default threshold for warning about coming close to quota + /// + private const int DEFAULT_QUOTA_WARNING_THRESHOLD = 10; + + /// + /// An enumeration that describes the supported strategies for an optimization + /// + public enum OptimizationStrategy + { + /// + /// The optimization feature is created if possible, but silently ignored if it fails + /// + Auto, + /// + /// The optimization feature is created if possible, but an error is logged if it fails + /// + On, + /// + /// The optimization feature is deactivated + /// + Off, + /// + /// The optimization feature is created, and the backup is aborted if it fails + /// + Required + } + + /// + /// The possible settings for the symlink strategy + /// + public enum SymlinkStrategy + { + /// + /// Store information about the symlink + /// + Store, + + /// + /// Treat symlinks as normal files or folders + /// + Follow, + + /// + /// Ignore all symlinks + /// + Ignore + } + + /// + /// The possible settings for the hardlink strategy + /// + public enum HardlinkStrategy + { + /// + /// Process only the first hardlink + /// + First, + + /// + /// Process all hardlinks + /// + All, + + /// + /// Ignore all hardlinks + /// + None + } + + /// + /// The possible settings for index file usage + /// + public enum IndexFileStrategy + { + /// + /// Disables usage of index files + /// + None, + + /// + /// Stores only block lookup information in the index files + /// + Lookup, + + /// + /// Stores both block lookup and block lists in the index files + /// + Full + + } + + private static string[] GetSupportedHashes() + { + var r = new List(); + foreach (var h in new string[] { "SHA1", "MD5", "SHA256", "SHA384", "SHA512" }) + { + try + { + var p = System.Security.Cryptography.HashAlgorithm.Create(h); + if (p != null) + r.Add(h); + } + catch + { + } + } + + return r.ToArray(); + } + + private static readonly string DEFAULT_COMPRESSED_EXTENSION_FILE = System.IO.Path.Combine(Duplicati.Library.AutoUpdater.UpdaterManager.InstalledBaseDir, "default_compressed_extensions.txt"); + + /// + /// Lock that protects the options collection + /// + protected readonly object m_lock = new object(); + + protected Dictionary m_options; + + protected List> m_loadedModules = new List>(); + + /// + /// Lookup table for compression hints + /// + private Dictionary m_compressionHints; + + public Options(Dictionary options) + { + m_options = options; + } + + public Dictionary RawOptions { get { return m_options; } } + + /// + /// Returns a list of strings that are not supported on the commandline as options, but used internally + /// + public static string[] InternalOptions + { + get + { + return new string[] { + "main-action" + }; + } + } + + /// + /// Returns a list of options that are intentionally duplicate + /// + public static string[] KnownDuplicates + { + get { return new string[] { "auth-password", "auth-username" }; } + } + + /// + /// A default backup name + /// + public static string DefaultBackupName + { + get + { + return System.IO.Path.GetFileNameWithoutExtension(Library.Utility.Utility.getEntryAssembly().Location); + } + } + + /// + /// Gets all supported commands + /// + public IList SupportedCommands + { + get + { + var lst = new List(new ICommandLineArgument[] { + new CommandLineArgument("dblock-size", CommandLineArgument.ArgumentType.Size, Strings.Options.DblocksizeShort, Strings.Options.DblocksizeLong, DEFAULT_VOLUME_SIZE), + new CommandLineArgument("auto-cleanup", CommandLineArgument.ArgumentType.Boolean, Strings.Options.AutocleanupShort, Strings.Options.AutocleanupLong, "false"), + new CommandLineArgument("unittest-mode", CommandLineArgument.ArgumentType.Boolean, Strings.Options.UnittestmodeShort, Strings.Options.UnittestmodeLong, "false"), + + new CommandLineArgument("control-files", CommandLineArgument.ArgumentType.Path, Strings.Options.ControlfilesShort, Strings.Options.ControlfilesLong), + new CommandLineArgument("skip-file-hash-checks", CommandLineArgument.ArgumentType.Boolean, Strings.Options.SkipfilehashchecksShort, Strings.Options.SkipfilehashchecksLong, "false"), + new CommandLineArgument("dont-read-manifests", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DontreadmanifestsShort, Strings.Options.DontreadmanifestsLong, "false"), + new CommandLineArgument("restore-path", CommandLineArgument.ArgumentType.String, Strings.Options.RestorepathShort, Strings.Options.RestorepathLong), + new CommandLineArgument("time", CommandLineArgument.ArgumentType.Timespan, Strings.Options.TimeShort, Strings.Options.TimeLong, "now"), + new CommandLineArgument("version", CommandLineArgument.ArgumentType.String, Strings.Options.VersionShort, Strings.Options.VersionLong, ""), + new CommandLineArgument("all-versions", CommandLineArgument.ArgumentType.Boolean, Strings.Options.AllversionsShort, Strings.Options.AllversionsLong, "false"), + new CommandLineArgument("list-prefix-only", CommandLineArgument.ArgumentType.Boolean, Strings.Options.ListprefixonlyShort, Strings.Options.ListprefixonlyLong, "false"), + new CommandLineArgument("list-folder-contents", CommandLineArgument.ArgumentType.Boolean, Strings.Options.ListfoldercontentsShort, Strings.Options.ListfoldercontentsLong, "false"), + new CommandLineArgument("list-sets-only", CommandLineArgument.ArgumentType.Boolean, Strings.Options.ListsetsonlyShort, Strings.Options.ListsetsonlyLong, "false"), + new CommandLineArgument("disable-autocreate-folder", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisableautocreatefolderShort, Strings.Options.DisableautocreatefolderLong, "false"), + new CommandLineArgument("allow-missing-source", CommandLineArgument.ArgumentType.Boolean, Strings.Options.AllowmissingsourceShort, Strings.Options.AllowmissingsourceLong, "false"), + + new CommandLineArgument("disable-filetime-check", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisablefiletimecheckShort, Strings.Options.DisablefiletimecheckLong, "false"), + new CommandLineArgument("check-filetime-only", CommandLineArgument.ArgumentType.Boolean, Strings.Options.CheckfiletimeonlyShort, Strings.Options.CheckfiletimeonlyLong, "false"), + //new CommandLineArgument("disable-usn-diff-check", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisableusndiffcheckShort, Strings.Options.DisableusndiffcheckLong, "false"), + new CommandLineArgument("disable-time-tolerance", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisabletimetoleranceShort, Strings.Options.DisabletimetoleranceLong, "false"), + + new CommandLineArgument("tempdir", CommandLineArgument.ArgumentType.Path, Strings.Options.TempdirShort, Strings.Options.TempdirLong, System.IO.Path.GetTempPath()), + new CommandLineArgument("thread-priority", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.ThreadpriorityShort, Strings.Options.ThreadpriorityLong, "normal", null, new string[] {"highest", "high", "abovenormal", "normal", "belownormal", "low", "lowest", "idle" }), + + new CommandLineArgument("prefix", CommandLineArgument.ArgumentType.String, Strings.Options.PrefixShort, Strings.Options.PrefixLong, "duplicati"), + + new CommandLineArgument("passphrase", CommandLineArgument.ArgumentType.Password, Strings.Options.PassphraseShort, Strings.Options.PassphraseLong), + new CommandLineArgument("no-encryption", CommandLineArgument.ArgumentType.Boolean, Strings.Options.NoencryptionShort, Strings.Options.NoencryptionLong, "false"), + + new CommandLineArgument("number-of-retries", CommandLineArgument.ArgumentType.Integer, Strings.Options.NumberofretriesShort, Strings.Options.NumberofretriesLong, "5"), + new CommandLineArgument("retry-delay", CommandLineArgument.ArgumentType.Timespan, Strings.Options.RetrydelayShort, Strings.Options.RetrydelayLong, "10s"), + + new CommandLineArgument("synchronous-upload", CommandLineArgument.ArgumentType.Boolean, Strings.Options.SynchronousuploadShort, Strings.Options.SynchronousuploadLong, "false"), + new CommandLineArgument("asynchronous-upload-limit", CommandLineArgument.ArgumentType.Integer, Strings.Options.AsynchronousuploadlimitShort, Strings.Options.AsynchronousuploadlimitLong, "4"), + new CommandLineArgument("asynchronous-concurrent-upload-limit", CommandLineArgument.ArgumentType.Integer, Strings.Options.AsynchronousconcurrentuploadlimitShort, Strings.Options.AsynchronousconcurrentuploadlimitLong, "4"), + new CommandLineArgument("asynchronous-upload-folder", CommandLineArgument.ArgumentType.Path, Strings.Options.AsynchronousuploadfolderShort, Strings.Options.AsynchronousuploadfolderLong, System.IO.Path.GetTempPath()), + + new CommandLineArgument("disable-streaming-transfers", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisableStreamingShort, Strings.Options.DisableStreamingLong, "false"), + + new CommandLineArgument("throttle-upload", CommandLineArgument.ArgumentType.Size, Strings.Options.ThrottleuploadShort, Strings.Options.ThrottleuploadLong, "0kb"), + new CommandLineArgument("throttle-download", CommandLineArgument.ArgumentType.Size, Strings.Options.ThrottledownloadShort, Strings.Options.ThrottledownloadLong, "0kb"), + new CommandLineArgument("skip-files-larger-than", CommandLineArgument.ArgumentType.Size, Strings.Options.SkipfileslargerthanShort, Strings.Options.SkipfileslargerthanLong), + + new CommandLineArgument("upload-unchanged-backups", CommandLineArgument.ArgumentType.Boolean, Strings.Options.UploadUnchangedBackupsShort, Strings.Options.UploadUnchangedBackupsLong, "false"), + + new CommandLineArgument("snapshot-policy", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.SnapshotpolicyShort, Strings.Options.SnapshotpolicyLong, "off", null, Enum.GetNames(typeof(OptimizationStrategy))), + new CommandLineArgument("vss-exclude-writers", CommandLineArgument.ArgumentType.String, Strings.Options.VssexcludewritersShort, Strings.Options.VssexcludewritersLong, "{e8132975-6f93-4464-a53e-1050253ae220}"), + new CommandLineArgument("vss-use-mapping", CommandLineArgument.ArgumentType.Boolean, Strings.Options.VssusemappingShort, Strings.Options.VssusemappingLong, "false"), + new CommandLineArgument("usn-policy", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.UsnpolicyShort, Strings.Options.UsnpolicyLong, "off", null, Enum.GetNames(typeof(OptimizationStrategy))), + + new CommandLineArgument("encryption-module", CommandLineArgument.ArgumentType.String, Strings.Options.EncryptionmoduleShort, Strings.Options.EncryptionmoduleLong, "aes"), + new CommandLineArgument("compression-module", CommandLineArgument.ArgumentType.String, Strings.Options.CompressionmoduleShort, Strings.Options.CompressionmoduleLong, "zip"), + + new CommandLineArgument("enable-module", CommandLineArgument.ArgumentType.String, Strings.Options.EnablemoduleShort, Strings.Options.EnablemoduleLong), + new CommandLineArgument("disable-module", CommandLineArgument.ArgumentType.String, Strings.Options.DisablemoduleShort, Strings.Options.DisablemoduleLong), + + new CommandLineArgument("debug-output", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DebugoutputShort, Strings.Options.DebugoutputLong, "false"), + new CommandLineArgument("debug-retry-errors", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DebugretryerrorsShort, Strings.Options.DebugretryerrorsLong, "false"), + + new CommandLineArgument("log-file", CommandLineArgument.ArgumentType.Path, Strings.Options.LogfileShort, Strings.Options.LogfileLong), + new CommandLineArgument("log-file-log-level", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.LogfileloglevelShort, Strings.Options.LogfileloglevelShort, "Warning", null, Enum.GetNames(typeof(Duplicati.Library.Logging.LogMessageType))), + new CommandLineArgument("log-file-log-filter", CommandLineArgument.ArgumentType.String, Strings.Options.LogfilelogfiltersShort, Strings.Options.LogfilelogfiltersLong(System.IO.Path.PathSeparator.ToString()), null), + + new CommandLineArgument("console-log-level", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.ConsoleloglevelShort, Strings.Options.ConsoleloglevelShort, "Warning", null, Enum.GetNames(typeof(Duplicati.Library.Logging.LogMessageType))), + new CommandLineArgument("console-log-filter", CommandLineArgument.ArgumentType.String, Strings.Options.ConsolelogfiltersShort, Strings.Options.ConsolelogfiltersLong(System.IO.Path.PathSeparator.ToString()), null), + + new CommandLineArgument("log-level", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.LoglevelShort, Strings.Options.LoglevelLong, "Warning", null, Enum.GetNames(typeof(Duplicati.Library.Logging.LogMessageType)), Strings.Options.LogLevelDeprecated("log-file-log-level", "console-log-level")), + + new CommandLineArgument("profile-all-database-queries", CommandLineArgument.ArgumentType.Boolean, Strings.Options.ProfilealldatabasequeriesShort, Strings.Options.ProfilealldatabasequeriesLong, "false"), + + new CommandLineArgument("list-verify-uploads", CommandLineArgument.ArgumentType.Boolean, Strings.Options.ListverifyuploadsShort, Strings.Options.ListverifyuploadsShort, "false"), + new CommandLineArgument("allow-sleep", CommandLineArgument.ArgumentType.Boolean, Strings.Options.AllowsleepShort, Strings.Options.AllowsleepLong, "false"), + new CommandLineArgument("use-background-io-priority", CommandLineArgument.ArgumentType.Boolean, Strings.Options.UsebackgroundiopriorityShort, Strings.Options.UsebackgroundiopriorityLong, "false"), + new CommandLineArgument("no-connection-reuse", CommandLineArgument.ArgumentType.Boolean, Strings.Options.NoconnectionreuseShort, Strings.Options.NoconnectionreuseLong, "false"), + + new CommandLineArgument("quota-size", CommandLineArgument.ArgumentType.Size, Strings.Options.QuotasizeShort, Strings.Options.QuotasizeLong), + new CommandLineArgument("quota-warning-threshold", CommandLineArgument.ArgumentType.Integer, Strings.Options.QuotaWarningThresholdShort, Strings.Options.QuotaWarningThresholdLong, DEFAULT_QUOTA_WARNING_THRESHOLD.ToString()), + + new CommandLineArgument("symlink-policy", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.SymlinkpolicyShort, Strings.Options.SymlinkpolicyLong("store", "ignore", "follow"), Enum.GetName(typeof(SymlinkStrategy), SymlinkStrategy.Store), null, Enum.GetNames(typeof(SymlinkStrategy))), + new CommandLineArgument("hardlink-policy", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.HardlinkpolicyShort, Strings.Options.HardlinkpolicyLong("first", "all", "none"), Enum.GetName(typeof(HardlinkStrategy), HardlinkStrategy.All), null, Enum.GetNames(typeof(HardlinkStrategy))), + new CommandLineArgument("exclude-files-attributes", CommandLineArgument.ArgumentType.String, Strings.Options.ExcludefilesattributesShort, Strings.Options.ExcludefilesattributesLong(Enum.GetNames(typeof(System.IO.FileAttributes)))), + new CommandLineArgument("backup-name", CommandLineArgument.ArgumentType.String, Strings.Options.BackupnameShort, Strings.Options.BackupnameLong, DefaultBackupName), + new CommandLineArgument("compression-extension-file", CommandLineArgument.ArgumentType.Path, Strings.Options.CompressionextensionfileShort, Strings.Options.CompressionextensionfileLong(DEFAULT_COMPRESSED_EXTENSION_FILE), DEFAULT_COMPRESSED_EXTENSION_FILE), + + new CommandLineArgument("verbose", CommandLineArgument.ArgumentType.Boolean, Strings.Options.VerboseShort, Strings.Options.VerboseLong, "false", null, null, Strings.Options.VerboseDeprecated), + new CommandLineArgument("full-result", CommandLineArgument.ArgumentType.Boolean, Strings.Options.FullresultShort, Strings.Options.FullresultLong, "false"), + + new CommandLineArgument("overwrite", CommandLineArgument.ArgumentType.Boolean, Strings.Options.OverwriteShort, Strings.Options.OverwriteLong, "false"), + + new CommandLineArgument("dbpath", CommandLineArgument.ArgumentType.Path, Strings.Options.DbpathShort, Strings.Options.DbpathLong), + new CommandLineArgument("blocksize", CommandLineArgument.ArgumentType.Size, Strings.Options.BlocksizeShort, Strings.Options.BlocksizeLong, DEFAULT_BLOCKSIZE), + new CommandLineArgument("file-read-buffer-size", CommandLineArgument.ArgumentType.Size, Strings.Options.FilereadbuffersizeShort, Strings.Options.FilereadbuffersizeLong, "0kb"), + new CommandLineArgument("skip-metadata", CommandLineArgument.ArgumentType.Boolean, Strings.Options.SkipmetadataShort, Strings.Options.SkipmetadataLong, "false"), + new CommandLineArgument("restore-permissions", CommandLineArgument.ArgumentType.Boolean, Strings.Options.RestorepermissionsShort, Strings.Options.RestorepermissionsLong, "false"), + new CommandLineArgument("skip-restore-verification", CommandLineArgument.ArgumentType.Boolean, Strings.Options.SkiprestoreverificationShort, Strings.Options.SkiprestoreverificationLong, "false"), + new CommandLineArgument("disable-filepath-cache", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisablefilepathcacheShort, Strings.Options.DisablefilepathcacheLong, "true", null, null, Strings.Options.VerboseDeprecated), + new CommandLineArgument("use-block-cache", CommandLineArgument.ArgumentType.Boolean, Strings.Options.UseblockcacheShort, Strings.Options.UseblockcacheLong, "false"), + new CommandLineArgument("changed-files", CommandLineArgument.ArgumentType.Path, Strings.Options.ChangedfilesShort, Strings.Options.ChangedfilesLong), + new CommandLineArgument("deleted-files", CommandLineArgument.ArgumentType.Path, Strings.Options.DeletedfilesShort, Strings.Options.DeletedfilesLong("changed-files")), + new CommandLineArgument("disable-synthetic-filelist", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisablesyntheticfilelistShort, Strings.Options.DisablesyntehticfilelistLong, "false"), + + new CommandLineArgument("threshold", CommandLineArgument.ArgumentType.Integer, Strings.Options.ThresholdShort, Strings.Options.ThresholdLong, DEFAULT_THRESHOLD.ToString()), + new CommandLineArgument("index-file-policy", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.IndexfilepolicyShort, Strings.Options.IndexfilepolicyLong, IndexFileStrategy.Full.ToString(), null, Enum.GetNames(typeof(IndexFileStrategy))), + new CommandLineArgument("no-backend-verification", CommandLineArgument.ArgumentType.Boolean, Strings.Options.NobackendverificationShort, Strings.Options.NobackendverificationLong, "false"), + new CommandLineArgument("backup-test-samples", CommandLineArgument.ArgumentType.Integer, Strings.Options.BackendtestsamplesShort, Strings.Options.BackendtestsamplesLong("no-backend-verification"), "1"), + new CommandLineArgument("backup-test-percentage", CommandLineArgument.ArgumentType.Integer, Strings.Options.BackendtestpercentageShort, Strings.Options.BackendtestpercentageLong, "0"), + new CommandLineArgument("full-remote-verification", CommandLineArgument.ArgumentType.Boolean, Strings.Options.FullremoteverificationShort, Strings.Options.FullremoteverificationLong("no-backend-verification"), "false"), + new CommandLineArgument("dry-run", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DryrunShort, Strings.Options.DryrunLong, "false", new string[] { "dryrun" }), + + new CommandLineArgument("block-hash-algorithm", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.BlockhashalgorithmShort, Strings.Options.BlockhashalgorithmLong, DEFAULT_BLOCK_HASH_ALGORITHM, null, GetSupportedHashes()), + new CommandLineArgument("file-hash-algorithm", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.FilehashalgorithmShort, Strings.Options.FilehashalgorithmLong, DEFAULT_FILE_HASH_ALGORITHM, null, GetSupportedHashes()), + + new CommandLineArgument("no-auto-compact", CommandLineArgument.ArgumentType.Boolean, Strings.Options.NoautocompactShort, Strings.Options.NoautocompactLong, "false"), + new CommandLineArgument("small-file-size", CommandLineArgument.ArgumentType.Size, Strings.Options.SmallfilesizeShort, Strings.Options.SmallfilesizeLong), + new CommandLineArgument("small-file-max-count", CommandLineArgument.ArgumentType.Integer, Strings.Options.SmallfilemaxcountShort, Strings.Options.SmallfilemaxcountLong, DEFAULT_SMALL_FILE_MAX_COUNT.ToString()), + + new CommandLineArgument("patch-with-local-blocks", CommandLineArgument.ArgumentType.Boolean, Strings.Options.PatchwithlocalblocksShort, Strings.Options.PatchwithlocalblocksLong, "false"), + new CommandLineArgument("no-local-db", CommandLineArgument.ArgumentType.Boolean, Strings.Options.NolocaldbShort, Strings.Options.NolocaldbLong, "false"), + new CommandLineArgument("dont-compress-restore-paths", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DontcompressrestorepathsShort, Strings.Options.DontcompressrestorepathsLong, "false"), + + new CommandLineArgument("keep-versions", CommandLineArgument.ArgumentType.Integer, Strings.Options.KeepversionsShort, Strings.Options.KeepversionsLong, DEFAULT_KEEP_VERSIONS.ToString()), + new CommandLineArgument("keep-time", CommandLineArgument.ArgumentType.Timespan, Strings.Options.KeeptimeShort, Strings.Options.KeeptimeLong), + new CommandLineArgument("retention-policy", CommandLineArgument.ArgumentType.String, Strings.Options.RetentionPolicyShort, Strings.Options.RetentionPolicyLong), + new CommandLineArgument("upload-verification-file", CommandLineArgument.ArgumentType.Boolean, Strings.Options.UploadverificationfileShort, Strings.Options.UploadverificationfileLong, "false"), + new CommandLineArgument("allow-passphrase-change", CommandLineArgument.ArgumentType.Boolean, Strings.Options.AllowpassphrasechangeShort, Strings.Options.AllowpassphrasechangeLong, "false"), + new CommandLineArgument("no-local-blocks", CommandLineArgument.ArgumentType.Boolean, Strings.Options.NolocalblocksShort, Strings.Options.NolocalblocksLong, "false"), + new CommandLineArgument("full-block-verification", CommandLineArgument.ArgumentType.Boolean, Strings.Options.FullblockverificationShort, Strings.Options.FullblockverificationLong, "false"), + new CommandLineArgument("allow-full-removal", CommandLineArgument.ArgumentType.Boolean, Strings.Options.AllowfullremovalShort, Strings.Options.AllowfullremovalLong, "false"), + + new CommandLineArgument("log-retention", CommandLineArgument.ArgumentType.Timespan, Strings.Options.LogretentionShort, Strings.Options.LogretentionLong, DEFAULT_LOG_RETENTION), + + new CommandLineArgument("repair-only-paths", CommandLineArgument.ArgumentType.Boolean, Strings.Options.RepaironlypathsShort, Strings.Options.RepaironlypathsLong, "false"), + new CommandLineArgument("force-locale", CommandLineArgument.ArgumentType.String, Strings.Options.ForcelocaleShort, Strings.Options.ForcelocaleLong), + new CommandLineArgument("force-actual-date", CommandLineArgument.ArgumentType.Boolean, Strings.Options.ForceActualDateShort, Strings.Options.ForceActualDateLong, "false"), + + new CommandLineArgument("disable-piped-streaming", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisablepipingShort, Strings.Options.DisablepipingLong, "false"), + + new CommandLineArgument("concurrency-max-threads", CommandLineArgument.ArgumentType.Integer, Strings.Options.ConcurrencymaxthreadsShort, Strings.Options.ConcurrencymaxthreadsLong, "0"), + new CommandLineArgument("concurrency-block-hashers", CommandLineArgument.ArgumentType.Integer, Strings.Options.ConcurrencyblockhashersShort, Strings.Options.ConcurrencyblockhashersLong, DEFAULT_BLOCK_HASHERS.ToString()), + new CommandLineArgument("concurrency-compressors", CommandLineArgument.ArgumentType.Integer, Strings.Options.ConcurrencycompressorsShort, Strings.Options.ConcurrencycompressorsLong, DEFAULT_COMPRESSORS.ToString()), + + new CommandLineArgument("auto-vacuum", CommandLineArgument.ArgumentType.Boolean, Strings.Options.AutoVacuumShort, Strings.Options.AutoVacuumLong, "false"), + new CommandLineArgument("disable-file-scanner", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisablefilescannerShort, Strings.Options.DisablefilescannerLong, "false"), + new CommandLineArgument("disable-filelist-consistency-checks", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisablefilelistconsistencychecksShort, Strings.Options.DisablefilelistconsistencychecksLong, "false"), + new CommandLineArgument("disable-on-battery", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DisableOnBatteryShort, Strings.Options.DisableOnBatteryLong, "false"), + + new CommandLineArgument("exclude-empty-folders", CommandLineArgument.ArgumentType.Boolean, Strings.Options.ExcludeemptyfoldersShort, Strings.Options.ExcludeemptyfoldersLong, "false"), + new CommandLineArgument("ignore-filenames", CommandLineArgument.ArgumentType.Path, Strings.Options.IgnorefilenamesShort, Strings.Options.IgnorefilenamesLong), + new CommandLineArgument("restore-symlink-metadata", CommandLineArgument.ArgumentType.Boolean, Strings.Options.RestoresymlinkmetadataShort, Strings.Options.RestoresymlinkmetadataLong, "false"), + new CommandLineArgument("rebuild-missing-dblock-files", CommandLineArgument.ArgumentType.Boolean, Strings.Options.RebuildmissingdblockfilesShort, Strings.Options.RebuildmissingdblockfilesLong, "false"), + + new CommandLineArgument("auto-compact-interval", CommandLineArgument.ArgumentType.Timespan, Strings.Options.AutoCompactIntervalShort, Strings.Options.AutoCompactIntervalLong, "0m"), + new CommandLineArgument("auto-vacuum-interval", CommandLineArgument.ArgumentType.Timespan, Strings.Options.AutoVacuumIntervalShort, Strings.Options.AutoVacuumIntervalLong, "0m"), + }); + + return lst; + } + } + + /// + /// Gets or sets the current main action of the instance + /// + public OperationMode MainAction + { + get { return (OperationMode)Enum.Parse(typeof(OperationMode), m_options["main-action"]); } + set { m_options["main-action"] = value.ToString(); } + } + + /// + /// Gets the size of each volume in bytes + /// + public long VolumeSize + { + get + { + string volsize; + m_options.TryGetValue("dblock-size", out volsize); + if (string.IsNullOrEmpty(volsize)) + volsize = DEFAULT_VOLUME_SIZE; + +#if DEBUG + return Math.Max(1024 * 10, Library.Utility.Sizeparser.ParseSize(volsize, "mb")); +#else + return Math.Max(1024 * 1024, Library.Utility.Sizeparser.ParseSize(volsize, "mb")); +#endif + } + } + + /// + /// Gets the maximum size of a single file + /// + public long SkipFilesLargerThan + { + get + { + if (!m_options.ContainsKey("skip-files-larger-than") || string.IsNullOrEmpty(m_options["skip-files-larger-than"])) + return long.MaxValue; + else + return Library.Utility.Sizeparser.ParseSize(m_options["skip-files-larger-than"], "mb"); + } + } + + /// + /// A value indicating if orphan files are deleted automatically + /// + public bool AutoCleanup { get { return GetBool("auto-cleanup"); } } + + /// + /// A value indicating if we are running in unittest mode + /// + public bool UnittestMode { get { return GetBool("unittest-mode"); } } + + + /// + /// Gets a list of files to add to the signature volumes + /// + public string ControlFiles + { + get + { + string v; + m_options.TryGetValue("control-files", out v); + return v; + } + } + + /// + /// A value indicating if file hash checks are skipped + /// + public bool SkipFileHashChecks { get { return GetBool("skip-file-hash-checks"); } } + + /// + /// A value indicating if the manifest files are not read + /// + public bool DontReadManifests { get { return GetBool("dont-read-manifests"); } } + + /// + /// Gets the backup that should be restored + /// + public DateTime Time + { + get + { + if (!m_options.ContainsKey("time") || string.IsNullOrEmpty(m_options["time"])) + return new DateTime(0, DateTimeKind.Utc); + else + return Library.Utility.Timeparser.ParseTimeInterval(m_options["time"], DateTime.Now); + } + } + + /// + /// Gets the versions the restore or list operation is limited to + /// + public long[] Version + { + get + { + string v; + m_options.TryGetValue("version", out v); + if (string.IsNullOrEmpty(v)) + return null; + + var versions = v.Split(new char[]{','}, StringSplitOptions.RemoveEmptyEntries); + if (v.Length == 0) + return null; + + var res = new List(); + foreach(var n in versions) + if (n.Contains('-')) + { + //TODO: Throw errors if too many entries? + var parts = n.Split(new char[]{'-'}, StringSplitOptions.RemoveEmptyEntries).Select(x => Convert.ToInt64(x.Trim())).ToArray(); + for(var i = Math.Min(parts[0], parts[1]); i <= Math.Max(parts[0], parts[1]); i++) + res.Add(i); + } + else + res.Add(Convert.ToInt64(n)); + + return res.ToArray(); + } + } + + /// + /// A value indicating if all versions are listed + /// + public bool AllVersions { get { return GetBool("all-versions"); } } + + /// + /// A value indicating if only the largest common prefix is returned + /// + public bool ListPrefixOnly { get { return GetBool("list-prefix-only"); } } + + /// + /// A value indicating if only folder contents are returned + /// + public bool ListFolderContents { get { return GetBool("list-folder-contents"); } } + + /// + /// A value indicating that only filesets are returned + /// + public bool ListSetsOnly { get { return GetBool("list-sets-only"); } } + + /// + /// A value indicating if file time checks are skipped + /// + public bool DisableFiletimeCheck { get { return GetBool("disable-filetime-check"); } } + + /// + /// A value indicating if file time checks are skipped + /// + public bool CheckFiletimeOnly { get { return GetBool("check-filetime-only"); } } + + /// + /// A value indicating if USN numbers are used to get list of changed files + /// + //public bool DisableUSNDiffCheck { get { return GetBool("disable-usn-diff-check"); } } + + /// + /// A value indicating if time tolerance is disabled + /// + public bool DisableTimeTolerance { get { return GetBool("disable-time-tolerance"); } } + + /// + /// Gets a value indicating whether a temporary folder has been specified + /// + public bool HasTempDir { get { return m_options.ContainsKey("tempdir") && !string.IsNullOrEmpty(m_options["tempdir"]); } } + + /// + /// Gets the folder where temporary files are stored + /// + public string TempDir + { + get + { + if (!m_options.ContainsKey("tempdir") || string.IsNullOrEmpty(m_options["tempdir"])) + { + return Duplicati.Library.Utility.TempFolder.SystemTempPath; + } + + return m_options["tempdir"]; + } + } + + /// + /// Gets a value indicating whether the user has forced the locale + /// + public bool HasForcedLocale { get { return m_options.ContainsKey("force-locale"); } } + + /// + /// Gets the forced locale for the current user + /// + public System.Globalization.CultureInfo ForcedLocale + { + get + { + if (!m_options.ContainsKey("force-locale")) + return System.Threading.Thread.CurrentThread.CurrentCulture; + else + { + var localestring = m_options["force-locale"]; + if (string.IsNullOrWhiteSpace(localestring)) + return System.Globalization.CultureInfo.InvariantCulture; + else + return new System.Globalization.CultureInfo(localestring); + } + } + } + + /// + /// Gets the process priority + /// + public string ThreadPriority + { + get + { + if (!m_options.ContainsKey("thread-priority") || string.IsNullOrEmpty(m_options["thread-priority"])) + return null; + else + return m_options["thread-priority"]; + } + } + + /// + /// A value indicating if missing folders should be created automatically + /// + public bool AutocreateFolders { get { return !GetBool("disable-autocreate-folder"); } } + + /// + /// Gets the backup prefix + /// + public string Prefix + { + get + { + string v; + m_options.TryGetValue("prefix", out v); + if (!string.IsNullOrEmpty(v)) + return v; + + return "duplicati"; + } + } + + /// + /// Gets the number of old backups to keep + /// + public int KeepVersions + { + get + { + string v; + m_options.TryGetValue("keep-versions", out v); + if (string.IsNullOrEmpty(v)) + return DEFAULT_KEEP_VERSIONS; + + return Math.Max(0, int.Parse(v)); + } + } + + /// + /// Gets the timelimit for removal + /// + public DateTime KeepTime + { + get + { + string v; + m_options.TryGetValue("keep-time", out v); + + if (string.IsNullOrEmpty(v)) + return new DateTime(0); + + TimeSpan tolerance = + this.DisableTimeTolerance ? + TimeSpan.FromSeconds(0) : + TimeSpan.FromSeconds(Math.Min(Library.Utility.Timeparser.ParseTimeSpan(v).TotalSeconds / 100, 60.0 * 60.0)); + + return Library.Utility.Timeparser.ParseTimeInterval(v, DateTime.Now, true) - tolerance; + } + } + + /// + /// Gets the time frames and intervals for the retention policy + /// + public List RetentionPolicy + { + get { + var retentionPolicyConfig = new List(); + + string v; + m_options.TryGetValue("retention-policy", out v); + if (string.IsNullOrEmpty(v)) { + return retentionPolicyConfig; + } + + var periodIntervalStrings = v.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + + foreach (var periodIntervalString in periodIntervalStrings) + { + retentionPolicyConfig.Add(RetentionPolicyValue.CreateFromString(periodIntervalString)); + } + + return retentionPolicyConfig; + } + } + + /// + /// Gets the encryption passphrase + /// + public string Passphrase + { + get + { + if (!m_options.ContainsKey("passphrase") || string.IsNullOrEmpty(m_options["passphrase"])) + return null; + else + return m_options["passphrase"]; + } + } + + /// + /// Helper method to set the default encryption mode based on the settings of the previous backup + /// + /// The encryption module used for the last entry + public void SetEncryptionModuleDefault(string lastSetting) + { + //If the encryption module was specified explicitly, don't change it + if (m_options.ContainsKey("no-encryption") || m_options.ContainsKey("encryption-module")) + return; + + if (string.IsNullOrEmpty(lastSetting)) + m_options["no-encryption"] = ""; + else + m_options["encryption-module"] = lastSetting; + } + + /// + /// A value indicating if backups are not encrypted + /// + public bool NoEncryption { get { return GetBool("no-encryption"); } } + + /// + /// Gets the module used for encryption + /// + public string EncryptionModule + { + get + { + //Disabled? + if (NoEncryption) + return null; + + //Specified? + if (m_options.ContainsKey("encryption-module")) + return m_options["encryption-module"]; + + return "aes"; + } + } + + /// + /// Helper method to set the default compression mode based on the settings of the previous backup + /// + /// The compression module used for the last entry + public void SetCompressionModuleDefault(string lastSetting) + { + //If a compression module is explicitly selected, don't change it + if (m_options.ContainsKey("compression-module")) + return; + + m_options["compression-module"] = lastSetting; + } + + /// + /// Gets the module used for compression + /// + public string CompressionModule + { + get + { + if (m_options.ContainsKey("compression-module")) + return m_options["compression-module"]; + else + return "zip"; + } + } + + + /// + /// Gets the number of time to retry transmission if it fails + /// + public int NumberOfRetries + { + get + { + if (!m_options.ContainsKey("number-of-retries") || string.IsNullOrEmpty(m_options["number-of-retries"])) + return 5; + else + { + int x = int.Parse(m_options["number-of-retries"]); + if (x < 0) + throw new UserInformationException("Invalid count for number-of-retries", "NumberOfRetriesInvalid"); + + return x; + } + } + } + + /// + /// A value indicating if backups are transmitted on a separate thread + /// + public bool SynchronousUpload { get { return Library.Utility.Utility.ParseBoolOption(m_options, "synchronous-upload"); } } + + /// + /// A value indicating if system is allowed to enter sleep power states during backup/restore + /// + public bool AllowSleep { get { return GetBool("allow-sleep"); } } + + /// + /// A value indicating if system should use the low-priority IO during backup/restore + /// + public bool UseBackgroundIOPriority { get { return GetBool("use-background-io-priority"); } } + + /// + /// A value indicating if use of the streaming interface is disallowed + /// + public bool DisableStreamingTransfers { get { return GetBool("disable-streaming-transfers"); } } + + /// + /// A value indicating if multithreaded pipes may be used for hashing and crypting on up-/downloads + /// + public bool DisablePipedStreaming { get { return GetBool("disable-piped-streaming"); } } + + /// + /// Gets the timelimit for removal + /// + public TimeSpan RetryDelay + { + get + { + if (!m_options.ContainsKey("retry-delay") || string.IsNullOrEmpty(m_options["retry-delay"])) + return new TimeSpan(TimeSpan.TicksPerSecond * 10); + else + return Library.Utility.Timeparser.ParseTimeSpan(m_options["retry-delay"]); + } + } + + /// + /// Gets the max upload speed in bytes pr. second + /// + public long MaxUploadPrSecond + { + get + { + lock(m_lock) + { + string v; + m_options.TryGetValue("throttle-upload", out v); + if (string.IsNullOrEmpty(v)) + return 0; + else + return Library.Utility.Sizeparser.ParseSize(v, "kb"); + } + } + set + { + lock (m_lock) + if (value <= 0) + m_options["throttle-upload"] = ""; + else + m_options["throttle-upload"] = value.ToString() + "b"; + } + } + + /// + /// Gets or sets the max download speed in bytes pr. second + /// + public long MaxDownloadPrSecond + { + get + { + lock (m_lock) + { + string v; + m_options.TryGetValue("throttle-download", out v); + if (string.IsNullOrEmpty(v)) + return 0; + else + return Library.Utility.Sizeparser.ParseSize(v, "kb"); + } + } + set + { + lock (m_lock) + if (value <= 0) + m_options["throttle-download"] = ""; + else + m_options["throttle-download"] = value.ToString() + "b"; + } + } + + /// + /// A value indicating if the backup is a full backup + /// + public bool AllowFullRemoval { get { return GetBool("allow-full-removal"); } } + + /// + /// A value indicating if debug output is enabled + /// + public bool DebugOutput { get { return GetBool("debug-output"); } } + + /// + /// A value indicating if unchanged backups are uploaded + /// + public bool UploadUnchangedBackups { get { return GetBool("upload-unchanged-backups"); } } + + /// + /// Gets a list of modules that should be loaded + /// + public string[] EnableModules + { + get + { + if (m_options.ContainsKey("enable-module")) + return m_options["enable-module"].Trim().ToLower(CultureInfo.InvariantCulture).Split(','); + else + return new string[0]; + } + } + + /// + /// Gets a list of modules that should not be loaded + /// + public string[] DisableModules + { + get + { + if (m_options.ContainsKey("disable-module")) + return m_options["disable-module"].Trim().ToLower(CultureInfo.InvariantCulture).Split(','); + else + return new string[0]; + } + } + + /// + /// Gets the snapshot strategy to use + /// + public OptimizationStrategy SnapShotStrategy + { + get + { + string strategy; + if (!m_options.TryGetValue("snapshot-policy", out strategy)) + strategy = ""; + + if (string.Equals(strategy, "on", StringComparison.OrdinalIgnoreCase)) + return OptimizationStrategy.On; + else if (string.Equals(strategy, "off", StringComparison.OrdinalIgnoreCase)) + return OptimizationStrategy.Off; + else if (string.Equals(strategy, "required", StringComparison.OrdinalIgnoreCase)) + return OptimizationStrategy.Required; + else if (string.Equals(strategy, "auto", StringComparison.OrdinalIgnoreCase)) + return OptimizationStrategy.Auto; + else + return OptimizationStrategy.Off; + } + } + + /// + /// Gets the symlink strategy to use + /// + public SymlinkStrategy SymlinkPolicy + { + get + { + string policy; + if (!m_options.TryGetValue("symlink-policy", out policy)) + policy = ""; + + SymlinkStrategy r; + if (!Enum.TryParse(policy, true, out r)) + r = SymlinkStrategy.Store; + + return r; + } + } + + /// + /// Gets the hardlink strategy to use + /// + public HardlinkStrategy HardlinkPolicy + { + get + { + string policy; + if (!m_options.TryGetValue("hardlink-policy", out policy)) + policy = ""; + + HardlinkStrategy r; + if (!Enum.TryParse(policy, true, out r)) + r = HardlinkStrategy.All; + + return r; + } + } + /// + /// Gets the update sequence number (USN) strategy to use + /// + public OptimizationStrategy UsnStrategy + { + get + { + string strategy; + if (!m_options.TryGetValue("usn-policy", out strategy)) + strategy = ""; + + if (string.Equals(strategy, "on", StringComparison.OrdinalIgnoreCase)) + return OptimizationStrategy.On; + else if (string.Equals(strategy, "off", StringComparison.OrdinalIgnoreCase)) + return OptimizationStrategy.Off; + else if (string.Equals(strategy, "required", StringComparison.OrdinalIgnoreCase)) + return OptimizationStrategy.Required; + else if (string.Equals(strategy, "auto", StringComparison.OrdinalIgnoreCase)) + return OptimizationStrategy.Auto; + else + return OptimizationStrategy.Off; + } + } + + /// + /// Gets the number of concurrent volume uploads allowed. Zero for unlimited. + /// + public int AsynchronousConcurrentUploadLimit + { + get + { + if (!m_options.TryGetValue("asynchronous-concurrent-upload-limit", out var value)) + value = null; + + if (string.IsNullOrEmpty(value)) + return 4; + else + return int.Parse(value); + } + } + + /// + /// Gets the number of volumes to create ahead of time when using async transfers, + /// a value of zero indicates no limit + /// + public long AsynchronousUploadLimit + { + get + { + string value; + if (!m_options.TryGetValue("asynchronous-upload-limit", out value)) + value = null; + + if (string.IsNullOrEmpty(value)) + return 4; + else + return long.Parse(value); + } + } + + /// + /// Gets the temporary folder to use for asyncronous transfers + /// + public string AsynchronousUploadFolder + { + get + { + string value; + if (!m_options.TryGetValue("asynchronous-upload-folder", out value)) + value = null; + + if (string.IsNullOrEmpty(value)) + return this.TempDir; + else + return value; + } + } + + /// + /// Gets the logfile filename + /// + public string Logfile + { + get + { + string value; + if (!m_options.TryGetValue("log-file", out value)) + value = null; + return value; + } + } + + /// + /// Gets the log-file detail level + /// + public Duplicati.Library.Logging.LogMessageType LogFileLoglevel + { + get + { + string value; + if (!m_options.TryGetValue("log-file-log-level", out value)) + value = null; + + if (string.IsNullOrWhiteSpace(value)) + if (!m_options.TryGetValue("log-level", out value)) + value = null; + + foreach (string s in Enum.GetNames(typeof(Duplicati.Library.Logging.LogMessageType))) + if (s.Equals(value, StringComparison.OrdinalIgnoreCase)) + return (Duplicati.Library.Logging.LogMessageType)Enum.Parse(typeof(Duplicati.Library.Logging.LogMessageType), s); + + return Duplicati.Library.Logging.LogMessageType.Warning; + } + } + + + + /// + /// Parses a log level string + /// + /// The log level enumeration value. + /// The string value to parse. + /// An optional fallback parsing value. + public static Logging.LogMessageType ParseLogLevel(string value, string backupvalue) + { + value = string.IsNullOrWhiteSpace(value) ? backupvalue : value; + foreach (string s in Enum.GetNames(typeof(Duplicati.Library.Logging.LogMessageType))) + if (s.Equals(value, StringComparison.OrdinalIgnoreCase)) + return (Duplicati.Library.Logging.LogMessageType)Enum.Parse(typeof(Duplicati.Library.Logging.LogMessageType), s); + + return Duplicati.Library.Logging.LogMessageType.Warning; + } + + /// + /// Gets the filter used for log-file messages. + /// + /// The log file filter. + public IFilter LogFileLogFilter + { + get + { + m_options.TryGetValue("log-file-log-filter", out var value); + return Library.Utility.FilterExpression.ParseLogFilter(value); + } + } + + /// + /// Gets the filter used for console messages. + /// + /// The log file filter. + public IFilter ConsoleLogFilter + { + get + { + m_options.TryGetValue("console-log-filter", out var value); + return Library.Utility.FilterExpression.ParseLogFilter(value); + } + } + + /// + /// Gets the console log detail level + /// + public Duplicati.Library.Logging.LogMessageType ConsoleLoglevel + { + get + { + string value; + if (!m_options.TryGetValue("console-log-level", out value)) + value = null; + + if (string.IsNullOrWhiteSpace(value)) + if (!m_options.TryGetValue("log-level", out value)) + value = null; + + foreach (string s in Enum.GetNames(typeof(Duplicati.Library.Logging.LogMessageType))) + if (s.Equals(value, StringComparison.OrdinalIgnoreCase)) + return (Duplicati.Library.Logging.LogMessageType)Enum.Parse(typeof(Duplicati.Library.Logging.LogMessageType), s); + + return Duplicati.Library.Logging.LogMessageType.Warning; + } + } + + /// + /// A value indicating if all database queries should be logged + /// + public bool ProfileAllDatabaseQueries { get { return GetBool("profile-all-database-queries"); } } + + /// + /// Gets the attribute filter used to exclude files and folders. + /// + public System.IO.FileAttributes FileAttributeFilter + { + get + { + System.IO.FileAttributes res = default(System.IO.FileAttributes); + string v; + if (!m_options.TryGetValue("exclude-files-attributes", out v)) + return res; + + foreach(string s in v.Split(new string[] {","}, StringSplitOptions.RemoveEmptyEntries)) + { + System.IO.FileAttributes f; + if (Enum.TryParse(s.Trim(), true, out f)) + res |= f; + } + + return res; + } + } + + /// + /// A value indicating if server uploads are verified by listing the folder contents + /// + public bool ListVerifyUploads { get { return GetBool("list-verify-uploads"); } } + + /// + /// A value indicating if connections cannot be re-used + /// + public bool NoConnectionReuse { get { return GetBool("no-connection-reuse"); } } + + /// + /// A value indicating if the returned value should not be truncated + /// + public bool FullResult { get { return GetBool("full-result"); } } + + /// + /// A value indicating restored files overwrite existing ones + /// + public bool Overwrite { get { return GetBool("overwrite"); } } + + /// + /// Gets the total size in bytes that the backend supports, returns -1 if there is no upper limit + /// + public long QuotaSize + { + get + { + if (!m_options.ContainsKey("quota-size") || string.IsNullOrEmpty(m_options["quota-size"])) + return -1; + else + return Library.Utility.Sizeparser.ParseSize(m_options["quota-size"], "mb"); + } + } + + /// + /// Gets the threshold at which a quota warning should be generated. + /// + /// + /// This is treated as a percentage, where a warning is given when the amount of free space is less than this percentage of the backup size. + /// + public int QuotaWarningThreshold + { + get + { + string tmp; + m_options.TryGetValue("quota-warning-threshold", out tmp); + if (string.IsNullOrEmpty(tmp)) + { + return DEFAULT_QUOTA_WARNING_THRESHOLD; + } + else + { + return int.Parse(tmp); + } + } + } + + /// + /// Gets the display name of the backup + /// + public string BackupName + { + get + { + string tmp; + m_options.TryGetValue("backup-name", out tmp); + if (string.IsNullOrEmpty(tmp)) + return DefaultBackupName; + else + return tmp; + } + set + { + m_options["backup-name"] = value; + } + } + + /// + /// Gets the path to the database + /// + public string Dbpath + { + get + { + string tmp; + m_options.TryGetValue("dbpath", out tmp); + return tmp; + } + set + { + m_options["dbpath"] = value; + } + } + + /// + /// Gets a value indicating whether a blocksize has been specified + /// + public bool HasBlocksize { get { return m_options.ContainsKey("blocksize") && !string.IsNullOrEmpty(m_options["blocksize"]); } } + + /// + /// Gets the size of file-blocks + /// + public int Blocksize + { + get + { + string tmp; + if (!m_options.TryGetValue("blocksize", out tmp)) + tmp = DEFAULT_BLOCKSIZE; + + long blocksize = Library.Utility.Sizeparser.ParseSize(tmp, "kb"); + if (blocksize > int.MaxValue || blocksize < 1024) + throw new ArgumentOutOfRangeException(nameof(blocksize), string.Format("The blocksize cannot be less than {0}, nor larger than {1}", 1024, int.MaxValue)); + + return (int)blocksize; + } + } + + /// + /// Cache for the block hash size value, to avoid creating new hash instances just to get the size + /// + private KeyValuePair m_cachedBlockHashSize; + + /// + /// Gets the size of the blockhash in bytes. + /// + /// The size of the blockhash. + public int BlockhashSize + { + get + { + if (m_cachedBlockHashSize.Key != BlockHashAlgorithm) + m_cachedBlockHashSize = new KeyValuePair(BlockHashAlgorithm, Duplicati.Library.Utility.HashAlgorithmHelper.Create(BlockHashAlgorithm).HashSize / 8); + + return m_cachedBlockHashSize.Value; + } + } + + /// + /// Gets the size the read-ahead buffer + /// + public long FileReadBufferSize + { + get + { + string tmp; + if (!m_options.TryGetValue("file-read-buffer-size", out tmp)) + tmp = DEFAULT_READ_BUFFER_SIZE; + + long t = Library.Utility.Sizeparser.ParseSize(tmp, "mb"); + return (int)t; + } + } + + /// + /// Gets a flag indicating if metadata for files and folders should be ignored + /// + public bool SkipMetadata + { + get { return Library.Utility.Utility.ParseBoolOption(m_options, "skip-metadata"); } + } + + /// + /// Gets a flag indicating if empty folders should be ignored + /// + public bool ExcludeEmptyFolders + { + get { return Library.Utility.Utility.ParseBoolOption(m_options, "exclude-empty-folders"); } + } + + /// + /// Gets a flag indicating if empty folders should be ignored + /// + public bool RestoreSymlinkMetadata + { + get { return Library.Utility.Utility.ParseBoolOption(m_options, "restore-symlink-metadata"); } + } + + /// + /// Gets a flag indicating if permissions should be restored + /// + public bool RestorePermissions + { + get { return Library.Utility.Utility.ParseBoolOption(m_options, "restore-permissions"); } + } + + + /// + /// Gets a flag indicating if file hashes are checked after a restore + /// + public bool PerformRestoredFileVerification + { + get { return !Library.Utility.Utility.ParseBoolOption(m_options, "skip-restore-verification"); } + } + + /// + /// Gets a flag indicating if synthetic filelist generation is disabled + /// + public bool DisableSyntheticFilelist + { + get { return Library.Utility.Utility.ParseBoolOption(m_options, "disable-synthetic-filelist"); } + } + + /// + /// Flag indicating if the in-memory block cache is used + /// + public bool UseBlockCache + { + get + { + return Library.Utility.Utility.ParseBoolOption(m_options, "use-block-cache"); + } + } + + + /// + /// Gets the compact threshold + /// + public long Threshold + { + get + { + string v; + m_options.TryGetValue("threshold", out v); + if (string.IsNullOrEmpty(v)) + return DEFAULT_THRESHOLD; + + return Convert.ToInt64(v); + } + } + + /// + /// Gets the size of small volumes + /// + public long SmallFileSize + { + get + { + string v; + m_options.TryGetValue("small-file-size", out v); + if (string.IsNullOrEmpty(v)) + return this.VolumeSize / 5; + + return Library.Utility.Sizeparser.ParseSize(v, "mb"); + } + } + + /// + /// Gets the maximum number of small volumes + /// + public long SmallFileMaxCount + { + get + { + string v; + m_options.TryGetValue("small-file-max-count", out v); + if (string.IsNullOrEmpty(v)) + return DEFAULT_SMALL_FILE_MAX_COUNT; + + return Convert.ToInt64(v); + } + } + + /// + /// List of files to check for changes + /// + public string[] ChangedFilelist + { + get + { + string v; + m_options.TryGetValue("changed-files", out v); + if (string.IsNullOrEmpty(v)) + return null; + + return v.Split(new char[] { System.IO.Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries); + } + } + + /// + /// List of files to mark as deleted + /// + public string[] DeletedFilelist + { + get + { + string v; + m_options.TryGetValue("deleted-files", out v); + if (string.IsNullOrEmpty(v)) + return null; + + return v.Split(new char[] { System.IO.Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries); + } + } + + /// + /// List of filenames that are used to exclude a folder + /// + public string[] IgnoreFilenames + { + get + { + string v; + m_options.TryGetValue("ignore-filenames", out v); + if (string.IsNullOrEmpty(v)) + return null; + + return v.Split(new char[] { System.IO.Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries); + } + } + /// + /// Alternate restore path + /// + public string Restorepath + { + get + { + string v; + m_options.TryGetValue("restore-path", out v); + return v; + } + } + + /// + /// Gets the index file usage method + /// + public IndexFileStrategy IndexfilePolicy + { + get + { + string strategy; + if (!m_options.TryGetValue("index-file-policy", out strategy)) + strategy = ""; + + IndexFileStrategy res; + if (!Enum.TryParse(strategy, true, out res)) + res = IndexFileStrategy.Full; + + return res; + } + } + + /// + /// Gets a flag indicating if the check for files on the remote storage should be omitted + /// + public bool NoBackendverification + { + get { return Library.Utility.Utility.ParseBoolOption(m_options, "no-backend-verification"); } + } + + /// + /// Gets the percentage of samples to test during a backup operation + /// + public long BackupTestPercentage + { + get + { + m_options.TryGetValue("backup-test-percentage", out string s); + if (string.IsNullOrEmpty(s)) + { + return 0; + } + + long percentage; + try + { + percentage = long.Parse(s); + } + catch (Exception ex) + { + throw new ArgumentException("The value provided for the backup-test-percentage option must lie between 0 and 100.", ex); + } + + if ((percentage < 0) || (percentage > 100)) + { + throw new ArgumentOutOfRangeException(nameof(percentage), "The value provided for the backup-test-percentage option must lie between 0 and 100."); + } + + return percentage; + } + } + + /// + /// Gets the number of samples to test during a backup operation + /// + public long BackupTestSampleCount + { + get + { + string s; + m_options.TryGetValue("backup-test-samples", out s); + if (string.IsNullOrEmpty(s)) + return 1; + + return long.Parse(s); + } + } + + /// + /// Gets a flag indicating if compacting should not be done automatically + /// + public bool NoAutoCompact + { + get { return Library.Utility.Utility.ParseBoolOption(m_options, "no-auto-compact"); } + } + + /// + /// Gets the minimum time that must elapse after last compaction before running next automatic compaction + /// + public TimeSpan AutoCompactInterval + { + get + { + if (!m_options.ContainsKey("auto-compact-interval") || string.IsNullOrEmpty(m_options["auto-compact-interval"])) + return TimeSpan.Zero; + else + return Library.Utility.Timeparser.ParseTimeSpan(m_options["auto-compact-interval"]); + } + } + + /// + /// Gets a flag indicating if compacting should not be done automatically + /// + public bool AllowMissingSource + { + get { return Library.Utility.Utility.ParseBoolOption(m_options, "allow-missing-source"); } + } + + /// + /// Gets a value indicating if a verification file should be uploaded after changing the remote store + /// + public bool UploadVerificationFile + { + get { return Library.Utility.Utility.ParseBoolOption(m_options, "upload-verification-file"); } + } + + /// + /// Gets a value indicating if a passphrase change is allowed + /// + public bool AllowPassphraseChange + { + get { return Library.Utility.Utility.ParseBoolOption(m_options, "allow-passphrase-change"); } + } + + /// + /// Gets a flag indicating if the current operation should merely output the changes + /// + public bool Dryrun + { + get + { + if (m_options.ContainsKey("dry-run")) + return Library.Utility.Utility.ParseBoolOption(m_options, "dry-run"); + else + return Library.Utility.Utility.ParseBoolOption(m_options, "dryrun"); + } + } + + /// + /// Gets a flag indicating if the current operation is intended to delete files older than a certain threshold + /// + public bool HasDeleteOlderThan + { + get { return m_options.ContainsKey("delete-older-than"); } + } + + /// + /// Gets a flag indicating if the current operation is intended to delete files older than a certain threshold + /// + public bool HasDeleteAllButN + { + get { return m_options.ContainsKey("delete-all-but-n") || m_options.ContainsKey("delete-all-but-n-full"); } + } + + + /// + /// Gets a flag indicating if the remote verification is deep + /// + public bool FullRemoteVerification + { + get { return Library.Utility.Utility.ParseBoolOption(m_options, "full-remote-verification"); } + } + + /// + /// The block hash algorithm to use + /// + public string BlockHashAlgorithm + { + get + { + string v; + m_options.TryGetValue("block-hash-algorithm", out v); + if (string.IsNullOrEmpty(v)) + return DEFAULT_BLOCK_HASH_ALGORITHM; + + return v; + } + } + + /// + /// The file hash algorithm to use + /// + public string FileHashAlgorithm + { + get + { + string v; + m_options.TryGetValue("file-hash-algorithm", out v); + if (string.IsNullOrEmpty(v)) + return DEFAULT_FILE_HASH_ALGORITHM; + + return v; + } + } + + /// + /// Gets a flag indicating if the current operation is intended to delete files older than a certain threshold + /// + public bool PatchWithLocalBlocks + { + get { return m_options.ContainsKey("patch-with-local-blocks"); } + } + + /// + /// Gets a value indicating whether local blocks usage should be skipped. + /// + /// true if no local blocks; otherwise, false. + public bool NoLocalBlocks + { + get { return Library.Utility.Utility.ParseBoolOption(m_options, "no-local-blocks"); } + } + + /// + /// Gets a flag indicating if the local database should not be used + /// + /// true if no local db is used; otherwise, false. + public bool NoLocalDb + { + get { return Library.Utility.Utility.ParseBoolOption(m_options, "no-local-db"); } + } + + /// + /// Gets a flag indicating if the local database should not be used + /// + /// true if no local db is used; otherwise, false. + public bool DontCompressRestorePaths + { + get { return Library.Utility.Utility.ParseBoolOption(m_options, "dont-compress-restore-paths"); } + } + + /// + /// Gets a flag indicating if block hashes are checked before being applied + /// + /// true if block hashes are checked; otherwise, false. + public bool FullBlockVerification + { + get { return Library.Utility.Utility.ParseBoolOption(m_options, "full-block-verification"); } + } + + /// + /// Gets a flag indicating if the repair process will only restore paths + /// + /// true if only paths are restored; otherwise, false. + public bool RepairOnlyPaths + { + get { return Library.Utility.Utility.ParseBoolOption(m_options, "repair-only-paths"); } + } + + /// + /// Gets a flag indicating whether the VACUUM operation should ever be run automatically. + /// + public bool AutoVacuum + { + get { return GetBool("auto-vacuum"); } + } + + /// + /// Gets the minimum time that must elapse after last vacuum before running next automatic vacuum + /// + public TimeSpan AutoVacuumInterval + { + get + { + if (!m_options.ContainsKey("auto-vacuum-interval") || string.IsNullOrEmpty(m_options["auto-vacuum-interval"])) + return TimeSpan.Zero; + else + return Library.Utility.Timeparser.ParseTimeSpan(m_options["auto-vacuum-interval"]); + } + } + + /// + /// Gets a flag indicating if the local filescanner should be disabled + /// + /// true if the filescanner should be disabled; otherwise, false. + public bool DisableFileScanner + { + get { return Library.Utility.Utility.ParseBoolOption(m_options, "disable-file-scanner"); } + } + + /// + /// Gets a flag indicating if the filelist consistency checks should be disabled + /// + /// true if the filelist consistency checks should be disabled; otherwise, false. + public bool DisableFilelistConsistencyChecks + { + get { return Library.Utility.Utility.ParseBoolOption(m_options, "disable-filelist-consistency-checks"); } + } + + /// + /// Gets a flag indicating whether the backup should be disabled when on battery power. + /// + /// true if the backup should be disabled when on battery power; otherwise, false. + public bool DisableOnBattery + { + get { return Library.Utility.Utility.ParseBoolOption(m_options, "disable-on-battery"); } + } + + /// + /// Gets a value indicating if missing dblock files are attempted created + /// + public bool RebuildMissingDblockFiles + { + get { return GetBool("rebuild-missing-dblock-files"); } + } + + /// + /// Gets the threshold for when log data should be cleaned + /// + public DateTime LogRetention + { + get + { + string pts; + if (!m_options.TryGetValue("log-retention", out pts)) + pts = DEFAULT_LOG_RETENTION; + + return Library.Utility.Timeparser.ParseTimeInterval(pts, DateTime.Now, true); + } + } + + + /// + /// Gets the number of concurrent threads + /// + public int ConcurrencyMaxThreads + { + get + { + string value; + if (!m_options.TryGetValue("concurrency-max-threads", out value)) + value = null; + + if (string.IsNullOrEmpty(value)) + return 0; + else + return int.Parse(value); + } + } + + /// + /// Gets the number of concurrent block hashers + /// + public int ConcurrencyBlockHashers + { + get + { + string value; + if (!m_options.TryGetValue("concurrency-block-hashers", out value)) + value = null; + + if (string.IsNullOrEmpty(value)) + return DEFAULT_BLOCK_HASHERS; + else + return Math.Max(1, int.Parse(value)); + } + } + + /// + /// Gets the number of concurrent block hashers + /// + public int ConcurrencyCompressors + { + get + { + string value; + if (!m_options.TryGetValue("concurrency-compressors", out value)) + value = null; + + if (string.IsNullOrEmpty(value)) + return DEFAULT_COMPRESSORS; + else + return Math.Max(1, int.Parse(value)); + } + } + + /// + /// Gets a lookup table with compression hints, the key is the file extension with the leading period + /// + public IDictionary CompressionHints + { + get + { + if (m_compressionHints == null) + { + var hints = new Dictionary(Library.Utility.Utility.ClientFilenameStringComparer); + + string file; + if (!m_options.TryGetValue("compression-extension-file", out file)) + file = DEFAULT_COMPRESSED_EXTENSION_FILE; + + if (!string.IsNullOrEmpty(file) && System.IO.File.Exists(file)) + foreach (var _line in Library.Utility.Utility.ReadFileWithDefaultEncoding(file).Split('\n')) + { + var line = _line.Trim(); + var lix = line.IndexOf(' '); + if (lix > 0) + line = line.Substring(0, lix); + if (line.Length >= 2 && line[0] == '.') + hints[line] = CompressionHint.Noncompressible; + } + + //Don't try again, if the file does not exist + m_compressionHints = hints; + } + + return m_compressionHints; + } + } + + /// + /// Gets a compression hint from a filename + /// + /// The filename to get the hint for + /// The compression hint + public CompressionHint GetCompressionHintFromFilename(string filename) + { + CompressionHint h; + if (!CompressionHints.TryGetValue(System.IO.Path.GetExtension(filename), out h)) + return CompressionHint.Default; + return h; + } + + /// + /// Gets a list of modules, the key indicates if they are loaded + /// + public List> LoadedModules { get { return m_loadedModules; } } + + /// + /// Helper method to extract boolean values. + /// If the option is not present, it it's value is false. + /// If the option is present it's value is true, unless the option's value is false, off or 0 + /// + /// The name of the option to read + /// The interpreted value of the option + private bool GetBool(string name) + { + return Library.Utility.Utility.ParseBoolOption(m_options, name); + } + + /// + /// Class for handling a single RententionPolicy timeframe-interval-pair + /// + public class RetentionPolicyValue + { + public readonly TimeSpan Timeframe; + public readonly TimeSpan Interval; + + public RetentionPolicyValue(TimeSpan timeframe, TimeSpan interval) + { + if (timeframe < TimeSpan.Zero) + { + throw new ArgumentOutOfRangeException(nameof(timeframe), string.Format("The timeframe cannot be negative: '{0}'", timeframe)); + } + if (interval < TimeSpan.Zero) + { + throw new ArgumentOutOfRangeException(nameof(interval), string.Format("The interval cannot be negative: '{0}'", interval)); + } + + this.Timeframe = timeframe; + this.Interval = interval; + } + + /// + /// Returns whether this is an unlimited timeframe or not + /// + /// + public Boolean IsUnlimtedTimeframe() + { + // Timeframes equal or bigger than the maximum TimeSpan effectivly represent an unlimited timeframe + return Timeframe >= TimeSpan.MaxValue; + } + + /// + /// Returns whether all versions in this timeframe should be kept or not + /// + /// + public Boolean IsKeepAllVersions() + { + /// Intervals between two versions that are equal or smaller than zero effectivly result in + /// all versions in that timeframe being kept. + return Interval <= TimeSpan.Zero; + } + + public override string ToString() + { + return (IsUnlimtedTimeframe() ? "Unlimited" : Timeframe.ToString()) + " / " + (IsKeepAllVersions() ? "Keep all" : Interval.ToString()); + } + + /// + /// Parses a string representation of a timeframe-interval-pair and returns a RentionPolicyValue object + /// + /// + public static RetentionPolicyValue CreateFromString(string rententionPolicyValueString) + { + var periodInterval = rententionPolicyValueString.Split(':'); + + TimeSpan timeframe; + // Timeframe "U" (= Unlimited) means: For unlimted time keep one version every X interval. + // So the timeframe has to span the maximum time possible. + if (String.Equals(periodInterval[0], "U", StringComparison.OrdinalIgnoreCase)) + { + timeframe = TimeSpan.MaxValue; + } + else + { + timeframe = Library.Utility.Timeparser.ParseTimeSpan(periodInterval[0]); + } + + TimeSpan interval; + // Interval "U" (= Unlimited) means: For period X keep all versions. + // So the interval between two versions has to be zero. + if (String.Equals(periodInterval[1], "U", StringComparison.OrdinalIgnoreCase)) + { + interval = TimeSpan.Zero; + } + else + { + interval = Library.Utility.Timeparser.ParseTimeSpan(periodInterval[1]); + } + + return new RetentionPolicyValue(timeframe, interval); + } + } + } +} diff --git a/Duplicati/Library/Main/Strings.cs b/Duplicati/Library/Main/Strings.cs index da8cc7448..8fba44aac 100644 --- a/Duplicati/Library/Main/Strings.cs +++ b/Duplicati/Library/Main/Strings.cs @@ -1,297 +1,299 @@ -using System; -using Duplicati.Library.Localization.Short; - -namespace Duplicati.Library.Main.Strings -{ - internal static class Controller - { - public static string HashMismatchError(string filename, string recordedhash, string actualhash) { return LC.L(@"Hash mismatch on file ""{0}"", recorded hash: {1}, actual hash {2}", filename, recordedhash, actualhash); } - public static string DownloadedFileSizeError(string filename, long actualsize, long expectedsize) { return LC.L(@"The file {0} was downloaded and had size {1} but the size was expected to be {2}", filename, actualsize, expectedsize); } - public static string DeprecatedOptionUsedWarning(string optionname, string message) { return LC.L(@"The option {0} is deprecated: {1}", optionname, message); } - public static string DuplicateOptionNameWarning(string optionname) { return LC.L(@"The option --{0} exists more than once, please report this to the developers", optionname); } - public static string NoSourceFoldersError { get { return LC.L(@"No source folders specified for backup"); } } - public static string SourceIsMissingError(string foldername) { return LC.L(@"The source folder {0} does not exist, aborting backup", foldername); } - public static string SourceUnauthorizedError(string foldername) { return LC.L(@"Unauthorized to access source folder {0}, aborting backup", foldername); } - public static string UnsupportedBooleanValue(string optionname, string value) { return LC.L(@"The value ""{1}"" supplied to --{0} does not parse into a valid boolean, this will be treated as if it was set to ""true""", optionname, value); } - public static string UnsupportedEnumerationValue(string optionname, string value, string[] values) { return LC.L(@"The option --{0} does not support the value ""{1}"", supported values are: {2}", optionname, value, string.Join(", ", values)); } - public static string UnsupportedFlagsValue(string optionname, string value, string[] values) { return LC.L(@"The option --{0} does not support the value ""{1}"", supported flag values are: {2}", optionname, value, string.Join(", ", values)); } - public static string UnsupportedIntegerValue(string optionname, string value) { return LC.L(@"The value ""{1}"" supplied to --{0} does not represent a valid integer", optionname, value); } - public static string UnsupportedOptionDisabledModuleWarning(string optionname, string modulename) { return LC.L(@"The option --{0} is not supported because the module {1} is not currently loaded", optionname, modulename); } - public static string UnsupportedOptionWarning(string optionname) { return LC.L(@"The supplied option --{0} is not supported and will be ignored", optionname); } - public static string UnsupportedPathValue(string optionname, string value) { return LC.L(@"The value ""{1}"" supplied to --{0} does not represent a valid path", optionname, value); } - public static string UnsupportedSizeValue(string optionname, string value) { return LC.L(@"The value ""{1}"" supplied to --{0} does not represent a valid size", optionname, value); } - public static string UnsupportedTimeValue(string optionname, string value) { return LC.L(@"The value ""{1}"" supplied to --{0} does not represent a valid time", optionname, value); } - public static string StartingOperationMessage(OperationMode operationname) { return LC.L(@"The operation {0} has started", operationname); } - public static string CompletedOperationMessage(OperationMode operationname) { return LC.L(@"The operation {0} has completed", operationname); } - public static string FailedOperationMessage(OperationMode operationname, string errormessage) { return LC.L(@"The operation {0} has failed with error: {1}", operationname, errormessage); } - public static string InvalidPathError(string path, string message) { return LC.L(@"Invalid path: ""{0}"" ({1})", path, message); } - public static string FailedForceLocaleError(string exMsg) { return LC.L(@"Failed to apply 'force-locale' setting. Please try to update .NET-Framework. Exception was: ""{0}"" ", exMsg); } - public static string SourceVolumeNameInvalidError(string filename) { return LC.L(@"The source {0} uses an invalid volume name, aborting backup", filename); } - public static string SourceVolumeNameNotFoundError(string filename, Guid volumeGuid) { return LC.L(@"The source {0} is on volume {1}, which could not be found, aborting backup", filename, volumeGuid); } - public static string NonQualifiedSizeValue(string optionname, string value) { return LC.L(@"The size ""{1}"" supplied to --{0} does not have a multiplier (b, kb, mb, etc). A multiplier is recommended to avoid unexpected changes if the program is updated.", optionname, value); } - } - - internal static class Options - { - public static string AutocleanupLong { get { return LC.L(@"If a backup is interrupted there will likely be partial files present on the backend. Using this flag, Duplicati will automatically remove such files when encountered."); } } - public static string AutocleanupShort { get { return LC.L(@"A flag indicating that Duplicati should remove unused files"); } } - public static string PrefixLong { get { return LC.L(@"A string used to prefix the filenames of the remote volumes, can be used to store multiple backups in the same remote folder. The prefix cannot contain a hyphen (-), but can contain all other characters allowed by the remote storage."); } } - public static string PrefixShort { get { return LC.L(@"Remote filename prefix"); } } - public static string DisablefiletimecheckLong { get { return LC.L(@"The operating system keeps track of the last time a file was written. Using this information, Duplicati can quickly determine if the file has been modified. If some application deliberately modifies this information, Duplicati won't work correctly unless this flag is set."); } } - public static string DisablefiletimecheckShort { get { return LC.L(@"Disable checks based on file time"); } } - public static string RestorepathLong { get { return LC.L(@"By default, files will be restored in the source folders, use this option to restore to another folder"); } } - public static string RestorepathShort { get { return LC.L(@"Restore to another folder"); } } - public static string AllowsleepShort { get { return LC.L(@"Toggles system sleep mode"); } } - public static string AllowsleepLong { get { return LC.L(@"Allow system to enter sleep power modes for inactivity during backup/restore operations (Windows/OSX only)"); } } - public static string ThrottledownloadLong { get { return LC.L(@"By setting this value you can limit how much bandwidth Duplicati consumes for downloads. Setting this limit can make the backups take longer, but will make Duplicati less intrusive."); } } - public static string ThrottledownloadShort { get { return LC.L(@"Max number of kilobytes to download pr. second"); } } - public static string ThrottleuploadLong { get { return LC.L(@"By setting this value you can limit how much bandwidth Duplicati consumes for uploads. Setting this limit can make the backups take longer, but will make Duplicati less intrusive."); } } - public static string ThrottleuploadShort { get { return LC.L(@"Max number of kilobytes to upload pr. second"); } } - public static string NoencryptionLong { get { return LC.L(@"If you store the backups on a local disk, and prefer that they are kept unencrypted, you can turn of encryption completely by using this switch."); } } - public static string NoencryptionShort { get { return LC.L(@"Disable encryption"); } } - public static string NumberofretriesLong { get { return LC.L(@"If an upload or download fails, Duplicati will retry a number of times before failing. Use this to handle unstable network connections better."); } } - public static string NumberofretriesShort { get { return LC.L(@"Number of times to retry a failed transmission"); } } - public static string PassphraseLong { get { return LC.L(@"Supply a passphrase that Duplicati will use to encrypt the backup volumes, making them unreadable without the passphrase. This variable can also be supplied through the environment variable PASSPHRASE."); } } - public static string PassphraseShort { get { return LC.L(@"Passphrase used to encrypt backups"); } } - public static string TimeLong { get { return LC.L(@"By default, Duplicati will list and restore files from the most recent backup, use this option to select another item. You may use relative times, like ""-2M"" for a backup from two months ago."); } } - public static string TimeShort { get { return LC.L(@"The time to list/restore files"); } } - public static string VersionLong { get { return LC.L(@"By default, Duplicati will list and restore files from the most recent backup, use this option to select another item. You may enter multiple values separated with comma, and ranges using -, e.g. ""0,2-4,7"" ."); } } - public static string VersionShort { get { return LC.L(@"The version to list/restore files"); } } - public static string AllversionsLong { get { return LC.L(@"When searching for files, only the most recent backup is searched. Use this option to show all previous versions too."); } } - public static string AllversionsShort { get { return LC.L(@"Show all versions"); } } - public static string ListprefixonlyLong { get { return LC.L(@"When searching for files, all matching files are returned. Use this option to return only the largest common prefix path."); } } - public static string ListprefixonlyShort { get { return LC.L(@"Show largest prefix"); } } - public static string ListfoldercontentsLong { get { return LC.L(@"When searching for files, all matching files are returned. Use this option to return only the entries found in the folder specified as filter."); } } - public static string ListfoldercontentsShort { get { return LC.L(@"Show folder contents"); } } - public static string RetrydelayLong { get { return LC.L(@"After a failed transmission, Duplicati will wait a short period before attempting again. This is useful if the network drops out occasionally during transmissions."); } } - public static string RetrydelayShort { get { return LC.L(@"Time to wait between retries"); } } - public static string ControlfilesLong { get { return LC.L(@"Use this option to attach extra files to the newly uploaded filelists."); } } - public static string ControlfilesShort { get { return LC.L(@"Set control files"); } } - public static string SkipfilehashchecksLong { get { return LC.L(@"If the hash for the volume does not match, Duplicati will refuse to use the backup. Supply this flag to allow Duplicati to proceed anyway."); } } - public static string SkipfilehashchecksShort { get { return LC.L(@"Set this flag to skip hash checks"); } } - public static string SkipfileslargerthanLong { get { return LC.L(@"This option allows you to exclude files that are larger than the given value. Use this to prevent backups becoming extremely large."); } } - public static string SkipfileslargerthanShort { get { return LC.L(@"Limit the size of files being backed up"); } } - public static string TempdirShort { get { return LC.L(@"Temporary storage folder"); } } - public static string TempdirLong { get { return LC.L(@"This option can be used to supply an alternative folder for temporary storage. By default the system default temporary folder is used. Note that also SQLite will put temporary files in this temporary folder."); } } - public static string ThreadpriorityLong { get { return LC.L(@"Selects another thread priority for the process. Use this to set Duplicati to be more or less CPU intensive."); } } - public static string ThreadpriorityShort { get { return LC.L(@"Thread priority"); } } - public static string DblocksizeLong { get { return LC.L(@"This option can change the maximum size of dblock files. Changing the size can be useful if the backend has a limit on the size of each individual file"); } } - public static string DblocksizeShort { get { return LC.L(@"Limit the size of the volumes"); } } - public static string DisableStreamingLong { get { return LC.L(@"Enabling this option will disallow usage of the streaming interface, which means that transfer progress bars will not show, and bandwidth throttle settings will be ignored."); } } - public static string DisableStreamingShort { get { return LC.L(@"Disables use of the streaming transfer method"); } } - public static string DontreadmanifestsLong { get { return LC.L(@"This option will make sure the contents of the manifest file are not read. This also implies that file hashes are not checked either. Use only for disaster recovery."); } } - public static string DontreadmanifestsShort { get { return LC.L(@"An option that prevents verifying the manifests"); } } - public static string CompressionmoduleLong { get { return LC.L(@"Duplicati supports pluggable compression modules. Use this option to select a module to use for compression. This is only applied when creating new volumes, when reading an existing file, the filename is used to select the compression module."); } } - public static string CompressionmoduleShort { get { return LC.L(@"Select what module to use for compression"); } } - public static string EncryptionmoduleLong { get { return LC.L(@"Duplicati supports pluggable encryption modules. Use this option to select a module to use for encryption. This is only applied when creating new volumes, when reading an existing file, the filename is used to select the encryption module."); } } - public static string EncryptionmoduleShort { get { return LC.L(@"Select what module to use for encryption"); } } - public static string DisablemoduleLong { get { return LC.L(@"Supply one or more module names, separated by commas to unload them"); } } - public static string DisablemoduleShort { get { return LC.L(@"Disabled one or more modules"); } } - public static string EnablemoduleLong { get { return LC.L(@"Supply one or more module names, separated by commas to load them"); } } - public static string EnablemoduleShort { get { return LC.L(@"Enables one or more modules"); } } - public static string SnapshotpolicyLong { get { return LC.L(@"This setting controls the usage of snapshots, which allows Duplicati to backup files that are locked by other programs. If this is set to ""off"", Duplicati will not attempt to create a disk snapshot. Setting this to ""auto"" makes Duplicati attempt to create a snapshot, and fail silently if that was not allowed or supported (note that the OS may still log system warnings). A setting of ""on"" will also make Duplicati attempt to create a snapshot, but will produce a warning message in the log if it fails. Setting it to ""required"" will make Duplicati abort the backup if the snapshot creation fails. On windows this uses the Volume Shadow Copy Services (VSS) and requires administrative privileges. On Linux this uses Logical Volume Management (LVM) and requires root privileges."); } } - public static string SnapshotpolicyShort { get { return LC.L(@"Controls the use of disk snapshots"); } } - public static string AsynchronousuploadfolderLong { get { return LC.L(@"The pre-generated volumes will be placed into the temporary folder by default, this option can set a different folder for placing the temporary volumes, despite the name, this also works for synchronous runs"); } } - public static string AsynchronousuploadfolderShort { get { return LC.L(@"The path where ready volumes are placed until uploaded"); } } - public static string AsynchronousuploadlimitLong { get { return LC.L(@"When performing asynchronous uploads, Duplicati will create volumes that can be uploaded. To prevent Duplicati from generating too many volumes, this option limits the number of pending uploads. Set to zero to disable the limit"); } } - public static string AsynchronousuploadlimitShort { get { return LC.L(@"The number of volumes to create ahead of time"); } } - public static string AsynchronousconcurrentuploadlimitLong { get { return LC.L(@"When performing asynchronous uploads, the maximum number of concurrent uploads allowed. Set to zero to disable the limit."); } } - public static string AsynchronousconcurrentuploadlimitShort { get { return LC.L(@"The number of concurrent uploads allowed"); } } - public static string DebugoutputLong { get { return LC.L(@"Activating this option will make some error messages more verbose, which may help you track down a particular issue"); } } - public static string DebugoutputShort { get { return LC.L(@"Enables debugging output"); } } - public static string LogfileShort { get { return LC.L(@"Log internal information to a file"); } } - public static string LogfileLong { get { return LC.L(@"Logs information to the file specified"); } } - public static string LoglevelLong { get { return LC.L(@"Specifies the amount of log information to write into the file specified by --log-file"); } } - public static string LoglevelShort { get { return LC.L(@"Log information level"); } } - public static string LogLevelDeprecated(string option1, string option2) { return LC.L("Use the {0} and {1} options instead", option1, option2); } - public static string DisableautocreatefolderLong { get { return LC.L(@"If Duplicati detects that the target folder is missing, it will create it automatically. Activate this option to prevent automatic folder creation."); } } - public static string DisableautocreatefolderShort { get { return LC.L(@"Disables automatic folder creation"); } } - public static string VssexcludewritersLong { get { return LC.L(@"Use this option to exclude faulty writers from a snapshot. This is equivalent to the -wx flag of the vshadow.exe tool, except that it only accepts writer class GUIDs, and not component names or instance GUIDs. Multiple GUIDs must be separated with a semicolon, and most forms of GUIDs are allowed, including with and without curly braces."); } } - public static string VssexcludewritersShort { get { return LC.L(@"A semicolon separated list of guids of VSS writers to exclude (Windows only)"); } } - public static string UsnpolicyLong { get { return LC.L(@"This setting controls the usage of NTFS USN numbers, which allows Duplicati to obtain a list of files and folders much faster. If this is set to ""off"", Duplicati will not attempt to use USN. Setting this to ""auto"" makes Duplicati attempt to use USN, and fail silently if that was not allowed or supported. A setting of ""on"" will also make Duplicati attempt to use USN, but will produce a warning message in the log if it fails. Setting it to ""required"" will make Duplicati abort the backup if the USN usage fails. This feature is only supported on Windows and requires administrative privileges."); } } - public static string UsnpolicyShort { get { return LC.L(@"Controls the use of NTFS Update Sequence Numbers"); } } - public static string DisableusndiffcheckLong { get { return LC.L(@"If USN is enabled the USN numbers are used to find all changed files since last backup. Use this option to disable the use of USN numbers, which will make Duplicati investigate all source files. This option is primarily intended for testing and should not be disabled in a production environment. If USN is not enabled, this option has no effect."); } } - public static string DisableusndiffcheckShort { get { return LC.L(@"Disables changelist by USN numbers"); } } - public static string DisabletimetoleranceLong { get { return LC.L(@"When matching timestamps, Duplicati will adjust the times by a small fraction to ensure that minor time differences do not cause unexpected updates. If the option --{0} is set to keep a week of backups, and the backup is made the same time each week, it is possible that the clock drifts slightly, such that full week has just passed, causing Duplicati to delete the older backup earlier than expected. To avoid this, Duplicati inserts a 1% tolerance (max 1 hour). Use this option to disable the tolerance, and use strict time checking", "--keep-time"); } } - public static string DisabletimetoleranceShort { get { return LC.L(@"Deactivates tolerance when comparing times"); } } - public static string ListverifyuploadsShort { get { return LC.L(@"Verify uploads by listing contents"); } } - public static string SynchronousuploadLong { get { return LC.L(@"Duplicati will upload files while scanning the disk and producing volumes, which usually makes the backup faster. Use this flag to turn the behavior off, so that Duplicati will wait for each volume to complete."); } } - public static string SynchronousuploadShort { get { return LC.L(@"Upload files synchronously"); } } - public static string NoconnectionreuseLong { get { return LC.L(@"Duplicati will attempt to perform multiple operations on a single connection, as this avoids repeated login attempts, and thus speeds up the process. This option can be used to ensure that each operation is performed on a seperate connection"); } } - public static string NoconnectionreuseShort { get { return LC.L(@"Do not re-use connections"); } } - public static string DebugretryerrorsLong { get { return LC.L(@"When an error occurs, Duplicati will silently retry, and only report the number of retries. Enable this option to have the error messages displayed when a retry is performed."); } } - public static string DebugretryerrorsShort { get { return LC.L(@"Show error messages when a retry is performed"); } } - public static string UploadUnchangedBackupsLong { get { return LC.L(@"If no files have changed, Duplicati will not upload a backup set. If the backup data is used to verify that a backup was executed, this option will make Duplicati upload a backupset even if it is empty"); } } - public static string UploadUnchangedBackupsShort { get { return LC.L(@"Upload empty backup files"); } } - public static string QuotasizeLong { get { return LC.L(@"This value can be used to set a known upper limit on the amount of space a backend has. If the backend reports the size itself, this value is ignored"); } } - public static string QuotasizeShort { get { return LC.L(@"A reported maximum storage"); } } - public static string QuotaWarningThresholdLong { get { return LC.L(@"Sets a threshold for when to warn about the backend quota being nearly exceeded. It is given as a percentage, and a warning is generated if the amount of available quota is less than this percentage of the total backup size. If the backend does not report the quota information, this value will be ignored"); } } - public static string QuotaWarningThresholdShort { get { return LC.L(@"Threshold for warning about low quota"); } } - public static string SymlinkpolicyShort { get { return LC.L(@"Symlink handling"); } } - public static string SymlinkpolicyLong(string store, string ignore, string follow) { return LC.L(@"Use this option to handle symlinks differently. The ""{0}"" option will simply record a symlink with its name and destination, and a restore will recreate the symlink as a link. Use the option ""{1}"" to ignore all symlinks and not store any information about them. Previous versions of Duplicati used the setting ""{2}"", which will cause symlinked files to be included and restore as normal files.", store, ignore, follow); } - public static string HardlinkpolicyShort { get { return LC.L(@"Hardlink handling"); } } - public static string HardlinkpolicyLong(string first, string all, string none) { return LC.L(@"Use this option to handle hardlinks (only works on Linux/OSX). The ""{0}"" option will record a hardlink ID for each hardlink to avoid storing hardlinked paths multiple times. The option ""{1}"" will ignore hardlink information, and treat each hardlink as a unique path. The option ""{2}"" will ignore all hardlinks with more than one link.", first, all, none); } - public static string ExcludefilesattributesShort { get { return LC.L(@"Exclude files by attribute"); } } - public static string ExcludefilesattributesLong(string[] attributes) { return LC.L(@"Use this option to exclude files with certain attributes. Use a comma separated list of attribute names to specify more than one. Possible values are: {0}", string.Join(", ", attributes)); } - public static string VssusemappingLong { get { return LC.L(@"Activate this option to map VSS snapshots to a drive (similar to SUBST, using Win32 DefineDosDevice). This will create temporary drives that are then used to access the contents of a snapshot. This workaround can speed up file access on Windows XP."); } } - public static string VssusemappingShort { get { return LC.L(@"Map snapshots to a drive (Windows only)"); } } - public static string BackupnameLong { get { return LC.L(@"A display name that is attached to this backup. Can be used to identify the backup when sending mail or running scripts."); } } - public static string BackupnameShort { get { return LC.L(@"Name of the backup"); } } - public static string CompressionextensionfileLong(string path) { return LC.L(@"This property can be used to point to a text file where each line contains a file extension that indicates a non-compressible file. Files that have an extension found in the file will not be compressed, but simply stored in the archive. The file format ignores any lines that do not start with a period, and considers a space to indicate the end of the extension. A default file is supplied, that also serves as an example. The default file is placed in {0}.", path); } - public static string CompressionextensionfileShort { get { return LC.L(@"Manage non-compressible file extensions"); } } - public static string BlockhashlookupsizeLong { get { return LC.L(@"A fragment of memory is used to reduce database lookups. You should not change this value unless you get warnings in the log."); } } - public static string BlockhashlookupsizeShort { get { return LC.L(@"Memory used by the block hash"); } } - public static string BlocksizeLong { get { return LC.L(@"The block size determines how files are fragmented. Choosing a large value will cause a larger overhead on file changes, choosing a small value will cause a large overhead on storage of file lists. Note that the value cannot be changed after remote files are created."); } } - public static string BlocksizeShort { get { return LC.L(@"Block size used in hashing"); } } - public static string ChangedfilesLong { get { return LC.L(@"This option can be used to limit the scan to only files that are known to have changed. This is usually only activated in combination with a filesystem watcher that keeps track of file changes."); } } - public static string ChangedfilesShort { get { return LC.L(@"List of files to examine for changes"); } } - public static string DbpathLong { get { return LC.L(@"Path to the file containing the local cache of the remote file database"); } } - public static string DbpathShort { get { return LC.L(@"Path to the local state database"); } } - public static string DeletedfilesLong(string optionname) { return LC.L(@"This option can be used to supply a list of deleted files. This option will be ignored unless the option --{0} is also set.", optionname); } - public static string DeletedfilesShort { get { return LC.L(@"List of deleted files"); } } - public static string FilehashlookupsizeLong { get { return LC.L(@"A fragment of memory is used to reduce database lookups. You should not change this value unless you get warnings in the log."); } } - public static string FilehashlookupsizeShort { get { return LC.L(@"Memory used by the file hash"); } } - public static string DisablefilepathcacheLong { get { return LC.L(@"This option can be used to reduce the memory footprint by not keeping paths and modification timestamps in memory"); } } - public static string DisablefilepathcacheShort { get { return LC.L(@"Reduce memory footprint by disabling in-memory lookups"); } } - public static string UseblockcacheShort { get { return LC.L(@"This option can be used to increase speed in exchange for extra memory use."); } } - public static string UseblockcacheLong { get { return LC.L(@"Store an in-memory block cache"); } } - public static string MetadatahashlookupsizeLong { get { return LC.L(@"A fragment of memory is used to reduce database lookups. You should not change this value unless you get warnings in the log."); } } - public static string MetadatahashlookupsizeShort { get { return LC.L(@"Memory used by the metadata hash"); } } - public static string NobackendverificationLong { get { return LC.L(@"If this flag is set, the local database is not compared to the remote filelist on startup. The intended usage for this option is to work correctly in cases where the filelisting is broken or unavailable."); } } - public static string NobackendverificationShort { get { return LC.L(@"Do not query backend at startup"); } } - public static string IndexfilepolicyLong { get { return LC.L(@"The index files are used to limit the need for downloading dblock files when there is no local database present. The more information is recorded in the index files, the faster operations can proceed without the database. The tradeoff is that larger index files take up more remote space and which may never be used."); } } - public static string IndexfilepolicyShort { get { return LC.L(@"Determines usage of index files"); } } - public static string ThresholdLong { get { return LC.L(@"As files are changed, some data stored at the remote destination may not be required. This option controls how much wasted space the destination can contain before being reclaimed. This value is a percentage used on each volume and the total storage."); } } - public static string ThresholdShort { get { return LC.L(@"The maximum wasted space in percent"); } } - public static string DryrunLong { get { return LC.L(@"This option can be used to experiment with different settings and observe the outcome without changing actual files."); } } - public static string DryrunShort { get { return LC.L(@"Does not perform any modifications"); } } - public static string BlockhashalgorithmLong { get { return LC.L(@"This is a very advanced option! This option can be used to select a block hash algorithm with smaller or larger hash size, for performance or storage space reasons."); } } - public static string BlockhashalgorithmShort { get { return LC.L(@"The hash algorithm used on blocks"); } } - public static string FilehashalgorithmLong { get { return LC.L(@"This is a very advanced option! This option can be used to select a file hash algorithm with smaller or larger hash size, for performance or storage space reasons."); } } - public static string FilehashalgorithmShort { get { return LC.L(@"The hash algorithm used on files"); } } - public static string NoautocompactLong { get { return LC.L(@"If a large number of small files are detected during a backup, or wasted space is found after deleting backups, the remote data will be compacted. Use this option to disable such automatic compacting and only compact when running the compact command."); } } - public static string NoautocompactShort { get { return LC.L(@"Disable automatic compacting"); } } - public static string SmallfilesizeLong { get { return LC.L(@"When examining the size of a volume in consideration for compacting, a small tolerance value is used, by default 20 percent of the volume size. This ensures that large volumes which may have a few bytes wasted space are not downloaded and rewritten."); } } - public static string SmallfilesizeShort { get { return LC.L(@"Volume size threshold"); } } - public static string SmallfilemaxcountLong { get { return LC.L(@"To avoid filling the remote storage with small files, this value can force grouping small files. The small volumes will always be combined when they can fill an entire volume."); } } - public static string SmallfilemaxcountShort { get { return LC.L(@"Maximum number of small volumes"); } } - public static string PatchwithlocalblocksLong { get { return LC.L(@"Enable this option to look into other files on this machine to find existing blocks. This is a fairly slow operation but can limit the size of downloads."); } } - public static string PatchwithlocalblocksShort { get { return LC.L(@"Use local file data when restoring"); } } - public static string NolocaldbShort { get { return LC.L(@"Disables the local database"); } } - public static string NolocaldbLong { get { return LC.L(@"When listing contents or when restoring files, the local database can be skipped. This is usually slower, but can be used to verify the actual contents of the remote store"); } } - public static string KeepversionsShort { get { return LC.L(@"Keep a number of versions"); } } - public static string KeepversionsLong { get { return LC.L(@"Use this option to set number of versions to keep, supply -1 to keep all versions"); } } - public static string KeeptimeShort { get { return LC.L(@"Keep all versions within a timespan"); } } - public static string KeeptimeLong { get { return LC.L(@"Use this option to set the timespan in which backups are kept."); } } - public static string RetentionPolicyShort { get { return LC.L(@"Reduce number of versions by deleting old intermediate backups"); } } - public static string RetentionPolicyLong { get { return LC.L(@"Use this option to reduce the number of versions that are kept with increasing version age by deleting most of the old backups. The expected format is a comma separated list of colon separated time frame and interval pairs. For example the value ""7D:0s,3M:1D,10Y:2M"" means ""For 7 day keep all backups, for 3 months keep one backup every day, for 10 years one backup every 2nd month and delete every backup older than this."". This option also supports using the specifier ""U"" to indicate an unlimited time interval."); } } - public static string AllowmissingsourceShort { get { return LC.L(@"Ignore missing source elements"); } } - public static string AllowmissingsourceLong { get { return LC.L(@"Use this option to continue even if some source entries are missing."); } } - public static string OverwriteShort { get { return LC.L(@"Overwrite files when restoring"); } } - public static string OverwriteLong { get { return LC.L(@"Use this option to overwrite target files when restoring, if this option is not set the files will be restored with a timestamp and a number appended."); } } - public static string VerboseShort { get { return LC.L(@"Output more progress information"); } } - public static string VerboseLong { get { return LC.L(@"Use this option to increase the amount of output generated when running an option. Generally this option will produce a line for each file processed."); } } - public static string VerboseDeprecated { get { return LC.L(@"Set a log-level for the desired output method instead"); } } - public static string FullresultShort { get { return LC.L(@"Output full results"); } } - public static string FullresultLong { get { return LC.L(@"Use this option to increase the amount of output generated as the result of the operation, including all filenames."); } } - public static string UploadverificationfileShort { get { return LC.L(@"Determine if verification files are uploaded"); } } - public static string UploadverificationfileLong { get { return LC.L(@"Use this option to upload a verification file after changing the remote storage. The file is not encrypted and contains the size and SHA256 hashes of all the remote files and can be used to verify the integrity of the files."); } } - public static string BackendtestsamplesShort { get { return LC.L(@"The number of samples to test after a backup"); } } - public static string BackendtestsamplesLong(string optionname) { return LC.L(@"After a backup is completed, some (dblock, dindex, dlist) files from the remote backend are selected for verification. Use this option to change how many. If the backup-test-percentage option is also provided, the number of samples tested is the maximum implied by the two options. If this value is set to 0 or the option --{0} is set, no remote files are verified", optionname); } - public static string BackendtestpercentageShort { get { return LC.L(@"The percentage of samples to test after a backup"); } } - public static string BackendtestpercentageLong { get { return LC.L(@"After a backup is completed, some (dblock, dindex, dlist) files from the remote backend are selected for verification. Use this option to specify the percentage (between 0 and 100) of files to test. If the backup-test-samples option is also provided, the number of samples tested is the maximum implied by the two options. If the no-backend-verification option is provided, no remote files are verified."); } } - public static string FullremoteverificationShort { get { return LC.L(@"Activates in-depth verification of files"); } } - public static string FullremoteverificationLong(string optionname) { return LC.L(@"After a backup is completed, some (dblock, dindex, dlist) files from the remote backend are selected for verification. Use this option to turn on full verification, which will decrypt the files and examine the insides of each volume, instead of simply verifying the external hash, If the option --{0} is set, no remote files are verified. This option is automatically set when then verification is performed directly.", optionname); } - public static string FilereadbuffersizeShort { get { return LC.L(@"Size of the file read buffer"); } } - public static string FilereadbuffersizeLong { get { return LC.L(@"Use this size to control how many bytes are read from a file before processing"); } } - public static string AllowpassphrasechangeShort { get { return LC.L(@"Allow the passphrase to change"); } } - public static string AllowpassphrasechangeLong { get { return LC.L(@"Use this option to allow the passphrase to change, note that this option is not permitted for a backup or repair operation"); } } - public static string ListsetsonlyShort { get { return LC.L(@"List only filesets"); } } - public static string ListsetsonlyLong { get { return LC.L(@"Use this option to only list filesets and avoid traversing file names and other metadata which slows down the process"); } } - - public static string SkipmetadataShort { get { return LC.L(@"Don't store metadata"); } } - public static string SkipmetadataLong { get { return LC.L(@"Use this option to disable the storage of metadata, such as file timestamps. Disabling metadata storage will speed up the backup and restore operations, but does not affect file size much."); } } - public static string RestorepermissionsShort { get { return LC.L(@"Restore file permissions"); } } - public static string RestorepermissionsLong { get { return LC.L(@"By default permissions are not restored as they might prevent you from accessing your files. Use this option to restore the permissions as well."); } } - public static string SkiprestoreverificationShort { get { return LC.L(@"Skip restored file check"); } } - public static string SkiprestoreverificationLong { get { return LC.L(@"After restoring files, the file hash of all restored files are checked to verify that the restore was successful. Use this option to disable the check and avoid waiting for the verification."); } } - public static string OldmemorylookupdefaultsShort { get { return LC.L(@"Activate caches"); } } - public static string OldmemorylookupdefaultsLong { get { return LC.L(@"Activate in-memory caches, which are now off by default"); } } - public static string NolocalblocksShort { get { return LC.L(@"Do not use local data"); } } - public static string NolocalblocksLong { get { return LC.L(@"Duplicati will attempt to use data from source files to minimize the amount of downloaded data. Use this option to skip this optimization and only use remote data."); } } - public static string FullblockverificationShort { get { return LC.L(@"Check block hashes"); } } - public static string FullblockverificationLong { get { return LC.L(@"Use this option to increase verification by checking the hash of blocks read from a volume before patching restored files with the data."); } } - public static string LogretentionShort { get { return LC.L(@"Clean up old log data"); } } - public static string LogretentionLong { get { return LC.L(@"Set the time after which log data will be purged from the database."); } } - public static string RepaironlypathsShort { get { return LC.L(@"Repair database with paths"); } } - public static string RepaironlypathsLong { get { return LC.L(@"Use this option to build a searchable local database which only contains path information. This option is usable for quickly building a database to locate certain content without needing to reconstruct all information. The resulting database can be searched, but cannot be used to restore data with."); } } - public static string ForcelocaleShort { get { return LC.L(@"Force the locale setting"); } } - public static string ForcelocaleLong { get { return LC.L(@"By default, your system locale and culture settings will be used. In some cases you may prefer to run with another locale, for example to get messages in another language. This option can be used to set the locale. Supply a blank string to choose the ""Invariant Culture""."); } } - public static string DisablepipingShort{ get { return LC.L(@"Handle file communication with backend using threaded pipes"); } } - public static string DisablepipingLong { get { return LC.L(@"Use this option to disable multithreaded handling of up- and downloads, that can significantly speed up backend operations depending on the hardware you're running on and the transfer rate of your backend."); } } - public static string ConcurrencymaxthreadsShort{ get { return LC.L(@"Limit number of concurrent threads"); } } - public static string ConcurrencymaxthreadsLong { get { return LC.L(@"Use this option to set the maximum number of threads used. Setting this value to zero or less will dynamically balance the number of active threads to fit the hardware."); } } - public static string ConcurrencyblockhashersShort{ get { return LC.L(@"Specify the number of concurrent hashing processes"); } } - public static string ConcurrencyblockhashersLong { get { return LC.L(@"Use this option to set the number of processes that perform hashing of data."); } } - public static string ConcurrencycompressorsShort{ get { return LC.L(@"Specify the number of concurrent compression processes"); } } - public static string ConcurrencycompressorsLong { get { return LC.L(@"Use this option to set the number of processes that perform compression of output data."); } } - public static string HypervbackupvmShort { get { return LC.L(@"Perform backup of Hyper-V machines (Windows only)"); } } - public static string HypervbackupvmLong { get { return LC.L(@"Use this option to specify the IDs of machines to include in the backup. Specify multiple machine IDs with a semicolon separator. (You can use this Powershell command to get ID 'Get-VM | ft VMName, ID')"); } } - public static string DisablesyntehticfilelistLong { get { return LC.L(@"If Duplicati detects that the previous backup did not complete, it will generate a filelist that is a merge of the last completed backup and the contents that were uploaded in the incomplete backup session."); } } - public static string DisablesyntheticfilelistShort { get { return LC.L(@"Disables synthetic filelist"); } } - public static string CheckfiletimeonlyLong { get { return LC.L(@"This flag instructs Duplicati to not look at metadata or filesize when deciding to scan a file for changes. Use this option if you have a large number of files and notice that the scanning takes a long time with unmodified files."); } } - public static string CheckfiletimeonlyShort { get { return LC.L(@"Checks only file lastmodified"); } } - public static string DontcompressrestorepathsShort { get { return LC.L(@"Disables path compression on restore"); } } - public static string DontcompressrestorepathsLong { get { return LC.L(@"When restore a subset of a backup into a new folder, the shortest possible path is used to avoid generating deep paths with empty folders. Use this flag to skip this compression, such that the entire original folder structure is preserved, including upper level empty folders."); } } - public static string AllowfullremovalShort { get { return LC.L(@"Allow removing all filesets"); } } - public static string AllowfullremovalLong { get { return LC.L(@"By default, the last fileset cannot be removed. This is a safeguard to make sure that all remote data is not deleted by a configuration mistake. Use this flag to disable that protection, such that all filesets can be deleted."); } } - public static string AutoVacuumShort { get { return LC.L(@"Allow automatic rebuilding of local database to save space."); } } - public static string AutoVacuumLong { get { return LC.L(@"Some operations that manipulate the local database leave unused entries behind. These entries are not deleted from a hard drive until a VACUUM operation is run. This operation saves disk space in the long run but needs to temporarily create a copy of all valid entries in the database. Setting this to true will allow Duplicati to perform VACUUM operations at its discretion."); } } - public static string DisablefilescannerShort { get { return LC.L(@"Disable the read-ahead scanner"); } } - public static string DisablefilescannerLong { get { return LC.L(@"When this flag is enabled, the scanner that computes the size of source files is disabled, and instead the reported size is read from the database. Using this flag can speed up the backup by reducing disk access, but will give a less accurate progress indicator."); } } - public static string DisablefilelistconsistencychecksShort { get { return LC.L(@"Disable filelist consistency checks"); } } - public static string DisablefilelistconsistencychecksLong { get { return LC.L(@"In backups with a large number of filesets, the verification can take up a large part of the backup time. If you disable the checks, make sure you run regular check commands to ensure that everything is working as expected."); } } - public static string DisableOnBatteryShort { get { return LC.L("Disable the backup when on battery power"); } } - public static string DisableOnBatteryLong { get { return LC.L("When this flag is enabled, a scheduled backup will not run if the system is detected to be running on battery power (manual or command line backups will still be run). If the detected power source is mains (i.e., AC) or unknown, then scheduled backups will proceed as normal."); } } - - public static string LogfileloglevelLong { get { return LC.L(@"Specifies the amount of log information to write into the file specified by --log-file"); } } - public static string LogfileloglevelShort { get { return LC.L(@"Log file information level"); } } - public static string LogfilelogfiltersShort { get { return LC.L(@"Applies filters to the file log data"); } } - public static string LogfilelogfiltersLong(string delimiter) { return LC.L(@"This option accepts filters that removes or includes messages regardless of their log level. Multiple filters are supported by separating with {0}. Filters are matched against the log tag and assumed to be including, unless they start with '-'. Regular expressions are supported within hard braces. Example: ""+Path*{0}+*Mail*{0}-[.*DNS]"" ", delimiter); } - public static string ConsoleloglevelLong { get { return LC.L(@"Specifies the amount of log information to write as console output"); } } - public static string ConsoleloglevelShort { get { return LC.L(@"Console information level"); } } - public static string ConsolelogfiltersShort { get { return LC.L(@"Applies filters to the console log data"); } } - public static string ConsolelogfiltersLong(string delimiter) { return LogfilelogfiltersLong(delimiter); } - - public static string UsebackgroundiopriorityShort { get { return LC.L("Sets the process to use low IO priority"); } } - public static string UsebackgroundiopriorityLong { get { return LC.L("This option instructions the operating system to set the current process to use the lowest IO priority level, which can make operations run slower but will interfere less with other operations running at the same time"); } } - - public static string ExcludeemptyfoldersShort { get { return "Excludes empty folders"; } } - public static string ExcludeemptyfoldersLong { get { return "Use this option to remove all empty folders from a backup."; } } - public static string IgnorefilenamesShort { get { return LC.L("List of filenames that exclude folders"); } } - public static string IgnorefilenamesLong { get { return LC.L("Use this option to set a filename, or list of filenames, that indicate exclusion of a folder which contains it. A common use would be to have a file named something like \".nobackup\" and place this file into folders that should not be backed up."); } } - public static string RestoresymlinkmetadataShort { get { return "Apply metadata to symlinks"; } } - public static string RestoresymlinkmetadataLong { get { return "If symlink metadata is applied, it will usually mean changing the symlink target, instead of the symlink itself. For this reason, metadata is not applied to symlinks, but this option can be used to override this, such that metadata is applied to symlinks as well."; } } - public static string UnittestmodeShort { get { return "Activate unittest mode"; } } - public static string UnittestmodeLong { get { return "When running in unittest mode, no automatic fixes are applied, which assumes that the input data is always in perfect shape. This option is not intended for use in daily backups, but required for testing purposes to reveal potential problems."; } } - - public static string ProfilealldatabasequeriesShort { get { return LC.L("Activates logging of all database queries"); } } - public static string ProfilealldatabasequeriesLong { get { return LC.L("To improve performance of the backups, frequent database queries are not logged by default. Enable this option to log all database queries, and remember to set either --{0}={2} or --{1}={2} to report the additional log data", "console-log-level", "log-file-log-level", nameof(Logging.LogMessageType.Profiling)); } } - public static string RebuildmissingdblockfilesShort { get { return "Rebuild dblock files when missing"; } } - public static string RebuildmissingdblockfilesLong { get { return "If dblock files are missing from the destination, you can attempt to rebuild them using local source data. However, since the local data may have changed, it may not be possible to retrieve all the required data and the process may be slow. Use this option to attempt to rebuild missing dblock files."; } } - - public static string AutoCompactIntervalShort { get { return "Minimum time between auto compactions"; } } - public static string AutoCompactIntervalLong { get { return "The minimum amount of time that must elapse after the last compaction before another will be automatically triggered at the end of a backup job. Automatic compaction can be a long-running process and may not be desirable to run after every single backup."; } } - public static string AutoVacuumIntervalShort { get { return "Minimum time between auto vacuums"; } } - public static string AutoVacuumIntervalLong { get { return "The minimum amount of time that must elapse after the last vacuum before another will be automatically triggered at the end of a backup job. Automatic vacuum can be a long-running process and may not be desirable to run after every single backup."; } } - } - - internal static class Common - { - public static string InvalidCryptoSystem(string algorithm) { return LC.L(@"The cryptolibrary does not support re-usable transforms for the hash algorithm {0}", algorithm); } - public static string InvalidHashAlgorithm(string algorithm) { return LC.L(@"The cryptolibrary does not support the hash algorithm {0}", algorithm); } - public static string PassphraseChangeUnsupported { get { return LC.L(@"The passphrase cannot be changed for an existing backup"); } } - public static string SnapshotFailedError(string message) { return LC.L(@"Failed to create a snapshot: {0}", message); } - } - -} +using System; +using Duplicati.Library.Localization.Short; + +namespace Duplicati.Library.Main.Strings +{ + internal static class Controller + { + public static string HashMismatchError(string filename, string recordedhash, string actualhash) { return LC.L(@"Hash mismatch on file ""{0}"", recorded hash: {1}, actual hash {2}", filename, recordedhash, actualhash); } + public static string DownloadedFileSizeError(string filename, long actualsize, long expectedsize) { return LC.L(@"The file {0} was downloaded and had size {1} but the size was expected to be {2}", filename, actualsize, expectedsize); } + public static string DeprecatedOptionUsedWarning(string optionname, string message) { return LC.L(@"The option {0} is deprecated: {1}", optionname, message); } + public static string DuplicateOptionNameWarning(string optionname) { return LC.L(@"The option --{0} exists more than once, please report this to the developers", optionname); } + public static string NoSourceFoldersError { get { return LC.L(@"No source folders specified for backup"); } } + public static string SourceIsMissingError(string foldername) { return LC.L(@"The source folder {0} does not exist, aborting backup", foldername); } + public static string SourceUnauthorizedError(string foldername) { return LC.L(@"Unauthorized to access source folder {0}, aborting backup", foldername); } + public static string UnsupportedBooleanValue(string optionname, string value) { return LC.L(@"The value ""{1}"" supplied to --{0} does not parse into a valid boolean, this will be treated as if it was set to ""true""", optionname, value); } + public static string UnsupportedEnumerationValue(string optionname, string value, string[] values) { return LC.L(@"The option --{0} does not support the value ""{1}"", supported values are: {2}", optionname, value, string.Join(", ", values)); } + public static string UnsupportedFlagsValue(string optionname, string value, string[] values) { return LC.L(@"The option --{0} does not support the value ""{1}"", supported flag values are: {2}", optionname, value, string.Join(", ", values)); } + public static string UnsupportedIntegerValue(string optionname, string value) { return LC.L(@"The value ""{1}"" supplied to --{0} does not represent a valid integer", optionname, value); } + public static string UnsupportedOptionDisabledModuleWarning(string optionname, string modulename) { return LC.L(@"The option --{0} is not supported because the module {1} is not currently loaded", optionname, modulename); } + public static string UnsupportedOptionWarning(string optionname) { return LC.L(@"The supplied option --{0} is not supported and will be ignored", optionname); } + public static string UnsupportedPathValue(string optionname, string value) { return LC.L(@"The value ""{1}"" supplied to --{0} does not represent a valid path", optionname, value); } + public static string UnsupportedSizeValue(string optionname, string value) { return LC.L(@"The value ""{1}"" supplied to --{0} does not represent a valid size", optionname, value); } + public static string UnsupportedTimeValue(string optionname, string value) { return LC.L(@"The value ""{1}"" supplied to --{0} does not represent a valid time", optionname, value); } + public static string StartingOperationMessage(OperationMode operationname) { return LC.L(@"The operation {0} has started", operationname); } + public static string CompletedOperationMessage(OperationMode operationname) { return LC.L(@"The operation {0} has completed", operationname); } + public static string FailedOperationMessage(OperationMode operationname, string errormessage) { return LC.L(@"The operation {0} has failed with error: {1}", operationname, errormessage); } + public static string InvalidPathError(string path, string message) { return LC.L(@"Invalid path: ""{0}"" ({1})", path, message); } + public static string FailedForceLocaleError(string exMsg) { return LC.L(@"Failed to apply 'force-locale' setting. Please try to update .NET-Framework. Exception was: ""{0}"" ", exMsg); } + public static string SourceVolumeNameInvalidError(string filename) { return LC.L(@"The source {0} uses an invalid volume name, aborting backup", filename); } + public static string SourceVolumeNameNotFoundError(string filename, Guid volumeGuid) { return LC.L(@"The source {0} is on volume {1}, which could not be found, aborting backup", filename, volumeGuid); } + public static string NonQualifiedSizeValue(string optionname, string value) { return LC.L(@"The size ""{1}"" supplied to --{0} does not have a multiplier (b, kb, mb, etc). A multiplier is recommended to avoid unexpected changes if the program is updated.", optionname, value); } + } + + internal static class Options + { + public static string AutocleanupLong { get { return LC.L(@"If a backup is interrupted there will likely be partial files present on the backend. Using this flag, Duplicati will automatically remove such files when encountered."); } } + public static string AutocleanupShort { get { return LC.L(@"A flag indicating that Duplicati should remove unused files"); } } + public static string PrefixLong { get { return LC.L(@"A string used to prefix the filenames of the remote volumes, can be used to store multiple backups in the same remote folder. The prefix cannot contain a hyphen (-), but can contain all other characters allowed by the remote storage."); } } + public static string PrefixShort { get { return LC.L(@"Remote filename prefix"); } } + public static string DisablefiletimecheckLong { get { return LC.L(@"The operating system keeps track of the last time a file was written. Using this information, Duplicati can quickly determine if the file has been modified. If some application deliberately modifies this information, Duplicati won't work correctly unless this flag is set."); } } + public static string DisablefiletimecheckShort { get { return LC.L(@"Disable checks based on file time"); } } + public static string RestorepathLong { get { return LC.L(@"By default, files will be restored in the source folders, use this option to restore to another folder"); } } + public static string RestorepathShort { get { return LC.L(@"Restore to another folder"); } } + public static string AllowsleepShort { get { return LC.L(@"Toggles system sleep mode"); } } + public static string AllowsleepLong { get { return LC.L(@"Allow system to enter sleep power modes for inactivity during backup/restore operations (Windows/OSX only)"); } } + public static string ThrottledownloadLong { get { return LC.L(@"By setting this value you can limit how much bandwidth Duplicati consumes for downloads. Setting this limit can make the backups take longer, but will make Duplicati less intrusive."); } } + public static string ThrottledownloadShort { get { return LC.L(@"Max number of kilobytes to download pr. second"); } } + public static string ThrottleuploadLong { get { return LC.L(@"By setting this value you can limit how much bandwidth Duplicati consumes for uploads. Setting this limit can make the backups take longer, but will make Duplicati less intrusive."); } } + public static string ThrottleuploadShort { get { return LC.L(@"Max number of kilobytes to upload pr. second"); } } + public static string NoencryptionLong { get { return LC.L(@"If you store the backups on a local disk, and prefer that they are kept unencrypted, you can turn of encryption completely by using this switch."); } } + public static string NoencryptionShort { get { return LC.L(@"Disable encryption"); } } + public static string NumberofretriesLong { get { return LC.L(@"If an upload or download fails, Duplicati will retry a number of times before failing. Use this to handle unstable network connections better."); } } + public static string NumberofretriesShort { get { return LC.L(@"Number of times to retry a failed transmission"); } } + public static string PassphraseLong { get { return LC.L(@"Supply a passphrase that Duplicati will use to encrypt the backup volumes, making them unreadable without the passphrase. This variable can also be supplied through the environment variable PASSPHRASE."); } } + public static string PassphraseShort { get { return LC.L(@"Passphrase used to encrypt backups"); } } + public static string TimeLong { get { return LC.L(@"By default, Duplicati will list and restore files from the most recent backup, use this option to select another item. You may use relative times, like ""-2M"" for a backup from two months ago."); } } + public static string TimeShort { get { return LC.L(@"The time to list/restore files"); } } + public static string VersionLong { get { return LC.L(@"By default, Duplicati will list and restore files from the most recent backup, use this option to select another item. You may enter multiple values separated with comma, and ranges using -, e.g. ""0,2-4,7"" ."); } } + public static string VersionShort { get { return LC.L(@"The version to list/restore files"); } } + public static string AllversionsLong { get { return LC.L(@"When searching for files, only the most recent backup is searched. Use this option to show all previous versions too."); } } + public static string AllversionsShort { get { return LC.L(@"Show all versions"); } } + public static string ListprefixonlyLong { get { return LC.L(@"When searching for files, all matching files are returned. Use this option to return only the largest common prefix path."); } } + public static string ListprefixonlyShort { get { return LC.L(@"Show largest prefix"); } } + public static string ListfoldercontentsLong { get { return LC.L(@"When searching for files, all matching files are returned. Use this option to return only the entries found in the folder specified as filter."); } } + public static string ListfoldercontentsShort { get { return LC.L(@"Show folder contents"); } } + public static string RetrydelayLong { get { return LC.L(@"After a failed transmission, Duplicati will wait a short period before attempting again. This is useful if the network drops out occasionally during transmissions."); } } + public static string RetrydelayShort { get { return LC.L(@"Time to wait between retries"); } } + public static string ControlfilesLong { get { return LC.L(@"Use this option to attach extra files to the newly uploaded filelists."); } } + public static string ControlfilesShort { get { return LC.L(@"Set control files"); } } + public static string SkipfilehashchecksLong { get { return LC.L(@"If the hash for the volume does not match, Duplicati will refuse to use the backup. Supply this flag to allow Duplicati to proceed anyway."); } } + public static string SkipfilehashchecksShort { get { return LC.L(@"Set this flag to skip hash checks"); } } + public static string SkipfileslargerthanLong { get { return LC.L(@"This option allows you to exclude files that are larger than the given value. Use this to prevent backups becoming extremely large."); } } + public static string SkipfileslargerthanShort { get { return LC.L(@"Limit the size of files being backed up"); } } + public static string TempdirShort { get { return LC.L(@"Temporary storage folder"); } } + public static string TempdirLong { get { return LC.L(@"This option can be used to supply an alternative folder for temporary storage. By default the system default temporary folder is used. Note that also SQLite will put temporary files in this temporary folder."); } } + public static string ThreadpriorityLong { get { return LC.L(@"Selects another thread priority for the process. Use this to set Duplicati to be more or less CPU intensive."); } } + public static string ThreadpriorityShort { get { return LC.L(@"Thread priority"); } } + public static string DblocksizeLong { get { return LC.L(@"This option can change the maximum size of dblock files. Changing the size can be useful if the backend has a limit on the size of each individual file"); } } + public static string DblocksizeShort { get { return LC.L(@"Limit the size of the volumes"); } } + public static string DisableStreamingLong { get { return LC.L(@"Enabling this option will disallow usage of the streaming interface, which means that transfer progress bars will not show, and bandwidth throttle settings will be ignored."); } } + public static string DisableStreamingShort { get { return LC.L(@"Disables use of the streaming transfer method"); } } + public static string DontreadmanifestsLong { get { return LC.L(@"This option will make sure the contents of the manifest file are not read. This also implies that file hashes are not checked either. Use only for disaster recovery."); } } + public static string DontreadmanifestsShort { get { return LC.L(@"An option that prevents verifying the manifests"); } } + public static string CompressionmoduleLong { get { return LC.L(@"Duplicati supports pluggable compression modules. Use this option to select a module to use for compression. This is only applied when creating new volumes, when reading an existing file, the filename is used to select the compression module."); } } + public static string CompressionmoduleShort { get { return LC.L(@"Select what module to use for compression"); } } + public static string EncryptionmoduleLong { get { return LC.L(@"Duplicati supports pluggable encryption modules. Use this option to select a module to use for encryption. This is only applied when creating new volumes, when reading an existing file, the filename is used to select the encryption module."); } } + public static string EncryptionmoduleShort { get { return LC.L(@"Select what module to use for encryption"); } } + public static string DisablemoduleLong { get { return LC.L(@"Supply one or more module names, separated by commas to unload them"); } } + public static string DisablemoduleShort { get { return LC.L(@"Disabled one or more modules"); } } + public static string EnablemoduleLong { get { return LC.L(@"Supply one or more module names, separated by commas to load them"); } } + public static string EnablemoduleShort { get { return LC.L(@"Enables one or more modules"); } } + public static string SnapshotpolicyLong { get { return LC.L(@"This setting controls the usage of snapshots, which allows Duplicati to backup files that are locked by other programs. If this is set to ""off"", Duplicati will not attempt to create a disk snapshot. Setting this to ""auto"" makes Duplicati attempt to create a snapshot, and fail silently if that was not allowed or supported (note that the OS may still log system warnings). A setting of ""on"" will also make Duplicati attempt to create a snapshot, but will produce a warning message in the log if it fails. Setting it to ""required"" will make Duplicati abort the backup if the snapshot creation fails. On windows this uses the Volume Shadow Copy Services (VSS) and requires administrative privileges. On Linux this uses Logical Volume Management (LVM) and requires root privileges."); } } + public static string SnapshotpolicyShort { get { return LC.L(@"Controls the use of disk snapshots"); } } + public static string AsynchronousuploadfolderLong { get { return LC.L(@"The pre-generated volumes will be placed into the temporary folder by default, this option can set a different folder for placing the temporary volumes, despite the name, this also works for synchronous runs"); } } + public static string AsynchronousuploadfolderShort { get { return LC.L(@"The path where ready volumes are placed until uploaded"); } } + public static string AsynchronousuploadlimitLong { get { return LC.L(@"When performing asynchronous uploads, Duplicati will create volumes that can be uploaded. To prevent Duplicati from generating too many volumes, this option limits the number of pending uploads. Set to zero to disable the limit"); } } + public static string AsynchronousuploadlimitShort { get { return LC.L(@"The number of volumes to create ahead of time"); } } + public static string AsynchronousconcurrentuploadlimitLong { get { return LC.L(@"When performing asynchronous uploads, the maximum number of concurrent uploads allowed. Set to zero to disable the limit."); } } + public static string AsynchronousconcurrentuploadlimitShort { get { return LC.L(@"The number of concurrent uploads allowed"); } } + public static string DebugoutputLong { get { return LC.L(@"Activating this option will make some error messages more verbose, which may help you track down a particular issue"); } } + public static string DebugoutputShort { get { return LC.L(@"Enables debugging output"); } } + public static string LogfileShort { get { return LC.L(@"Log internal information to a file"); } } + public static string LogfileLong { get { return LC.L(@"Logs information to the file specified"); } } + public static string LoglevelLong { get { return LC.L(@"Specifies the amount of log information to write into the file specified by --log-file"); } } + public static string LoglevelShort { get { return LC.L(@"Log information level"); } } + public static string LogLevelDeprecated(string option1, string option2) { return LC.L("Use the {0} and {1} options instead", option1, option2); } + public static string DisableautocreatefolderLong { get { return LC.L(@"If Duplicati detects that the target folder is missing, it will create it automatically. Activate this option to prevent automatic folder creation."); } } + public static string DisableautocreatefolderShort { get { return LC.L(@"Disables automatic folder creation"); } } + public static string VssexcludewritersLong { get { return LC.L(@"Use this option to exclude faulty writers from a snapshot. This is equivalent to the -wx flag of the vshadow.exe tool, except that it only accepts writer class GUIDs, and not component names or instance GUIDs. Multiple GUIDs must be separated with a semicolon, and most forms of GUIDs are allowed, including with and without curly braces."); } } + public static string VssexcludewritersShort { get { return LC.L(@"A semicolon separated list of guids of VSS writers to exclude (Windows only)"); } } + public static string UsnpolicyLong { get { return LC.L(@"This setting controls the usage of NTFS USN numbers, which allows Duplicati to obtain a list of files and folders much faster. If this is set to ""off"", Duplicati will not attempt to use USN. Setting this to ""auto"" makes Duplicati attempt to use USN, and fail silently if that was not allowed or supported. A setting of ""on"" will also make Duplicati attempt to use USN, but will produce a warning message in the log if it fails. Setting it to ""required"" will make Duplicati abort the backup if the USN usage fails. This feature is only supported on Windows and requires administrative privileges."); } } + public static string UsnpolicyShort { get { return LC.L(@"Controls the use of NTFS Update Sequence Numbers"); } } + public static string DisableusndiffcheckLong { get { return LC.L(@"If USN is enabled the USN numbers are used to find all changed files since last backup. Use this option to disable the use of USN numbers, which will make Duplicati investigate all source files. This option is primarily intended for testing and should not be disabled in a production environment. If USN is not enabled, this option has no effect."); } } + public static string DisableusndiffcheckShort { get { return LC.L(@"Disables changelist by USN numbers"); } } + public static string DisabletimetoleranceLong { get { return LC.L(@"When matching timestamps, Duplicati will adjust the times by a small fraction to ensure that minor time differences do not cause unexpected updates. If the option --{0} is set to keep a week of backups, and the backup is made the same time each week, it is possible that the clock drifts slightly, such that full week has just passed, causing Duplicati to delete the older backup earlier than expected. To avoid this, Duplicati inserts a 1% tolerance (max 1 hour). Use this option to disable the tolerance, and use strict time checking", "--keep-time"); } } + public static string DisabletimetoleranceShort { get { return LC.L(@"Deactivates tolerance when comparing times"); } } + public static string ListverifyuploadsShort { get { return LC.L(@"Verify uploads by listing contents"); } } + public static string SynchronousuploadLong { get { return LC.L(@"Duplicati will upload files while scanning the disk and producing volumes, which usually makes the backup faster. Use this flag to turn the behavior off, so that Duplicati will wait for each volume to complete."); } } + public static string SynchronousuploadShort { get { return LC.L(@"Upload files synchronously"); } } + public static string NoconnectionreuseLong { get { return LC.L(@"Duplicati will attempt to perform multiple operations on a single connection, as this avoids repeated login attempts, and thus speeds up the process. This option can be used to ensure that each operation is performed on a seperate connection"); } } + public static string NoconnectionreuseShort { get { return LC.L(@"Do not re-use connections"); } } + public static string DebugretryerrorsLong { get { return LC.L(@"When an error occurs, Duplicati will silently retry, and only report the number of retries. Enable this option to have the error messages displayed when a retry is performed."); } } + public static string DebugretryerrorsShort { get { return LC.L(@"Show error messages when a retry is performed"); } } + public static string UploadUnchangedBackupsLong { get { return LC.L(@"If no files have changed, Duplicati will not upload a backup set. If the backup data is used to verify that a backup was executed, this option will make Duplicati upload a backupset even if it is empty"); } } + public static string UploadUnchangedBackupsShort { get { return LC.L(@"Upload empty backup files"); } } + public static string QuotasizeLong { get { return LC.L(@"This value can be used to set a known upper limit on the amount of space a backend has. If the backend reports the size itself, this value is ignored"); } } + public static string QuotasizeShort { get { return LC.L(@"A reported maximum storage"); } } + public static string QuotaWarningThresholdLong { get { return LC.L(@"Sets a threshold for when to warn about the backend quota being nearly exceeded. It is given as a percentage, and a warning is generated if the amount of available quota is less than this percentage of the total backup size. If the backend does not report the quota information, this value will be ignored"); } } + public static string QuotaWarningThresholdShort { get { return LC.L(@"Threshold for warning about low quota"); } } + public static string SymlinkpolicyShort { get { return LC.L(@"Symlink handling"); } } + public static string SymlinkpolicyLong(string store, string ignore, string follow) { return LC.L(@"Use this option to handle symlinks differently. The ""{0}"" option will simply record a symlink with its name and destination, and a restore will recreate the symlink as a link. Use the option ""{1}"" to ignore all symlinks and not store any information about them. Previous versions of Duplicati used the setting ""{2}"", which will cause symlinked files to be included and restore as normal files.", store, ignore, follow); } + public static string HardlinkpolicyShort { get { return LC.L(@"Hardlink handling"); } } + public static string HardlinkpolicyLong(string first, string all, string none) { return LC.L(@"Use this option to handle hardlinks (only works on Linux/OSX). The ""{0}"" option will record a hardlink ID for each hardlink to avoid storing hardlinked paths multiple times. The option ""{1}"" will ignore hardlink information, and treat each hardlink as a unique path. The option ""{2}"" will ignore all hardlinks with more than one link.", first, all, none); } + public static string ExcludefilesattributesShort { get { return LC.L(@"Exclude files by attribute"); } } + public static string ExcludefilesattributesLong(string[] attributes) { return LC.L(@"Use this option to exclude files with certain attributes. Use a comma separated list of attribute names to specify more than one. Possible values are: {0}", string.Join(", ", attributes)); } + public static string VssusemappingLong { get { return LC.L(@"Activate this option to map VSS snapshots to a drive (similar to SUBST, using Win32 DefineDosDevice). This will create temporary drives that are then used to access the contents of a snapshot. This workaround can speed up file access on Windows XP."); } } + public static string VssusemappingShort { get { return LC.L(@"Map snapshots to a drive (Windows only)"); } } + public static string BackupnameLong { get { return LC.L(@"A display name that is attached to this backup. Can be used to identify the backup when sending mail or running scripts."); } } + public static string BackupnameShort { get { return LC.L(@"Name of the backup"); } } + public static string CompressionextensionfileLong(string path) { return LC.L(@"This property can be used to point to a text file where each line contains a file extension that indicates a non-compressible file. Files that have an extension found in the file will not be compressed, but simply stored in the archive. The file format ignores any lines that do not start with a period, and considers a space to indicate the end of the extension. A default file is supplied, that also serves as an example. The default file is placed in {0}.", path); } + public static string CompressionextensionfileShort { get { return LC.L(@"Manage non-compressible file extensions"); } } + public static string BlockhashlookupsizeLong { get { return LC.L(@"A fragment of memory is used to reduce database lookups. You should not change this value unless you get warnings in the log."); } } + public static string BlockhashlookupsizeShort { get { return LC.L(@"Memory used by the block hash"); } } + public static string BlocksizeLong { get { return LC.L(@"The block size determines how files are fragmented. Choosing a large value will cause a larger overhead on file changes, choosing a small value will cause a large overhead on storage of file lists. Note that the value cannot be changed after remote files are created."); } } + public static string BlocksizeShort { get { return LC.L(@"Block size used in hashing"); } } + public static string ChangedfilesLong { get { return LC.L(@"This option can be used to limit the scan to only files that are known to have changed. This is usually only activated in combination with a filesystem watcher that keeps track of file changes."); } } + public static string ChangedfilesShort { get { return LC.L(@"List of files to examine for changes"); } } + public static string DbpathLong { get { return LC.L(@"Path to the file containing the local cache of the remote file database"); } } + public static string DbpathShort { get { return LC.L(@"Path to the local state database"); } } + public static string DeletedfilesLong(string optionname) { return LC.L(@"This option can be used to supply a list of deleted files. This option will be ignored unless the option --{0} is also set.", optionname); } + public static string DeletedfilesShort { get { return LC.L(@"List of deleted files"); } } + public static string FilehashlookupsizeLong { get { return LC.L(@"A fragment of memory is used to reduce database lookups. You should not change this value unless you get warnings in the log."); } } + public static string FilehashlookupsizeShort { get { return LC.L(@"Memory used by the file hash"); } } + public static string DisablefilepathcacheLong { get { return LC.L(@"This option can be used to reduce the memory footprint by not keeping paths and modification timestamps in memory"); } } + public static string DisablefilepathcacheShort { get { return LC.L(@"Reduce memory footprint by disabling in-memory lookups"); } } + public static string UseblockcacheShort { get { return LC.L(@"This option can be used to increase speed in exchange for extra memory use."); } } + public static string UseblockcacheLong { get { return LC.L(@"Store an in-memory block cache"); } } + public static string MetadatahashlookupsizeLong { get { return LC.L(@"A fragment of memory is used to reduce database lookups. You should not change this value unless you get warnings in the log."); } } + public static string MetadatahashlookupsizeShort { get { return LC.L(@"Memory used by the metadata hash"); } } + public static string NobackendverificationLong { get { return LC.L(@"If this flag is set, the local database is not compared to the remote filelist on startup. The intended usage for this option is to work correctly in cases where the filelisting is broken or unavailable."); } } + public static string NobackendverificationShort { get { return LC.L(@"Do not query backend at startup"); } } + public static string IndexfilepolicyLong { get { return LC.L(@"The index files are used to limit the need for downloading dblock files when there is no local database present. The more information is recorded in the index files, the faster operations can proceed without the database. The tradeoff is that larger index files take up more remote space and which may never be used."); } } + public static string IndexfilepolicyShort { get { return LC.L(@"Determines usage of index files"); } } + public static string ThresholdLong { get { return LC.L(@"As files are changed, some data stored at the remote destination may not be required. This option controls how much wasted space the destination can contain before being reclaimed. This value is a percentage used on each volume and the total storage."); } } + public static string ThresholdShort { get { return LC.L(@"The maximum wasted space in percent"); } } + public static string DryrunLong { get { return LC.L(@"This option can be used to experiment with different settings and observe the outcome without changing actual files."); } } + public static string DryrunShort { get { return LC.L(@"Does not perform any modifications"); } } + public static string BlockhashalgorithmLong { get { return LC.L(@"This is a very advanced option! This option can be used to select a block hash algorithm with smaller or larger hash size, for performance or storage space reasons."); } } + public static string BlockhashalgorithmShort { get { return LC.L(@"The hash algorithm used on blocks"); } } + public static string FilehashalgorithmLong { get { return LC.L(@"This is a very advanced option! This option can be used to select a file hash algorithm with smaller or larger hash size, for performance or storage space reasons."); } } + public static string FilehashalgorithmShort { get { return LC.L(@"The hash algorithm used on files"); } } + public static string NoautocompactLong { get { return LC.L(@"If a large number of small files are detected during a backup, or wasted space is found after deleting backups, the remote data will be compacted. Use this option to disable such automatic compacting and only compact when running the compact command."); } } + public static string NoautocompactShort { get { return LC.L(@"Disable automatic compacting"); } } + public static string SmallfilesizeLong { get { return LC.L(@"When examining the size of a volume in consideration for compacting, a small tolerance value is used, by default 20 percent of the volume size. This ensures that large volumes which may have a few bytes wasted space are not downloaded and rewritten."); } } + public static string SmallfilesizeShort { get { return LC.L(@"Volume size threshold"); } } + public static string SmallfilemaxcountLong { get { return LC.L(@"To avoid filling the remote storage with small files, this value can force grouping small files. The small volumes will always be combined when they can fill an entire volume."); } } + public static string SmallfilemaxcountShort { get { return LC.L(@"Maximum number of small volumes"); } } + public static string PatchwithlocalblocksLong { get { return LC.L(@"Enable this option to look into other files on this machine to find existing blocks. This is a fairly slow operation but can limit the size of downloads."); } } + public static string PatchwithlocalblocksShort { get { return LC.L(@"Use local file data when restoring"); } } + public static string NolocaldbShort { get { return LC.L(@"Disables the local database"); } } + public static string NolocaldbLong { get { return LC.L(@"When listing contents or when restoring files, the local database can be skipped. This is usually slower, but can be used to verify the actual contents of the remote store"); } } + public static string KeepversionsShort { get { return LC.L(@"Keep a number of versions"); } } + public static string KeepversionsLong { get { return LC.L(@"Use this option to set number of versions to keep, supply -1 to keep all versions"); } } + public static string KeeptimeShort { get { return LC.L(@"Keep all versions within a timespan"); } } + public static string KeeptimeLong { get { return LC.L(@"Use this option to set the timespan in which backups are kept."); } } + public static string RetentionPolicyShort { get { return LC.L(@"Reduce number of versions by deleting old intermediate backups"); } } + public static string RetentionPolicyLong { get { return LC.L(@"Use this option to reduce the number of versions that are kept with increasing version age by deleting most of the old backups. The expected format is a comma separated list of colon separated time frame and interval pairs. For example the value ""7D:0s,3M:1D,10Y:2M"" means ""For 7 day keep all backups, for 3 months keep one backup every day, for 10 years one backup every 2nd month and delete every backup older than this."". This option also supports using the specifier ""U"" to indicate an unlimited time interval."); } } + public static string AllowmissingsourceShort { get { return LC.L(@"Ignore missing source elements"); } } + public static string AllowmissingsourceLong { get { return LC.L(@"Use this option to continue even if some source entries are missing."); } } + public static string OverwriteShort { get { return LC.L(@"Overwrite files when restoring"); } } + public static string OverwriteLong { get { return LC.L(@"Use this option to overwrite target files when restoring, if this option is not set the files will be restored with a timestamp and a number appended."); } } + public static string VerboseShort { get { return LC.L(@"Output more progress information"); } } + public static string VerboseLong { get { return LC.L(@"Use this option to increase the amount of output generated when running an option. Generally this option will produce a line for each file processed."); } } + public static string VerboseDeprecated { get { return LC.L(@"Set a log-level for the desired output method instead"); } } + public static string FullresultShort { get { return LC.L(@"Output full results"); } } + public static string FullresultLong { get { return LC.L(@"Use this option to increase the amount of output generated as the result of the operation, including all filenames."); } } + public static string UploadverificationfileShort { get { return LC.L(@"Determine if verification files are uploaded"); } } + public static string UploadverificationfileLong { get { return LC.L(@"Use this option to upload a verification file after changing the remote storage. The file is not encrypted and contains the size and SHA256 hashes of all the remote files and can be used to verify the integrity of the files."); } } + public static string BackendtestsamplesShort { get { return LC.L(@"The number of samples to test after a backup"); } } + public static string BackendtestsamplesLong(string optionname) { return LC.L(@"After a backup is completed, some (dblock, dindex, dlist) files from the remote backend are selected for verification. Use this option to change how many. If the backup-test-percentage option is also provided, the number of samples tested is the maximum implied by the two options. If this value is set to 0 or the option --{0} is set, no remote files are verified", optionname); } + public static string BackendtestpercentageShort { get { return LC.L(@"The percentage of samples to test after a backup"); } } + public static string BackendtestpercentageLong { get { return LC.L(@"After a backup is completed, some (dblock, dindex, dlist) files from the remote backend are selected for verification. Use this option to specify the percentage (between 0 and 100) of files to test. If the backup-test-samples option is also provided, the number of samples tested is the maximum implied by the two options. If the no-backend-verification option is provided, no remote files are verified."); } } + public static string FullremoteverificationShort { get { return LC.L(@"Activates in-depth verification of files"); } } + public static string FullremoteverificationLong(string optionname) { return LC.L(@"After a backup is completed, some (dblock, dindex, dlist) files from the remote backend are selected for verification. Use this option to turn on full verification, which will decrypt the files and examine the insides of each volume, instead of simply verifying the external hash, If the option --{0} is set, no remote files are verified. This option is automatically set when then verification is performed directly.", optionname); } + public static string FilereadbuffersizeShort { get { return LC.L(@"Size of the file read buffer"); } } + public static string FilereadbuffersizeLong { get { return LC.L(@"Use this size to control how many bytes are read from a file before processing"); } } + public static string AllowpassphrasechangeShort { get { return LC.L(@"Allow the passphrase to change"); } } + public static string AllowpassphrasechangeLong { get { return LC.L(@"Use this option to allow the passphrase to change, note that this option is not permitted for a backup or repair operation"); } } + public static string ListsetsonlyShort { get { return LC.L(@"List only filesets"); } } + public static string ListsetsonlyLong { get { return LC.L(@"Use this option to only list filesets and avoid traversing file names and other metadata which slows down the process"); } } + + public static string SkipmetadataShort { get { return LC.L(@"Don't store metadata"); } } + public static string SkipmetadataLong { get { return LC.L(@"Use this option to disable the storage of metadata, such as file timestamps. Disabling metadata storage will speed up the backup and restore operations, but does not affect file size much."); } } + public static string RestorepermissionsShort { get { return LC.L(@"Restore file permissions"); } } + public static string RestorepermissionsLong { get { return LC.L(@"By default permissions are not restored as they might prevent you from accessing your files. Use this option to restore the permissions as well."); } } + public static string SkiprestoreverificationShort { get { return LC.L(@"Skip restored file check"); } } + public static string SkiprestoreverificationLong { get { return LC.L(@"After restoring files, the file hash of all restored files are checked to verify that the restore was successful. Use this option to disable the check and avoid waiting for the verification."); } } + public static string OldmemorylookupdefaultsShort { get { return LC.L(@"Activate caches"); } } + public static string OldmemorylookupdefaultsLong { get { return LC.L(@"Activate in-memory caches, which are now off by default"); } } + public static string NolocalblocksShort { get { return LC.L(@"Do not use local data"); } } + public static string NolocalblocksLong { get { return LC.L(@"Duplicati will attempt to use data from source files to minimize the amount of downloaded data. Use this option to skip this optimization and only use remote data."); } } + public static string FullblockverificationShort { get { return LC.L(@"Check block hashes"); } } + public static string FullblockverificationLong { get { return LC.L(@"Use this option to increase verification by checking the hash of blocks read from a volume before patching restored files with the data."); } } + public static string LogretentionShort { get { return LC.L(@"Clean up old log data"); } } + public static string LogretentionLong { get { return LC.L(@"Set the time after which log data will be purged from the database."); } } + public static string RepaironlypathsShort { get { return LC.L(@"Repair database with paths"); } } + public static string RepaironlypathsLong { get { return LC.L(@"Use this option to build a searchable local database which only contains path information. This option is usable for quickly building a database to locate certain content without needing to reconstruct all information. The resulting database can be searched, but cannot be used to restore data with."); } } + public static string ForcelocaleShort { get { return LC.L(@"Force the locale setting"); } } + public static string ForcelocaleLong { get { return LC.L(@"By default, your system locale and culture settings will be used. In some cases you may prefer to run with another locale, for example to get messages in another language. This option can be used to set the locale. Supply a blank string to choose the ""Invariant Culture""."); } } + public static string ForceActualDateShort { get { return LC.L(@"Forces the display of the actual date instead of calendar date"); } } + public static string ForceActualDateLong { get { return LC.L(@"By default, dates are displayed in the calendar format, meaning ""Today"" or ""Last Thursday"". By setting this option, only the actual dates are displayed, ""Nov 12, 2018, 8:01 AM"" for example."); } } + public static string DisablepipingShort{ get { return LC.L(@"Handle file communication with backend using threaded pipes"); } } + public static string DisablepipingLong { get { return LC.L(@"Use this option to disable multithreaded handling of up- and downloads, that can significantly speed up backend operations depending on the hardware you're running on and the transfer rate of your backend."); } } + public static string ConcurrencymaxthreadsShort{ get { return LC.L(@"Limit number of concurrent threads"); } } + public static string ConcurrencymaxthreadsLong { get { return LC.L(@"Use this option to set the maximum number of threads used. Setting this value to zero or less will dynamically balance the number of active threads to fit the hardware."); } } + public static string ConcurrencyblockhashersShort{ get { return LC.L(@"Specify the number of concurrent hashing processes"); } } + public static string ConcurrencyblockhashersLong { get { return LC.L(@"Use this option to set the number of processes that perform hashing of data."); } } + public static string ConcurrencycompressorsShort{ get { return LC.L(@"Specify the number of concurrent compression processes"); } } + public static string ConcurrencycompressorsLong { get { return LC.L(@"Use this option to set the number of processes that perform compression of output data."); } } + public static string HypervbackupvmShort { get { return LC.L(@"Perform backup of Hyper-V machines (Windows only)"); } } + public static string HypervbackupvmLong { get { return LC.L(@"Use this option to specify the IDs of machines to include in the backup. Specify multiple machine IDs with a semicolon separator. (You can use this Powershell command to get ID 'Get-VM | ft VMName, ID')"); } } + public static string DisablesyntehticfilelistLong { get { return LC.L(@"If Duplicati detects that the previous backup did not complete, it will generate a filelist that is a merge of the last completed backup and the contents that were uploaded in the incomplete backup session."); } } + public static string DisablesyntheticfilelistShort { get { return LC.L(@"Disables synthetic filelist"); } } + public static string CheckfiletimeonlyLong { get { return LC.L(@"This flag instructs Duplicati to not look at metadata or filesize when deciding to scan a file for changes. Use this option if you have a large number of files and notice that the scanning takes a long time with unmodified files."); } } + public static string CheckfiletimeonlyShort { get { return LC.L(@"Checks only file lastmodified"); } } + public static string DontcompressrestorepathsShort { get { return LC.L(@"Disables path compression on restore"); } } + public static string DontcompressrestorepathsLong { get { return LC.L(@"When restore a subset of a backup into a new folder, the shortest possible path is used to avoid generating deep paths with empty folders. Use this flag to skip this compression, such that the entire original folder structure is preserved, including upper level empty folders."); } } + public static string AllowfullremovalShort { get { return LC.L(@"Allow removing all filesets"); } } + public static string AllowfullremovalLong { get { return LC.L(@"By default, the last fileset cannot be removed. This is a safeguard to make sure that all remote data is not deleted by a configuration mistake. Use this flag to disable that protection, such that all filesets can be deleted."); } } + public static string AutoVacuumShort { get { return LC.L(@"Allow automatic rebuilding of local database to save space."); } } + public static string AutoVacuumLong { get { return LC.L(@"Some operations that manipulate the local database leave unused entries behind. These entries are not deleted from a hard drive until a VACUUM operation is run. This operation saves disk space in the long run but needs to temporarily create a copy of all valid entries in the database. Setting this to true will allow Duplicati to perform VACUUM operations at its discretion."); } } + public static string DisablefilescannerShort { get { return LC.L(@"Disable the read-ahead scanner"); } } + public static string DisablefilescannerLong { get { return LC.L(@"When this flag is enabled, the scanner that computes the size of source files is disabled, and instead the reported size is read from the database. Using this flag can speed up the backup by reducing disk access, but will give a less accurate progress indicator."); } } + public static string DisablefilelistconsistencychecksShort { get { return LC.L(@"Disable filelist consistency checks"); } } + public static string DisablefilelistconsistencychecksLong { get { return LC.L(@"In backups with a large number of filesets, the verification can take up a large part of the backup time. If you disable the checks, make sure you run regular check commands to ensure that everything is working as expected."); } } + public static string DisableOnBatteryShort { get { return LC.L("Disable the backup when on battery power"); } } + public static string DisableOnBatteryLong { get { return LC.L("When this flag is enabled, a scheduled backup will not run if the system is detected to be running on battery power (manual or command line backups will still be run). If the detected power source is mains (i.e., AC) or unknown, then scheduled backups will proceed as normal."); } } + + public static string LogfileloglevelLong { get { return LC.L(@"Specifies the amount of log information to write into the file specified by --log-file"); } } + public static string LogfileloglevelShort { get { return LC.L(@"Log file information level"); } } + public static string LogfilelogfiltersShort { get { return LC.L(@"Applies filters to the file log data"); } } + public static string LogfilelogfiltersLong(string delimiter) { return LC.L(@"This option accepts filters that removes or includes messages regardless of their log level. Multiple filters are supported by separating with {0}. Filters are matched against the log tag and assumed to be including, unless they start with '-'. Regular expressions are supported within hard braces. Example: ""+Path*{0}+*Mail*{0}-[.*DNS]"" ", delimiter); } + public static string ConsoleloglevelLong { get { return LC.L(@"Specifies the amount of log information to write as console output"); } } + public static string ConsoleloglevelShort { get { return LC.L(@"Console information level"); } } + public static string ConsolelogfiltersShort { get { return LC.L(@"Applies filters to the console log data"); } } + public static string ConsolelogfiltersLong(string delimiter) { return LogfilelogfiltersLong(delimiter); } + + public static string UsebackgroundiopriorityShort { get { return LC.L("Sets the process to use low IO priority"); } } + public static string UsebackgroundiopriorityLong { get { return LC.L("This option instructions the operating system to set the current process to use the lowest IO priority level, which can make operations run slower but will interfere less with other operations running at the same time"); } } + + public static string ExcludeemptyfoldersShort { get { return "Excludes empty folders"; } } + public static string ExcludeemptyfoldersLong { get { return "Use this option to remove all empty folders from a backup."; } } + public static string IgnorefilenamesShort { get { return LC.L("List of filenames that exclude folders"); } } + public static string IgnorefilenamesLong { get { return LC.L("Use this option to set a filename, or list of filenames, that indicate exclusion of a folder which contains it. A common use would be to have a file named something like \".nobackup\" and place this file into folders that should not be backed up."); } } + public static string RestoresymlinkmetadataShort { get { return "Apply metadata to symlinks"; } } + public static string RestoresymlinkmetadataLong { get { return "If symlink metadata is applied, it will usually mean changing the symlink target, instead of the symlink itself. For this reason, metadata is not applied to symlinks, but this option can be used to override this, such that metadata is applied to symlinks as well."; } } + public static string UnittestmodeShort { get { return "Activate unittest mode"; } } + public static string UnittestmodeLong { get { return "When running in unittest mode, no automatic fixes are applied, which assumes that the input data is always in perfect shape. This option is not intended for use in daily backups, but required for testing purposes to reveal potential problems."; } } + + public static string ProfilealldatabasequeriesShort { get { return LC.L("Activates logging of all database queries"); } } + public static string ProfilealldatabasequeriesLong { get { return LC.L("To improve performance of the backups, frequent database queries are not logged by default. Enable this option to log all database queries, and remember to set either --{0}={2} or --{1}={2} to report the additional log data", "console-log-level", "log-file-log-level", nameof(Logging.LogMessageType.Profiling)); } } + public static string RebuildmissingdblockfilesShort { get { return "Rebuild dblock files when missing"; } } + public static string RebuildmissingdblockfilesLong { get { return "If dblock files are missing from the destination, you can attempt to rebuild them using local source data. However, since the local data may have changed, it may not be possible to retrieve all the required data and the process may be slow. Use this option to attempt to rebuild missing dblock files."; } } + + public static string AutoCompactIntervalShort { get { return "Minimum time between auto compactions"; } } + public static string AutoCompactIntervalLong { get { return "The minimum amount of time that must elapse after the last compaction before another will be automatically triggered at the end of a backup job. Automatic compaction can be a long-running process and may not be desirable to run after every single backup."; } } + public static string AutoVacuumIntervalShort { get { return "Minimum time between auto vacuums"; } } + public static string AutoVacuumIntervalLong { get { return "The minimum amount of time that must elapse after the last vacuum before another will be automatically triggered at the end of a backup job. Automatic vacuum can be a long-running process and may not be desirable to run after every single backup."; } } + } + + internal static class Common + { + public static string InvalidCryptoSystem(string algorithm) { return LC.L(@"The cryptolibrary does not support re-usable transforms for the hash algorithm {0}", algorithm); } + public static string InvalidHashAlgorithm(string algorithm) { return LC.L(@"The cryptolibrary does not support the hash algorithm {0}", algorithm); } + public static string PassphraseChangeUnsupported { get { return LC.L(@"The passphrase cannot be changed for an existing backup"); } } + public static string SnapshotFailedError(string message) { return LC.L(@"Failed to create a snapshot: {0}", message); } + } + +} diff --git a/Duplicati/Library/Utility/TempFile.cs b/Duplicati/Library/Utility/TempFile.cs index 7056d9fd4..2865247b4 100644 --- a/Duplicati/Library/Utility/TempFile.cs +++ b/Duplicati/Library/Utility/TempFile.cs @@ -19,21 +19,20 @@ #endregion using System; using System.Collections.Generic; -using System.Text; -using Duplicati.Library.Common.IO; - +using Duplicati.Library.Common.IO; + namespace Duplicati.Library.Utility { /// /// This class represents a temporary file that will be automatically deleted when disposed /// - public class TempFile : IDisposable + public class TempFile : IDisposable { /// /// The prefix applied to all temporary files /// public static string APPLICATION_PREFIX = Utility.getEntryAssembly().FullName.Substring(0, 3).ToLower(System.Globalization.CultureInfo.InvariantCulture) + "-"; - + private string m_path; private bool m_protect; @@ -41,20 +40,20 @@ namespace Duplicati.Library.Utility //In debug mode, we track the creation of temporary files, and encode the generating method into the name private static readonly object m_lock = new object(); private static Dictionary m_fileTrace = new Dictionary(); - + public static System.Diagnostics.StackTrace GetStackTraceForTempFile(string filename) { - lock(m_lock) + lock (m_lock) if (m_fileTrace.ContainsKey(filename)) return m_fileTrace[filename]; else return null; } - + private static string GenerateUniqueName() { var st = new System.Diagnostics.StackTrace(); - foreach(var f in st.GetFrames()) + foreach (var f in st.GetFrames()) if (f.GetMethod().DeclaringType.Assembly != typeof(TempFile).Assembly) { var n = string.Format("{0}_{1}_{2}_{3}", f.GetMethod().DeclaringType.FullName, f.GetMethod().Name, Library.Utility.Utility.SerializeDateTime(DateTime.UtcNow), Guid.NewGuid().ToString().Substring(0, 8)); @@ -62,16 +61,16 @@ namespace Duplicati.Library.Utility n = string.Format("{0}_{1}_{2}_{3}", f.GetMethod().DeclaringType.Name, f.GetMethod().Name, Library.Utility.Utility.SerializeDateTime(DateTime.UtcNow), Guid.NewGuid().ToString().Substring(0, 8)); if (n.IndexOfAny(System.IO.Path.GetInvalidFileNameChars()) < 0) { - lock(m_lock) + lock (m_lock) m_fileTrace.Add(n, st); return n; } } - + var s = Guid.NewGuid().ToString(); - lock(m_lock) + lock (m_lock) m_fileTrace.Add(s, st); - return s; + return s; } #else private static string GenerateUniqueName() @@ -90,17 +89,11 @@ namespace Duplicati.Library.Utility /// The application temp files. private static IEnumerable GetApplicationTempFiles() { +#if DEBUG + return SystemIO.IO_OS.GetFiles(TempFolder.SystemTempPath, "Duplicati*"); +#else return SystemIO.IO_OS.GetFiles(TempFolder.SystemTempPath, APPLICATION_PREFIX + "*"); - } - - /// - /// Attempts to delete all temporary files for this application - /// - public static void RemoveAllApplicationTempFiles() - { - foreach(var s in GetApplicationTempFiles()) - try { System.IO.File.Delete(s); } - catch { } +#endif } /// @@ -109,20 +102,27 @@ namespace Duplicati.Library.Utility /// An optional callback method for logging errors public static void RemoveOldApplicationTempFiles(Action errorcallback = null) { +#if DEBUG + var expires = TimeSpan.FromHours(3); +#else var expires = TimeSpan.FromDays(30); - foreach(var e in GetApplicationTempFiles()) +#endif + foreach (string e in GetApplicationTempFiles()) + { try { if (DateTime.UtcNow > (System.IO.File.GetLastWriteTimeUtc(e) + expires)) + { System.IO.File.Delete(e); + } } catch (Exception ex) { - if (errorcallback != null) - errorcallback(e, ex); + errorcallback?.Invoke(e, ex); } + } } - + public TempFile() : this(System.IO.Path.Combine(TempFolder.SystemTempPath, GenerateUniqueName())) { @@ -134,7 +134,7 @@ namespace Duplicati.Library.Utility m_protect = false; if (!System.IO.File.Exists(m_path)) using (System.IO.File.Create(m_path)) - { /*Dispose it immediately*/ } + { /*Dispose it immediately*/ } } /// @@ -156,7 +156,7 @@ namespace Duplicati.Library.Utility { return new TempFile(path); } - + public static TempFile WrapExistingFile(string path) { return new TempFile(path); @@ -179,7 +179,7 @@ namespace Duplicati.Library.Utility { if (disposing) GC.SuppressFinalize(this); - + try { if (!m_protect && m_path != null && System.IO.File.Exists(m_path)) @@ -190,7 +190,7 @@ namespace Duplicati.Library.Utility { } } - + #region IDisposable Members public void Dispose() @@ -199,7 +199,7 @@ namespace Duplicati.Library.Utility } #endregion - + ~TempFile() { Dispose(false); diff --git a/Duplicati/Server/Program.cs b/Duplicati/Server/Program.cs index 19a693fa6..f6a1aed99 100644 --- a/Duplicati/Server/Program.cs +++ b/Duplicati/Server/Program.cs @@ -244,9 +244,9 @@ namespace Duplicati.Server { DataConnection.LogError(null, "Error in updater", obj); }; - - UpdatePoller = new UpdatePollThread(); + UpdatePoller = new UpdatePollThread(); + SetPurgeTempFilesTimer(commandlineOptions); SetLiveControls(); @@ -379,8 +379,17 @@ namespace Duplicati.Server { try { - if (Math.Abs((DateTime.Now - lastPurge).TotalHours) < 23) +#if DEBUG + if (Math.Abs((DateTime.Now - lastPurge).TotalHours) < 1) + { return; + } +#else + if (Math.Abs((DateTime.Now - lastPurge).TotalHours) < 23) + { + return; + } +#endif lastPurge = DateTime.Now; @@ -420,8 +429,13 @@ namespace Duplicati.Server try { +#if DEBUG + PurgeTempFilesTimer = + new System.Threading.Timer(purgeTempFilesCallback, null, TimeSpan.FromSeconds(10), TimeSpan.FromHours(1)); +#else PurgeTempFilesTimer = new System.Threading.Timer(purgeTempFilesCallback, null, TimeSpan.FromHours(1), TimeSpan.FromDays(1)); +#endif } catch (ArgumentOutOfRangeException) { diff --git a/Duplicati/Server/webroot/ngax/index.html b/Duplicati/Server/webroot/ngax/index.html index cc88c2875..842f38e24 100755 --- a/Duplicati/Server/webroot/ngax/index.html +++ b/Duplicati/Server/webroot/ngax/index.html @@ -191,7 +191,7 @@ Next task: {{nextTask.Backup.Name}} -
Next scheduled task: {{nextScheduledTask.Backup.Name}} {{nextScheduledTime | moment: 'calendar'}}
+
Next scheduled task: {{nextScheduledTask.Backup.Name}} {{nextScheduledTime | parseDate:forceActualDate }}
No scheduled tasks
diff --git a/Duplicati/Server/webroot/ngax/scripts/controllers/AppController.js b/Duplicati/Server/webroot/ngax/scripts/controllers/AppController.js index 9d93e9aad..57b1d1dac 100644 --- a/Duplicati/Server/webroot/ngax/scripts/controllers/AppController.js +++ b/Duplicati/Server/webroot/ngax/scripts/controllers/AppController.js @@ -159,6 +159,8 @@ backupApp.controller('AppController', function($scope, $cookies, $location, AppS }); AppService.get('/serversettings').then(function(data) { + $scope.forceActualDate = AppUtils.parseBoolString(data.data['--force-actual-date']); + var ut = data.data['max-upload-speed']; var dt = data.data['max-download-speed']; $scope.throttle_active = (ut != null && ut.trim().length != 0) || (dt != null && dt.trim().length != 0); diff --git a/Duplicati/Server/webroot/ngax/scripts/controllers/SystemSettingsController.js b/Duplicati/Server/webroot/ngax/scripts/controllers/SystemSettingsController.js index f1a5b2fa5..4b57662e1 100644 --- a/Duplicati/Server/webroot/ngax/scripts/controllers/SystemSettingsController.js +++ b/Duplicati/Server/webroot/ngax/scripts/controllers/SystemSettingsController.js @@ -1,4 +1,4 @@ -backupApp.controller('SystemSettingsController', function($rootScope, $scope, $location, $cookies, AppService, DialogService, AppUtils, SystemInfo, gettextCatalog) { +backupApp.controller('SystemSettingsController', function($rootScope, $scope, $route, $cookies, AppService, DialogService, AppUtils, SystemInfo, gettextCatalog) { $scope.SystemInfo = SystemInfo.watch($scope); $scope.theme = $scope.$parent.$parent.saved_theme; @@ -111,7 +111,7 @@ backupApp.controller('SystemSettingsController', function($rootScope, $scope, $l if ($scope.updateChannel != $scope.originalUpdateChannel) AppService.post('/updates/check'); - $location.path('/'); + $route.reload(); }, AppUtils.connectionError(gettextCatalog.getString('Failed to save:') + ' ') ); diff --git a/Duplicati/Server/webroot/ngax/scripts/filters/parsetimestamp.js b/Duplicati/Server/webroot/ngax/scripts/filters/parsetimestamp.js index 03b0652c8..4c129981e 100644 --- a/Duplicati/Server/webroot/ngax/scripts/filters/parsetimestamp.js +++ b/Duplicati/Server/webroot/ngax/scripts/filters/parsetimestamp.js @@ -14,3 +14,13 @@ backupApp.filter('parsetimestamp', function(AppUtils) { return AppUtils.toDisplayDateAndTime(value); } }); + +backupApp.filter('parseDate', function(parsetimestampFilter, momentFilter) { + return function(value, force) { + if (force) { + return parsetimestampFilter(value); + } + + return momentFilter(value, 'calendar'); + } +}); diff --git a/Duplicati/Server/webroot/ngax/templates/home.html b/Duplicati/Server/webroot/ngax/templates/home.html index f9a634629..5d1d73141 100644 --- a/Duplicati/Server/webroot/ngax/templates/home.html +++ b/Duplicati/Server/webroot/ngax/templates/home.html @@ -53,7 +53,7 @@
Last successful backup:
{{time}} (took {{duration}})
@@ -62,7 +62,7 @@
Next scheduled run:
-
{{item.Backup.Metadata.NextScheduledRun | moment: 'calendar'}}
+
{{item.Backup.Metadata.NextScheduledRun | parseDate:forceActualDate }}
diff --git a/Duplicati/Server/webroot/ngax/templates/restorewizard.html b/Duplicati/Server/webroot/ngax/templates/restorewizard.html index 49a5d6fea..21c795378 100644 --- a/Duplicati/Server/webroot/ngax/templates/restorewizard.html +++ b/Duplicati/Server/webroot/ngax/templates/restorewizard.html @@ -26,7 +26,7 @@
Last successful restore: {{time}} (took {{duration || '0 seconds'}})
diff --git a/Updates/build_version.txt b/Updates/build_version.txt index 409940768..a45fd52cc 100644 --- a/Updates/build_version.txt +++ b/Updates/build_version.txt @@ -1 +1 @@ -23 +24 diff --git a/build-release.sh b/build-release.sh index 5fec34ee2..0775f9dd1 100644 --- a/build-release.sh +++ b/build-release.sh @@ -125,7 +125,8 @@ fi rm -rf "Duplicati/GUI/Duplicati.GUI.TrayIcon/bin/Release" -"${XBUILD}" /property:Configuration=Release "BuildTools/UpdateVersionStamp/UpdateVersionStamp.csproj" +"${NUGET}" restore "BuildTools/UpdateVersionStamp/UpdateVersionStamp.sln" +"${XBUILD}" /property:Configuration=Release "BuildTools/UpdateVersionStamp/UpdateVersionStamp.sln" "${MONO}" "BuildTools/UpdateVersionStamp/bin/Release/UpdateVersionStamp.exe" --version="${RELEASE_VERSION}" "${NUGET}" restore "BuildTools/AutoUpdateBuilder/AutoUpdateBuilder.sln" diff --git a/changelog.txt b/changelog.txt index 498022784..999fcd9d7 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,29 @@ +2019-09-02 - 2.0.4.24_canary_2019-09-02 +========== +* Code cleanup, thanks @warwickmm +* Removed extra console output, thanks @wjansenw +* Fixed disposing backends after job completion, thanks @warwickmm +* Fixed an issue with throttled write, thanks @warwickmm +* Spelling fix, thanks @BlueBlock +* Fixed documetation in `run-script` examples, thanks @beppo-dd +* Improved unittests, thanks @BlueBlock +* Improved auto-compact and auto-vacuum, thanks @drwtsn32x +* Fixed problem with exceeeding the number of parameters supported by SQLite, thanks @drwtsn32x +* Improved status display, thanks @drwtsn32x +* Improved bugreport database scrubbing, thanks @drwtsn32x +* Removed GoogleDrive trash items in listing, thanks @BlueBlock +* Fixed the rename method in the GoogleDrive backend, thanks @BlueBlock +* Improved GCS storage class text, thanks @warwickmm +* Improved unittests for easier local testing, thanks @warwickmm +* Added workaround for AFTP upload delay, thanks @BlueBlock +* Fixed issue with reading the largest path prefix, thanks @BlueBlock +* Added conditional download of unittest data zip files, thanks @BlueBlock +* CI testing improvements, thanks @BlueBlock +* Fixed sporadic issue with backups of files being written, thanks @BlueBlock +* Updated to .Net Framework 4.6.2 +* Fixed issue with temporary files not being deleted as expected, thanks @BlueBlock +* Support for forcing calendar dates in time pickers, thanks @LacunaSoftware + 2019-07-14 - 2.0.4.23_beta_2019-07-14 ========== This update only contains warnings to inform users on Amazon Cloud Drive that the service is discontinued.