public string Cleanup() { CommunicationStatistics stats = new CommunicationStatistics(XervBackupOperationMode.CleanUp); SetupCommonOptions(stats); bool anyRemoved = false; StringBuilder sb = new StringBuilder(); using (BackendWrapper backend = new BackendWrapper(stats, m_backend, m_options)) { List<ManifestEntry> sorted = backend.GetBackupSets(); List<ManifestEntry> entries = new List<ManifestEntry>(); entries.AddRange(sorted); foreach (ManifestEntry be in sorted) entries.AddRange(be.Incrementals); string cleanup = backend.DeleteOrphans(false); if (!string.IsNullOrEmpty(cleanup)) sb.AppendLine(cleanup); if (m_options.SkipFileHashChecks) throw new Exception(Strings.Interface.CannotCleanWithoutHashesError); if (m_options.DontReadManifests) throw new Exception(Strings.Interface.CannotCleanWithoutHashesError); //We need the manifests anyway, so we verify the chain if (entries.Count > 0) VerifyManifestChain(backend, entries[0]); //Now compare the actual filelist with the manifest foreach (ManifestEntry be in entries) { Manifestfile manifest = GetManifest(backend, be); int count = manifest.ContentHashes.Count; for (int i = count - 1; i < be.Volumes.Count; i++) { anyRemoved = true; string sigmsg = string.Format(Strings.Interface.RemovingPartialFilesMessage, be.Volumes[i].Key.Filename); string cntmsg = string.Format(Strings.Interface.RemovingPartialFilesMessage, be.Volumes[i].Value.Filename); Logging.Log.WriteMessage(sigmsg, XervBackup.Library.Logging.LogMessageType.Information); Logging.Log.WriteMessage(cntmsg, XervBackup.Library.Logging.LogMessageType.Information); sb.AppendLine(sigmsg); sb.AppendLine(cntmsg); if (m_options.Force) { backend.Delete(be.Volumes[i].Key); backend.Delete(be.Volumes[i].Value); } } } } if (!m_options.Force && anyRemoved) { Logging.Log.WriteMessage(Strings.Interface.FilesAreNotForceDeletedMessage, XervBackup.Library.Logging.LogMessageType.Information); sb.AppendLine(Strings.Interface.FilesAreNotForceDeletedMessage); } return sb.ToString(); //TODO: Write a message here? }
/// <summary> /// Downloads all required signature files from the backend. /// </summary> /// <param name="backend">The backend to read from</param> /// <param name="entries">The flattened list of manifests</param> /// <param name="tempfolder">The tempfolder set for this operation</param> /// <param name="allowHashFail">True to ignore files with failed hash signature</param> /// <returns>A list of file archives</returns> private List<KeyValuePair<ManifestEntry, Library.Interface.ICompression>> FindPatches(BackendWrapper backend, List<ManifestEntry> entries, string tempfolder, bool allowHashFail, CommunicationStatistics stat) { List<KeyValuePair<ManifestEntry, Library.Interface.ICompression>> patches = new List<KeyValuePair<ManifestEntry, Library.Interface.ICompression>>(); using (new Logging.Timer("Reading incremental data")) { OperationProgress(this, GetOperationType(), stat.OperationMode, (int)(m_progress * 100), -1, Strings.Interface.StatusReadingIncrementalData, ""); //Calculate the total number of files to download //, and verify their order int incCount = 0; foreach (ManifestEntry be in entries) { int volNo = 0; //Prevent order based bugs if (entries.IndexOf(be) > 0) if (entries[entries.IndexOf(be) - 1].Time >= be.Time) throw new Exception(Strings.Interface.BadSortingDetectedError); incCount++; foreach (KeyValuePair<SignatureEntry, ContentEntry> bes in be.Volumes) { incCount++; if (volNo + 1 != bes.Key.Volumenumber || bes.Key.Volumenumber != bes.Value.Volumenumber) throw new Exception(Strings.Interface.BadVolumeSortOrder); volNo++; } } //The incremental part has a fixed cost, and each file has a fixed fraction of that double unitCost = m_incrementalFraction / incCount; //Ensure that the manifest chain has not been tampered with // since we will read all manifest files anyway, there is no harm in doing it here if (!m_options.DontReadManifests && entries.Count > 0) VerifyManifestChain(backend, entries[entries.Count - 1]); foreach (ManifestEntry be in entries) { m_progress += unitCost; Manifestfile manifest = GetManifest(backend, be); foreach (KeyValuePair<SignatureEntry, ContentEntry> bes in be.Volumes) { m_progress += unitCost; //Skip non-listed incrementals if (manifest.SignatureHashes != null && bes.Key.Volumenumber > manifest.SignatureHashes.Count) { backend.AddOrphan(bes.Key); backend.AddOrphan(bes.Value); continue; } OperationProgress(this, GetOperationType(), stat.OperationMode, (int)(m_progress * 100), -1, string.Format(Strings.Interface.StatusReadingSignatureFile, be.Time.ToShortDateString() + " " + be.Time.ToShortTimeString(), bes.Key.Volumenumber), ""); string filename = System.IO.Path.Combine(tempfolder, "patch-" + patches.Count.ToString() + ".zip"); //Check just before we download stuff CheckLiveControl(); try { using (new Logging.Timer("Get " + bes.Key.Filename)) backend.Get(bes.Key, manifest, filename, manifest.SignatureHashes == null ? null : manifest.SignatureHashes[bes.Key.Volumenumber - 1]); } catch (BackendWrapper.HashMismathcException hme) { if (allowHashFail) { if (stat != null) stat.LogError(string.Format(Strings.Interface.FileHashFailure, hme.Message), hme); continue; } else throw; } patches.Add(new KeyValuePair<ManifestEntry,XervBackup.Library.Interface.ICompression>(be, DynamicLoader.CompressionLoader.GetModule(bes.Key.Compression, filename, m_options.RawOptions))); } } } backend.DeleteOrphans(true); return patches; }