Пример #1
0
        public List<KeyValuePair<BackupEntryBase, Exception>> VerifyBackupChain()
        {
            CommunicationStatistics stats = new CommunicationStatistics(DuplicatiOperationMode.Verify);
            SetupCommonOptions(stats);

            List<KeyValuePair<BackupEntryBase, Exception>> results = new List<KeyValuePair<BackupEntryBase, Exception>>();

            if (m_options.DontReadManifests)
                throw new InvalidOperationException(Strings.Interface.ManifestsMustBeRead);
            if (m_options.SkipFileHashChecks)
                throw new InvalidOperationException(Strings.Interface.CannotVerifyWithoutHashes);

            if (!string.IsNullOrEmpty(m_options.SignatureCachePath))
            {
                stats.LogWarning(Strings.Interface.DisablingSignatureCacheForVerification, null);
                m_options.SignatureCachePath = null;
            }

            using (BackendWrapper backend = new BackendWrapper(stats, m_backend, m_options))
            {
                //Find the spot in the chain where we start
                ManifestEntry bestFit = backend.GetBackupSet(m_options.RestoreTime);

                //Get the list of manifests to validate
                List<ManifestEntry> entries = new List<ManifestEntry>();
                entries.Add(bestFit);
                entries.AddRange(bestFit.Incrementals);

                entries.Reverse();

                foreach (ManifestEntry me in entries)
                {
                    Manifestfile mf = null;

                    try
                    {
                        mf = GetManifest(backend, me);
                        VerifyBackupChainWithFiles(backend, me);

                        if (mf.SignatureHashes.Count != me.Volumes.Count)
                            results.Add(new KeyValuePair<BackupEntryBase,Exception>(me, new Exception(string.Format(Strings.Interface.ManifestAndFileCountMismatchError, mf.SelfFilename, mf.SignatureHashes.Count, me.Volumes.Count))));
                        else
                            results.Add(new KeyValuePair<BackupEntryBase,Exception>(me, null));
                    }
                    catch (Exception ex)
                    {
                        results.Add(new KeyValuePair<BackupEntryBase,Exception>(me, ex));
                    }

                    if (mf != null)
                    {
                        int volumes = Math.Min(mf.SignatureHashes.Count, me.Volumes.Count);
                        for(int i = 0; i <volumes; i++)
                        {
                            if (m_options.Verificationlevel == VerificationLevel.Signature || m_options.Verificationlevel == VerificationLevel.Full)
                            {
                                try
                                {
                                    using(Utility.TempFile tf = new Duplicati.Library.Utility.TempFile())
                                        backend.Get(me.Volumes[i].Key, mf, tf, mf.SignatureHashes[i]);
                                    results.Add(new KeyValuePair<BackupEntryBase, Exception>(me.Volumes[i].Key, null));
                                }
                                catch (Exception ex) { results.Add(new KeyValuePair<BackupEntryBase,Exception>(me.Volumes[i].Key, ex)); }
                            }

                            if (m_options.Verificationlevel == VerificationLevel.Full)
                            {
                                try
                                {
                                    using(Utility.TempFile tf = new Duplicati.Library.Utility.TempFile())
                                        backend.Get(me.Volumes[i].Value, mf, tf, mf.ContentHashes[i]);
                                    results.Add(new KeyValuePair<BackupEntryBase, Exception>(me.Volumes[i].Value, null));
                                }
                                catch (Exception ex) { results.Add(new KeyValuePair<BackupEntryBase,Exception>(me.Volumes[i].Value, ex)); }

                            }
                        }
                    }

                }

                //Re-generate verification file
                if (m_options.CreateVerificationFile)
                {
                    //Stop any async operations
                    if (m_options.AsynchronousUpload)
                        backend.ExtractPendingUploads();

                    VerificationFile vf = new VerificationFile(entries, new FilenameStrategy(m_options));
                    using (Utility.TempFile tf = new Duplicati.Library.Utility.TempFile())
                    {
                        vf.Save(tf);
                        tf.Protected = true;
                        backend.Put(new VerificationEntry(entries[entries.Count - 1].Time), tf);
                    }
                }

            }

            return results;
        }
