Example #1
0
        /// <summary>
        /// Restores control files added to a backup.
        /// </summary>
        /// <param name="target">The folder into which to restore the files</param>
        /// <returns>A restore report</returns>
        public string RestoreControlFiles(string target)
        {
            RestoreStatistics rs = new RestoreStatistics(DuplicatiOperationMode.RestoreControlfiles);
            SetupCommonOptions(rs);

            BackendWrapper backend = null;

            using (new Logging.Timer("Restore control files from " + m_backend + " to " + target))
            {
                try
                {
                    if (OperationStarted != null)
                        OperationStarted(this, DuplicatiOperation.Restore, rs.OperationMode, 0, -1, Strings.Interface.StatusStarted, "");

                    backend = new BackendWrapper(rs, m_backend, m_options);

                    List<ManifestEntry> attempts = backend.GetBackupSets();

                    List<ManifestEntry> flatlist = new List<ManifestEntry>();
                    foreach (ManifestEntry be in attempts)
                    {
                        flatlist.Add(be);
                        flatlist.AddRange(be.Incrementals);
                    }

                    flatlist.Reverse();

                    string prefix = Utility.Utility.AppendDirSeparator(RSync.RSyncDir.CONTROL_ROOT);

                    foreach (ManifestEntry be in flatlist)
                    {
                        if (be.Volumes.Count > 0)
                            using(Utility.TempFile z = new Duplicati.Library.Utility.TempFile())
                            {
                                OperationProgress(this, DuplicatiOperation.Restore, rs.OperationMode, 0, -1, string.Format(Strings.Interface.StatusReadingIncrementalFile, be.Volumes[0].Key.Filename), "");

                                Manifestfile mf = GetManifest(backend, be);

                                OperationProgress(this, DuplicatiOperation.Restore, rs.OperationMode, 0, -1, string.Format(Strings.Interface.StatusReadingIncrementalFile, be.Volumes[0].Key.Filename), "");

                                using (new Logging.Timer("Get " + be.Volumes[0].Key.Filename))
                                    backend.Get(be.Volumes[0].Key, mf, z, mf.SignatureHashes == null ? null : mf.SignatureHashes[0]);

                                using(Library.Interface.ICompression fz = DynamicLoader.CompressionLoader.GetModule(be.Volumes[0].Key.Compression, z, m_options.RawOptions))
                                {
                                    bool any = false;
                                    foreach (string f in fz.ListFiles(prefix))
                                    {
                                        any = true;
                                        using (System.IO.Stream s1 = fz.OpenRead(f))
                                        using (System.IO.Stream s2 = System.IO.File.Create(System.IO.Path.Combine(target, f.Substring(prefix.Length))))
                                            Utility.Utility.CopyStream(s1, s2);
                                    }

                                    if (any)
                                        break;

                                    rs.LogError(string.Format(Strings.Interface.FailedToFindControlFilesMessage, be.Volumes[0].Key.Filename), null);
                                }
                            }
                    }

                }
                finally
                {
                    if (backend != null)
                        backend.Dispose();

                    if (OperationCompleted != null)
                        OperationCompleted(this, DuplicatiOperation.Restore, rs.OperationMode, 100, -1, Strings.Interface.StatusCompleted, "");
                }
            }

            rs.EndTime = DateTime.Now;

            return rs.ToString();
        }
Example #2
0
        public string[] ListSourceFolders()
        {
            RestoreStatistics rs = new RestoreStatistics(DuplicatiOperationMode.ListSourceFolders);
            SetupCommonOptions(rs);

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

            DateTime timelimit = m_options.RestoreTime;

            if (OperationStarted != null)
                OperationStarted(this, DuplicatiOperation.List, rs.OperationMode, 0, -1, Strings.Interface.StatusStarted, "");

            string[] res;

            using (BackendWrapper backend = new BackendWrapper(rs, m_backend, m_options))
            using (Utility.TempFile mfile = new Duplicati.Library.Utility.TempFile())
            {
                ManifestEntry bestFit = backend.GetBackupSet(timelimit);

                backend.Get(bestFit, null, mfile, null);
                res = new Manifestfile(mfile, m_options.SkipFileHashChecks).SourceDirs;
            }

            if (OperationCompleted != null)
                OperationCompleted(this, DuplicatiOperation.List, rs.OperationMode, 100, -1, Strings.Interface.StatusCompleted, "");

            return res;
        }
