public List<KeyValuePair<BackupEntryBase, Exception>> VerifyBackupChain() { CommunicationStatistics stats = new CommunicationStatistics(XervBackupOperationMode.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 XervBackup.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 XervBackup.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 XervBackup.Library.Utility.TempFile()) { vf.Save(tf); tf.Protected = true; backend.Put(new VerificationEntry(entries[entries.Count - 1].Time), tf); } } } return results; }
public string Restore(string[] target) { RestoreStatistics rs = new RestoreStatistics(XervBackupOperationMode.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, XervBackupOperation.Restore, rs.OperationMode, -1, -1, Strings.Interface.StatusStarted, ""); OperationProgress(this, XervBackupOperation.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<XervBackup.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 XervBackup.Library.Utility.FilenameFilter(list); } backend = new BackendWrapper(rs, m_backend, m_options); backend.ProgressEvent += new XervBackup.Library.Main.RSync.RSyncDir.ProgressEventDelegate(BackupTransfer_ProgressEvent); OperationProgress(this, XervBackupOperation.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, XervBackupOperation.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 XervBackup.Library.Main.RSync.RSyncDir(target, rs, filter)) { sync.ProgressEvent += new XervBackup.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), XervBackup.Library.Logging.LogMessageType.Warning); rs.LogWarning(string.Format(Strings.Interface.SkippedContentVolumeLogMessage, contentVol.Volumenumber), null); patchno++; continue; } using (Utility.TempFile patchzip = new XervBackup.Library.Utility.TempFile()) { OperationProgress(this, XervBackupOperation.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 XervBackup.Library.Utility.TempFile()) { OperationProgress(this, XervBackupOperation.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, XervBackupOperation.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, XervBackupOperation.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, XervBackupOperation.Restore, rs.OperationMode, 100, -1, Strings.Interface.StatusCompleted, ""); OperationProgress(this, XervBackupOperation.Restore, rs.OperationMode, 100, -1, Strings.Interface.StatusCompleted, ""); } } rs.EndTime = DateTime.Now; return rs.ToString(); }
public IList<string> ListCurrentFiles() { RestoreStatistics rs = new RestoreStatistics(XervBackupOperationMode.ListCurrentFiles); SetupCommonOptions(rs); Utility.FilenameFilter filter = m_options.Filter; DateTime timelimit = m_options.RestoreTime; if (OperationStarted != null) OperationStarted(this, XervBackupOperation.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 XervBackup.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 XervBackup.Library.Main.RSync.RSyncDir(new string[] { basefolder }, rs, filter, patches)) res = dir.UnmatchedFiles(); } if (OperationCompleted != null) OperationCompleted(this, XervBackupOperation.List, rs.OperationMode, 100, -1, Strings.Interface.StatusCompleted, ""); return res; }
public string[] ListSourceFolders() { RestoreStatistics rs = new RestoreStatistics(XervBackupOperationMode.ListSourceFolders); SetupCommonOptions(rs); if (m_options.DontReadManifests) throw new Exception(Strings.Interface.ManifestsMustBeRead); DateTime timelimit = m_options.RestoreTime; if (OperationStarted != null) OperationStarted(this, XervBackupOperation.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 XervBackup.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, XervBackupOperation.List, rs.OperationMode, 100, -1, Strings.Interface.StatusCompleted, ""); return res; }
public List<KeyValuePair<RSync.RSyncDir.PatchFileType, string>> ListActualSignatureFiles() { CommunicationStatistics stats = new CommunicationStatistics(XervBackupOperationMode.ListActualSignatureFiles); SetupCommonOptions(stats); using (BackendWrapper backend = new BackendWrapper(stats, m_backend, m_options)) { ManifestEntry bestFit = backend.GetBackupSet(m_options.RestoreTime); if (bestFit.Incrementals.Count > 0) //Get the most recent incremental bestFit = bestFit.Incrementals[bestFit.Incrementals.Count - 1]; using (Utility.TempFolder folder = new XervBackup.Library.Utility.TempFolder()) { List<Library.Interface.ICompression> patches = new List<XervBackup.Library.Interface.ICompression>(); foreach (KeyValuePair<ManifestEntry, Library.Interface.ICompression> entry in FindPatches(backend, new List<ManifestEntry>(new ManifestEntry[] { bestFit }), folder, false, stats)) patches.Add(entry.Value); using (RSync.RSyncDir dir = new XervBackup.Library.Main.RSync.RSyncDir(new string[] { folder }, stats, null)) return dir.ListPatchFiles(patches); } } }