Пример #2
0
        /// <summary>
        /// This function will examine all options passed on the commandline, and test for unsupported or deprecated values.
        /// Any errors will be logged into the statistics module.
        /// </summary>
        /// <param name="options">The commandline options given</param>
        /// <param name="backend">The backend url</param>
        /// <param name="stats">The statistics into which warnings are written</param>
        private void ValidateOptions(CommunicationStatistics stats)
        {
            //No point in going through with this if we can't report
            if (stats == null)
                return;

            //Keep a list of all supplied options
            Dictionary<string, string> ropts = m_options.RawOptions;

            //Keep a list of all supported options
            Dictionary<string, Library.Interface.ICommandLineArgument> supportedOptions = new Dictionary<string, Library.Interface.ICommandLineArgument>();

            //There are a few internal options that are not accessible from outside, and thus not listed
            foreach (string s in Options.InternalOptions)
                supportedOptions[s] = null;

            //Figure out what module options are supported in the current setup
            List<Library.Interface.ICommandLineArgument> moduleOptions = new List<Duplicati.Library.Interface.ICommandLineArgument>();
            Dictionary<string, string> disabledModuleOptions = new Dictionary<string, string>();

            foreach (KeyValuePair<bool, Library.Interface.IGenericModule> m in m_options.LoadedModules)
                if (m.Value.SupportedCommands != null)
                    if (m.Key)
                        moduleOptions.AddRange(m.Value.SupportedCommands);
                    else
                    {
                        foreach (Library.Interface.ICommandLineArgument c in m.Value.SupportedCommands)
                        {
                            disabledModuleOptions[c.Name] = m.Value.DisplayName + " (" + m.Value.Key + ")";

                            if (c.Aliases != null)
                                foreach (string s in c.Aliases)
                                    disabledModuleOptions[s] = disabledModuleOptions[c.Name];
                        }
                    }

            //Now run through all supported options, and look for deprecated options
            foreach (IList<Library.Interface.ICommandLineArgument> l in new IList<Library.Interface.ICommandLineArgument>[] {
                m_options.SupportedCommands,
                DynamicLoader.BackendLoader.GetSupportedCommands(m_backend),
                m_options.NoEncryption ? null : DynamicLoader.EncryptionLoader.GetSupportedCommands(m_options.EncryptionModule),
                moduleOptions,
                DynamicLoader.CompressionLoader.GetSupportedCommands(m_options.CompressionModule) })
            {
                if (l != null)
                    foreach (Library.Interface.ICommandLineArgument a in l)
                    {
                        if (supportedOptions.ContainsKey(a.Name) && Array.IndexOf(Options.KnownDuplicates, a.Name.ToLower()) < 0)
                            stats.LogWarning(string.Format(Strings.Interface.DuplicateOptionNameWarning, a.Name), null);

                        supportedOptions[a.Name] = a;

                        if (a.Aliases != null)
                            foreach (string s in a.Aliases)
                            {
                                if (supportedOptions.ContainsKey(s) && Array.IndexOf(Options.KnownDuplicates, s.ToLower()) < 0)
                                    stats.LogWarning(string.Format(Strings.Interface.DuplicateOptionNameWarning, s), null);

                                supportedOptions[s] = a;
                            }

                        if (a.Deprecated)
                        {
                            List<string> aliases = new List<string>();
                            aliases.Add(a.Name);
                            if (a.Aliases != null)
                                aliases.AddRange(a.Aliases);

                            foreach (string s in aliases)
                                if (ropts.ContainsKey(s))
                                {
                                    string optname = a.Name;
                                    if (a.Name != s)
                                        optname += " (" + s + ")";

                                    stats.LogWarning(string.Format(Strings.Interface.DeprecatedOptionUsedWarning, optname, a.DeprecationMessage), null);
                                }

                        }
                    }
            }

            //Now look for options that were supplied but not supported
            foreach (string s in ropts.Keys)
                if (!supportedOptions.ContainsKey(s))
                    if (disabledModuleOptions.ContainsKey(s))
                        stats.LogWarning(string.Format(Strings.Interface.UnsupportedOptionDisabledModuleWarning, s, disabledModuleOptions[s]), null);
                    else
                        stats.LogWarning(string.Format(Strings.Interface.UnsupportedOptionWarning, s), null);

            //Look at the value supplied for each argument and see if is valid according to its type
            foreach (string s in ropts.Keys)
            {
                Library.Interface.ICommandLineArgument arg;
                if (supportedOptions.TryGetValue(s, out arg) && arg != null)
                {
                    string validationMessage = ValidateOptionValue(arg, s, ropts[s]);
                    if (validationMessage != null)
                        stats.LogWarning(validationMessage, null);
                }
            }

            //TODO: Based on the action, see if all options are relevant
        }