Example #3
0
        public string Restore(string[] target)
        {
            RestoreStatistics rs = new RestoreStatistics(DuplicatiOperationMode.Restore);
            SetupCommonOptions(rs);

            m_progress = 0;
            BackendWrapper backend = null;
            m_restorePatches = 0;

            using (new Logging.Timer("Restore from " + m_backend + " to " + string.Join(System.IO.Path.PathSeparator.ToString(), target)))
            {
                try
                {
                    if (OperationStarted != null)
                        OperationStarted(this, DuplicatiOperation.Restore, rs.OperationMode, -1, -1, Strings.Interface.StatusStarted, "");
                    OperationProgress(this, DuplicatiOperation.Restore, rs.OperationMode, -1, -1, Strings.Interface.StatusStarted, "");

                    Utility.FilenameFilter filter = m_options.Filter;

                    //Filter is prefered, if both file and filter is specified
                    if (!m_options.HasFilter && !string.IsNullOrEmpty(m_options.FileToRestore))
                    {
                        List<Utility.IFilenameFilter> list = new List<Duplicati.Library.Utility.IFilenameFilter>();
                        list.Add(new Utility.FilelistFilter(true, m_options.FileToRestore.Split(System.IO.Path.PathSeparator)));
                        list.Add(new Utility.RegularExpressionFilter(false, ".*"));

                        filter = new Duplicati.Library.Utility.FilenameFilter(list);
                    }

                    backend = new BackendWrapper(rs, m_backend, m_options);
                    backend.ProgressEvent += new Duplicati.Library.Main.RSync.RSyncDir.ProgressEventDelegate(BackupTransfer_ProgressEvent);

                    OperationProgress(this, DuplicatiOperation.Restore, rs.OperationMode, (int)(m_progress * 100), -1, Strings.Interface.StatusReadingIncrementals, "");

                    ManifestEntry bestFit = backend.GetBackupSet(m_options.RestoreTime);

                    //We will need all the manifests downloaded anyway
                    if (!m_options.DontReadManifests)
                    {
                        if (bestFit.Incrementals.Count > 0)
                            VerifyManifestChain(backend, bestFit.Incrementals[bestFit.Incrementals.Count - 1]);
                        else
                            VerifyManifestChain(backend, bestFit);

                        OperationProgress(this, DuplicatiOperation.Restore, rs.OperationMode, (int)(m_progress * 100), -1, Strings.Interface.StatusReadingIncrementals, "");
                    }

                    m_progress = INCREMENAL_COST;

                    List<ManifestEntry> entries = new List<ManifestEntry>();
                    entries.Add(bestFit);
                    entries.AddRange(bestFit.Incrementals);
                    int patchno = 0;

                    foreach (ManifestEntry be in entries)
                        m_restorePatches += be.Volumes.Count;

                    Manifestfile rootManifest = GetManifest(backend, bestFit);

                    int sourceDirCount = (rootManifest.SourceDirs == null || rootManifest.SourceDirs.Length == 0) ? 1 : rootManifest.SourceDirs.Length;

                    //After reading the first manifest, we know the source folder count
                    if ((rootManifest.SourceDirs == null || rootManifest.SourceDirs.Length == 0) && target.Length > 1)
                    {
                        //V1 support
                        rs.LogWarning(string.Format(Strings.Interface.TooManyTargetFoldersWarning, 1, target.Length), null);
                        Array.Resize(ref target, 1);
                    }
                    else if (target.Length > sourceDirCount)
                    {
                        //If we get too many, we can just cut them off
                        rs.LogWarning(string.Format(Strings.Interface.TooManyTargetFoldersWarning, sourceDirCount, target.Length), null);
                        Array.Resize(ref target, rootManifest.SourceDirs.Length);
                    }
                    else if (target.Length != 1 && target.Length < sourceDirCount)
                    {
                        //If we get too few, we have to bail
                        throw new Exception(string.Format(Strings.Interface.TooFewTargetFoldersError, sourceDirCount, target.Length));
                    }
                    else if (target.Length == 1 && sourceDirCount > 1)
                    {
                        //If there is just one target folder, we automatically compose target subfolders
                        string[] newtargets = new string[rootManifest.SourceDirs.Length];

                        List<string> suggestions = new List<string>();
                        for (int i = 0; i < rootManifest.SourceDirs.Length; i++)
                        {
                            string s = rootManifest.SourceDirs[i];
                            //HACK: We use a leading / in the path name to detect source OS
                            // all paths are absolute, so this detects all unix like systems
                            string dirSepChar = s.StartsWith("/") ? "/" : "\\";

                            if (s.EndsWith(dirSepChar))
                                s = s.Substring(0, s.Length - 1);

                            int lix = s.LastIndexOf(dirSepChar);
                            if (lix < 0 || lix + 1 >= s.Length)
                                s = i.ToString();
                            else
                                s = s.Substring(lix + 1);

                            foreach (char c in System.IO.Path.GetInvalidFileNameChars())
                                s = s.Replace(c, '_');

                            suggestions.Add(s);
                        }

                        Dictionary<string, int> duplicates = new Dictionary<string, int>(Library.Utility.Utility.ClientFilenameStringComparer);
                        for (int i = 0; i < suggestions.Count; i++)
                            if (duplicates.ContainsKey(suggestions[i]))
                                duplicates[suggestions[i]]++;
                            else
                                duplicates[suggestions[i]] = 1;

                        for (int i = 0; i < newtargets.Length; i++)
                        {
                            string suffix = duplicates[suggestions[i]] > 1 ? i.ToString() : suggestions[i];
                            newtargets[i] = System.IO.Path.Combine(target[0], suffix);
                        }

                        target = newtargets;
                    }

                    //Make sure all targets exist
                    foreach(string s in target)
                        if (!System.IO.Directory.Exists(s))
                            System.IO.Directory.CreateDirectory(s);

                    using (RSync.RSyncDir sync = new Duplicati.Library.Main.RSync.RSyncDir(target, rs, filter))
                    {
                        sync.ProgressEvent += new Duplicati.Library.Main.RSync.RSyncDir.ProgressEventDelegate(RestoreRSyncDir_ProgressEvent);

                        foreach (ManifestEntry be in entries)
                        {
                            m_progress = ((1.0 - INCREMENAL_COST) * (patchno / (double)m_restorePatches)) + INCREMENAL_COST;

                            CheckLiveControl();

                            Manifestfile manifest = be == bestFit ? rootManifest : GetManifest(backend, be);

                            CheckLiveControl();

                            foreach (KeyValuePair<SignatureEntry, ContentEntry> vol in be.Volumes)
                            {
                                ContentEntry contentVol = vol.Value;
                                SignatureEntry signatureVol = vol.Key;

                                m_progress = ((1.0 - INCREMENAL_COST) * (patchno / (double)m_restorePatches)) + INCREMENAL_COST;

                                //Skip nonlisted
                                if (manifest.ContentHashes != null && contentVol.Volumenumber > manifest.ContentHashes.Count)
                                {
                                    Logging.Log.WriteMessage(string.Format(Strings.Interface.SkippedContentVolumeLogMessage, contentVol.Volumenumber), Duplicati.Library.Logging.LogMessageType.Warning);
                                    rs.LogWarning(string.Format(Strings.Interface.SkippedContentVolumeLogMessage, contentVol.Volumenumber), null);
                                    patchno++;
                                    continue;
                                }

                                using (Utility.TempFile patchzip = new Duplicati.Library.Utility.TempFile())
                                {
                                    OperationProgress(this, DuplicatiOperation.Restore, rs.OperationMode, (int)(m_progress * 100), -1, string.Format(Strings.Interface.StatusPatching, patchno + 1), "");

                                    CheckLiveControl();

                                     if (m_options.HasFilter || !string.IsNullOrEmpty(m_options.FileToRestore))
                                     {
                                         bool hasFiles = false;

                                         using (Utility.TempFile sigFile = new Duplicati.Library.Utility.TempFile())
                                         {
                                             OperationProgress(this, DuplicatiOperation.Restore, rs.OperationMode, (int)(m_progress * 100), -1, string.Format(Strings.Interface.StatusDownloadingSignatureVolume, patchno + 1), "");

                                             try
                                             {
                                                 using (new Logging.Timer("Get " + signatureVol.Filename))
                                                     backend.Get(signatureVol, manifest, sigFile, manifest.SignatureHashes == null ? null : manifest.SignatureHashes[signatureVol.Volumenumber - 1]);
                                             }
                                             catch (BackendWrapper.HashMismathcException hme)
                                             {
                                                 hasFiles = true;
                                                 rs.LogError(string.Format(Strings.Interface.FileHashFailure, hme.Message), hme);
                                             }

                                             if (!hasFiles)
                                                 using (Library.Interface.ICompression patch = DynamicLoader.CompressionLoader.GetModule(signatureVol.Compression, sigFile, m_options.RawOptions))
                                                 {
                                                     foreach(KeyValuePair<RSync.RSyncDir.PatchFileType, string> k in sync.ListPatchFiles(patch))
                                                         if (filter.ShouldInclude("", System.IO.Path.DirectorySeparatorChar.ToString() + k.Value))
                                                         {
                                                             //TODO: Perhaps a bit much to download the content archive
                                                             // if the file is only marked for deletion?
                                                             hasFiles = true;
                                                             break;
                                                         }
                                                 }
                                         }

                                         if (!hasFiles)
                                         {
                                             //Avoid downloading the content file
                                             patchno++;
                                             continue;
                                         }
                                    }

                                     OperationProgress(this, DuplicatiOperation.Restore, rs.OperationMode, (int)(m_progress * 100), -1, string.Format(Strings.Interface.StatusDownloadingContentVolume, patchno + 1), "");

                                    using (new Logging.Timer("Get " + contentVol.Filename))
                                        backend.Get(contentVol, manifest, patchzip, manifest.ContentHashes == null ? null : manifest.ContentHashes[contentVol.Volumenumber - 1]);

                                    OperationProgress(this, DuplicatiOperation.Restore, rs.OperationMode, (int)(m_progress * 100), -1, string.Format(Strings.Interface.StatusPatching, patchno + 1), "");

                                    using (new Logging.Timer((patchno == 0 ? "Full restore to: " : "Incremental restore " + patchno.ToString() + " to: ") + string.Join(System.IO.Path.PathSeparator.ToString(), target)))
                                    using (Library.Interface.ICompression patch = DynamicLoader.CompressionLoader.GetModule(contentVol.Compression, patchzip, m_options.RawOptions))
                                        sync.Patch(target, patch);
                                }
                                patchno++;
                            }

                            //Make sure there are no partial files, as partial files are not allowed to span backup sets
                            sync.FinalizeRestore();
                        }
                    }
                }
                finally
                {
                    if (backend != null)
                        backend.Dispose();

                    if (OperationCompleted != null)
                        OperationCompleted(this, DuplicatiOperation.Restore, rs.OperationMode, 100, -1, Strings.Interface.StatusCompleted, "");

                    OperationProgress(this, DuplicatiOperation.Restore, rs.OperationMode, 100, -1, Strings.Interface.StatusCompleted, "");
                }
            }

            rs.EndTime = DateTime.Now;
            return rs.ToString();
        }
