#region Disclaimer / License // Copyright (C) 2011, Kenneth Skovhede // http://www.hexad.dk, opensource@hexad.dk // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // #endregion using System; using System.Linq; using System.Collections.Generic; using System.Text; using Duplicati.Library.Interface; 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_LOOKUP_SIZE = "64mb"; private const string DEFAULT_METADATA_HASH_LOOKUP_SIZE = "64mb"; private const string DEFAULT_FILE_HASH_LOOKUP_SIZE = "32mb"; 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; /// /// 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 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(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "default_compressed_extensions.txt"); /// /// Lock that protects the options collection /// protected 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" }; } } /// /// Gets all commands that effect a backup /// public static string[] BackupOptions { get { return new string[] { "dblock-size", "disable-autocreate-folder", "disable-filetime-check", "disable-time-tolerance", "allow-missing-source", "skip-files-larger-than", "upload-unchanged-backups", "list-verify-uploads", "signature-control-files", "snapshot-policy", "vss-exclude-writers", "vss-use-mapping", "usn-policy", "symlink-policy", "exclude-files-attributes", "compression-extension-file", "full-remote-verification" }; } } /// /// Gets all options that affect a connection /// public static string[] ConnectionOptions { get { return new string[] { "thread-priority", "number-of-retries", "retry-delay", "synchronous-upload", "asynchronous-upload-limit", "asynchronous-upload-folder", "disable-streaming-transfer", "max-upload-pr-second", "max-download-pr-second", "no-connection-reuse", "allow-sleep" }; } } /// /// Gets all options that affect a filename parsing /// public static string[] FilenameOptions { get { return new string[] { "prefix", "tempdir" }; } } /// /// Gets all options that can be used for debugging /// public static string[] DebugOptions { get { return new string[] { "debug-output", "debug-retry-errors", "log-file", "log-level", }; } } /// /// Gets all options that affect module loading /// public static string[] ModuleOptions { get { return new string[] { "encryption-module", "compression-module", "enable-module", "disable-module", "no-encryption" }; } } /// /// Gets all options that affect encryption /// public static string[] EncryptionOptions { get { return new string[] { "encryption-module", "passphrase", "no-encryption" }; } } /// /// Gets all options that affect cleanup commands /// public static string[] CleanupOptions { get { return new string[] { "dry-run" }; } } /// /// Gets all options that affect restore commands /// public static string[] RestoreOptions { get { return new string[] { "skip-file-hash-checks", "dont-read-manifests", "restore-path", "time", "version", "allow-passphrase-change", }; } } /// /// 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), 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), new CommandLineArgument("dont-read-manifests", CommandLineArgument.ArgumentType.Boolean, Strings.Options.DontreadmanifestsShort, Strings.Options.DontreadmanifestsLong), 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("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("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-upload-folder", CommandLineArgument.ArgumentType.Path, Strings.Options.AsynchronousuploadfolderShort, Strings.Options.AsynchronousuploadfolderLong), 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, "0"), new CommandLineArgument("throttle-download", CommandLineArgument.ArgumentType.Size, Strings.Options.ThrottledownloadShort, Strings.Options.ThrottledownloadLong, "0"), 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), 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", Duplicati.Library.Interface.CommandLineArgument.ArgumentType.Path, Strings.Options.LogfileShort, Strings.Options.LogfileShort), new CommandLineArgument("log-level", Duplicati.Library.Interface.CommandLineArgument.ArgumentType.Enumeration, Strings.Options.LoglevelShort, Strings.Options.LoglevelLong, "Warning", null, Enum.GetNames(typeof(Duplicati.Library.Logging.LogMessageType))), 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.AllowsleepShort, "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("symlink-policy", CommandLineArgument.ArgumentType.Enumeration, Strings.Options.SymlinkpolicyShort, string.Format(Strings.Options.SymlinkpolicyLong, "store", "ignore", "follow"), "store", null, Enum.GetNames(typeof(SymlinkStrategy))), new CommandLineArgument("exclude-files-attributes", CommandLineArgument.ArgumentType.String, Strings.Options.ExcludefilesattributesShort, string.Format(Strings.Options.ExcludefilesattributesLong, string.Join(", ", 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, string.Format(Strings.Options.CompressionextensionfileLong, DEFAULT_COMPRESSED_EXTENSION_FILE), DEFAULT_COMPRESSED_EXTENSION_FILE), new CommandLineArgument("verbose", CommandLineArgument.ArgumentType.Boolean, Strings.Options.VerboseShort, Strings.Options.VerboseLong, "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, DEFAULT_READ_BUFFER_SIZE), new CommandLineArgument("store-metadata", CommandLineArgument.ArgumentType.Boolean, Strings.Options.StoremetadataShort, Strings.Options.StoremetadataLong, "false"), new CommandLineArgument("blockhash-lookup-memory", CommandLineArgument.ArgumentType.Size, Strings.Options.BlockhashlookupsizeShort, Strings.Options.BlockhashlookupsizeLong, DEFAULT_BLOCK_HASH_LOOKUP_SIZE), new CommandLineArgument("filehash-lookup-memory", CommandLineArgument.ArgumentType.Size, Strings.Options.FilehashlookupsizeShort, Strings.Options.FilehashlookupsizeLong, DEFAULT_FILE_HASH_LOOKUP_SIZE), new CommandLineArgument("metadatahash-lookup-memory", CommandLineArgument.ArgumentType.Size, Strings.Options.MetadatahashlookupsizeShort, Strings.Options.MetadatahashlookupsizeLong, DEFAULT_METADATA_HASH_LOOKUP_SIZE), new CommandLineArgument("disable-filepath-cache", CommandLineArgument.ArgumentType.Size, Strings.Options.DisablefilepathcacheShort, Strings.Options.DisablefilepathcacheLong, "false"), new CommandLineArgument("changed-files", CommandLineArgument.ArgumentType.Path, Strings.Options.ChangedfilesShort, Strings.Options.ChangedfilesLong), new CommandLineArgument("deleted-files", CommandLineArgument.ArgumentType.Path, Strings.Options.DeletedfilesShort, string.Format(Strings.Options.DeletedfilesLong, "changed-files")), new CommandLineArgument("threshold", CommandLineArgument.ArgumentType.Size, 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, string.Format(Strings.Options.BackendtestsamplesLong, "no-backend-verification"), "1"), new CommandLineArgument("full-remote-verification", CommandLineArgument.ArgumentType.Boolean, Strings.Options.FullremoteverificationShort, string.Format(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.Size, Strings.Options.SmallfilemaxcountShort, Strings.Options.SmallfilemaxcountLong, DEFAULT_SMALL_FILE_MAX_COUNT.ToString()), new CommandLineArgument("patch-with-local-blocks", CommandLineArgument.ArgumentType.Size, Strings.Options.PatchwithlocalblocksShort, Strings.Options.PatchwithlocalblocksLong), new CommandLineArgument("no-local-db", CommandLineArgument.ArgumentType.Boolean, Strings.Options.NolocaldbShort, Strings.Options.NolocaldbLong, "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("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"), #if DEBUG new CommandLineArgument("no-local-blocks", CommandLineArgument.ArgumentType.Boolean, "Prevents using local blocks for restore", "", "false"), #endif }); 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"); } } /// /// 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 file time checks are skipped /// public bool DisableFiletimeCheck { get { return GetBool("disable-filetime-check"); } } /// /// 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 System.IO.Path.GetTempPath(); else return m_options["tempdir"]; } } /// /// 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 filesets selected for deletion /// /// The filesets to delete /// The list of backups that can be deleted public DateTime[] GetFilesetsToDelete (DateTime[] backups) { if (backups.Length == 0) return backups; List res = new List(); var versions = this.Version; if (versions != null && versions.Length > 0) foreach (var ix in versions.Distinct()) if (ix >= 0 && ix < backups.Length) res.Add(backups[ix]); var keepVersions = this.KeepVersions; if (keepVersions > 0 && keepVersions < backups.Length) res.AddRange(backups.Skip(keepVersions)); var keepTime = this.KeepTime; if (keepTime.Ticks > 0) res.AddRange(backups.SkipWhile(x => x >= keepTime)); var filtered = res.Distinct().OrderByDescending(x => x).AsEnumerable(); var removeCount = filtered.Count(); if (removeCount >= backups.Length) filtered = filtered.Skip(removeCount - backups.Length + (AllowFullRemoval ? 0 : 1)); return filtered.ToArray(); } /// /// 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 Exception("Invalid count for number-of-retries"); 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 ops (win32 only) /// public bool AllowSleep { get { return GetBool("allow-sleep"); } } /// /// A value indicating if use of the streaming interface is disallowed /// public bool DisableStreamingTransfers { get { return GetBool("disable-streaming-transfers"); } } /// /// 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().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().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.InvariantCultureIgnoreCase)) return OptimizationStrategy.On; else if (string.Equals(strategy, "off", StringComparison.InvariantCultureIgnoreCase)) return OptimizationStrategy.Off; else if (string.Equals(strategy, "required", StringComparison.InvariantCultureIgnoreCase)) return OptimizationStrategy.Required; else if (string.Equals(strategy, "auto", StringComparison.InvariantCultureIgnoreCase)) return OptimizationStrategy.Auto; else return OptimizationStrategy.Off; } } /// /// Gets the snapshot strategy to use /// public SymlinkStrategy SymlinkPolicy { get { string strategy; if (!m_options.TryGetValue("symlink-policy", out strategy)) strategy = ""; SymlinkStrategy r; if (!Enum.TryParse(strategy, true, out r)) r = SymlinkStrategy.Store; return r; } } /// /// Gets the snapshot strategy to use /// public OptimizationStrategy UsnStrategy { get { string strategy; if (!m_options.TryGetValue("usn-policy", out strategy)) strategy = ""; if (string.Equals(strategy, "on", StringComparison.InvariantCultureIgnoreCase)) return OptimizationStrategy.On; else if (string.Equals(strategy, "off", StringComparison.InvariantCultureIgnoreCase)) return OptimizationStrategy.Off; else if (string.Equals(strategy, "required", StringComparison.InvariantCultureIgnoreCase)) return OptimizationStrategy.Required; else if (string.Equals(strategy, "auto", StringComparison.InvariantCultureIgnoreCase)) return OptimizationStrategy.Auto; else return OptimizationStrategy.Off; } } /// /// 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 detail level /// public Duplicati.Library.Logging.LogMessageType Loglevel { get { string 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.InvariantCultureIgnoreCase)) return (Duplicati.Library.Logging.LogMessageType)Enum.Parse(typeof(Duplicati.Library.Logging.LogMessageType), s); return Duplicati.Library.Logging.LogMessageType.Warning; } } /// /// Gets the attribute filter used to exclude files and folders. /// public System.IO.FileAttributes FileAttributeFilter { get { System.IO.FileAttributes res = (System.IO.FileAttributes)0; 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 output should be verbose /// public bool Verbose { get { return GetBool("verbose"); } } /// /// 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 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 the size of file-blocks /// public int Blocksize { get { string tmp; if (!m_options.TryGetValue("blocksize", out tmp)) tmp = DEFAULT_BLOCKSIZE; long t = Library.Utility.Sizeparser.ParseSize(tmp, "kb"); if (t > int.MaxValue || t < 1024) throw new ArgumentOutOfRangeException("blocksize", string.Format("The blocksize cannot be less than {0}, nor larger than {1}", 1024, int.MaxValue)); return (int)t; } } /// /// 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 StoreMetadata { get { return Library.Utility.Utility.ParseBoolOption(m_options, "store-metadata"); } } /// /// Gets the block hash lookup size /// public long BlockHashLookupMemory { get { string v; m_options.TryGetValue("blockhash-lookup-memory", out v); if (string.IsNullOrEmpty(v)) v = DEFAULT_BLOCK_HASH_LOOKUP_SIZE; return Library.Utility.Sizeparser.ParseSize(v, "mb"); } } /// /// Gets the file hash size /// public long FileHashLookupMemory { get { string v; m_options.TryGetValue("filehash-lookup-memory", out v); if (string.IsNullOrEmpty(v)) v = DEFAULT_FILE_HASH_LOOKUP_SIZE; return Library.Utility.Sizeparser.ParseSize(v, "mb"); } } /// /// Gets the block hash size /// public long MetadataHashMemory { get { string v; m_options.TryGetValue("metadatahash-lookup-memory", out v); if (string.IsNullOrEmpty(v)) v = DEFAULT_METADATA_HASH_LOOKUP_SIZE; return Library.Utility.Sizeparser.ParseSize(v, "mb"); } } /// /// Gets the file hash size /// public bool UseFilepathCache { get { return !Library.Utility.Utility.ParseBoolOption(m_options, "disable-filepath-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); } } /// /// 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 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 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"); } } #if DEBUG public bool NoLocalBlocks { get { return Library.Utility.Utility.ParseBoolOption(m_options, "no-local-blocks"); } } #endif /// /// 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 lookup table with compression hints, the key is the file extension with the leading period /// public IDictionary CompressionHints { get { if (m_compressionHints == null) { //Don't try again, if the file does not exist m_compressionHints = 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] == '.') m_compressionHints[line] = CompressionHint.Noncompressible; } } 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); } } }