Пример #3
0
        /// <summary>
        /// Reads through a backup and finds the last backup entry that has a specific file
        /// </summary>
        /// <returns></returns>
        public List<KeyValuePair<string, DateTime>> FindLastFileVersion()
        {
            CommunicationStatistics stats = new CommunicationStatistics(DuplicatiOperationMode.FindLastFileVersion);
            SetupCommonOptions(stats);

            if (m_options.DontReadManifests)
                throw new Exception(Strings.Interface.ManifestsMustBeRead);

            if (string.IsNullOrEmpty(m_options.FileToRestore))
                throw new Exception(Strings.Interface.NoFilesGivenError);

            string[] filesToFind = m_options.FileToRestore.Split(System.IO.Path.PathSeparator);
            KeyValuePair<string, DateTime>[] results = new KeyValuePair<string, DateTime>[filesToFind.Length];
            for (int i = 0; i < results.Length; i++)
                results[i] = new KeyValuePair<string, DateTime>(filesToFind[i], new DateTime(0));

            using (BackendWrapper backend = new BackendWrapper(stats, m_backend, m_options))
            {
                //Extract the full backup set list
                List<ManifestEntry> fulls = backend.GetBackupSets();

                //Flatten the list
                List<ManifestEntry> workList = new List<ManifestEntry>();

                //The list is oldest first, this function work newest first
                fulls.Reverse();
                foreach (ManifestEntry f in fulls)
                {
                    f.Incrementals.Reverse();

                    workList.AddRange(f.Incrementals);
                    workList.Add(f);
                }

                bool warned_manifest_v1 = false;

                foreach (ManifestEntry mf in workList)
                {
                    List<Manifestfile.HashEntry> signatureHashes = null;
                    Manifestfile mfi;

                    using(Utility.TempFile tf = new Duplicati.Library.Utility.TempFile())
                    {
                        backend.Get(mf, null, tf, null);
                        mfi = new Manifestfile(tf, m_options.SkipFileHashChecks);
                        if (!m_options.SkipFileHashChecks)
                            signatureHashes = mfi.SignatureHashes;
                    }

                    //If there are no volumes, don't stop here
                    bool any_unmatched = true;

                    if (stats != null && !warned_manifest_v1 && (mfi.SourceDirs == null || mfi.SourceDirs.Length == 0))
                    {
                        warned_manifest_v1 = true;
                        stats.LogWarning(Strings.Interface.ManifestVersionRequiresRelativeNamesWarning, null);
                    }

                    foreach(KeyValuePair<SignatureEntry, ContentEntry> e in mf.Volumes)
                        using (Utility.TempFile tf = new Duplicati.Library.Utility.TempFile())
                        {
                            //Skip non-approved signature files
                            if (signatureHashes != null && e.Key.Volumenumber > signatureHashes.Count)
                            {
                                stats.LogWarning(string.Format(Strings.Interface.SkippedUnlistedSignatureFileWarning, e.Key.Filename), null);
                                continue;
                            }

                            backend.Get(e.Key, mfi, tf, signatureHashes == null ? null : signatureHashes[e.Key.Volumenumber - 1]);

                            any_unmatched = false;

                            RSync.RSyncDir.ContainsFile(mfi, filesToFind, DynamicLoader.CompressionLoader.GetModule(e.Key.Compression, tf, m_options.RawOptions));

                            for (int i = 0; i < filesToFind.Length; i++)
                            {
                                if (results[i].Value.Ticks == 0 && string.IsNullOrEmpty(filesToFind[i]))
                                    results[i] = new KeyValuePair<string,DateTime>(results[i].Key, mf.Time);
                                else
                                    any_unmatched = true;
                            }

                            if (!any_unmatched)
                                break;
                        }

                    if (!any_unmatched)
                        break;
                }

                return new List<KeyValuePair<string,DateTime>>(results);
            }
        }