Example #4
0
        public IList<string> ListCurrentFiles()
        {
            RestoreStatistics rs = new RestoreStatistics(DuplicatiOperationMode.ListCurrentFiles);
            SetupCommonOptions(rs);

            Utility.FilenameFilter filter = m_options.Filter;
            DateTime timelimit = m_options.RestoreTime;

            if (OperationStarted != null)
                OperationStarted(this, DuplicatiOperation.List, rs.OperationMode, 0, -1, Strings.Interface.StatusStarted, "");

            List<string> res;

            using (BackendWrapper backend = new BackendWrapper(rs, m_backend, m_options))
            using (Utility.TempFolder basefolder = new Duplicati.Library.Utility.TempFolder())
            {
                ManifestEntry bestFit = backend.GetBackupSet(timelimit);

                List<ManifestEntry> entries = new List<ManifestEntry>();
                entries.Add(bestFit);
                entries.AddRange(bestFit.Incrementals);

                List<KeyValuePair<ManifestEntry, Library.Interface.ICompression>> patches = FindPatches(backend, entries, basefolder, false, rs);

                using (RSync.RSyncDir dir = new Duplicati.Library.Main.RSync.RSyncDir(new string[] { basefolder }, rs, filter, patches))
                    res = dir.UnmatchedFiles();
            }

            if (OperationCompleted != null)
                OperationCompleted(this, DuplicatiOperation.List, rs.OperationMode, 100, -1, Strings.Interface.StatusCompleted, "");

            return res;
        }