// This updates cached XML, will still need flushing to disk afterwards in OutputToXml() public void SaveSnapshotRevision(VolumeSnapshot snapshot) { VolumeSnapshotRevision revision = snapshot.Revision; if (mSnapshotDictionary.ContainsKey(revision)) { mSnapshotDictionary[revision] = snapshot; } else { mSnapshotDictionary.Add(revision, snapshot); } System.IO.StringWriter stringWriter = new System.IO.StringWriter(); XmlTextWriter xmlWriter = new XmlTextWriter(stringWriter); xmlWriter.Formatting = Formatting.Indented; snapshot.OutputToXml(xmlWriter); string xmlFragment = stringWriter.ToString(); xmlWriter.Close(); stringWriter.Close(); if (mSnapshotXmlCache.ContainsKey(revision)) { mSnapshotXmlCache[revision] = xmlFragment; } else { mSnapshotXmlCache.Add(revision, xmlFragment); } }
// This updates cached XML, will still need flushing to disk afterwards in OutputToXml() public void SaveSnapshotRevision(VolumeSnapshot snapshot) { VolumeSnapshotRevision revision = snapshot.Revision; if (mSnapshotDictionary.ContainsKey(revision)) { mSnapshotDictionary[revision] = snapshot; } else { mSnapshotDictionary.Add(revision, snapshot); } if (!mSnapshotsStored.Contains(revision)) { mSnapshotsStored.Add(revision); } PWLib.Platform.Windows.Directory.CreateDirectory(mXmlRootDir); XmlTextWriter xmlWriter = new XmlTextWriter(GetRevisionFileName(revision), Encoding.Unicode); xmlWriter.Formatting = Formatting.Indented; xmlWriter.WriteStartDocument(); snapshot.OutputToXml(xmlWriter); xmlWriter.Close(); }
public bool Restore(VolumeSnapshotRevision revision, string onDiskPath) { bool success = false; mCancelledByUser = false; try { mBusy = true; VolumeSnapshot snapshot = mDatabase.LoadSnapshotRevision(mSource, revision); mRestoreOperation.Restore(snapshot, mArchive, onDiskPath); success = true; } catch (Exception e) { success = false; FileSync.__LogError(this, "BackupRestoreVolume.Restore", e); } finally { mBusy = false; } return(success); }
void TurnSnapshotIntoBaselinePrivate(VolumeSnapshotDirectory parentDir, ref List <VolumeSnapshotRevision> revisionsThatCanBeRemoved) { VolumeSnapshotRevision currentRevision = parentDir.Snapshot.Revision; foreach (VolumeSnapshotFile file in parentDir.Files) { if (file.Revision.Value < currentRevision.Value) { revisionsThatCanBeRemoved.Add(file.Revision); // file is older than current snapshot, copy it into the current snapshot // Use Move for speed - the file will be deleted in the next step anyway and // will no longer be needed mArchive.MoveFileFromRevision(file.Revision, currentRevision, file.RelativePath); // update revision id in .xml file file.Revision = currentRevision; } } foreach (VolumeSnapshotDirectory dir in parentDir.Directories) { if (dir.Revision.Value < currentRevision.Value) { dir.Revision = currentRevision; } TurnSnapshotIntoBaselinePrivate(dir, ref revisionsThatCanBeRemoved); } }
public override void RestoreFile(VolumeSnapshotRevision revision, string fileRelativePath, string onDiskOutputPath, ArchiveFileDelegate archiveFileDelegate, object userData) { if (onDiskOutputPath[onDiskOutputPath.Length - 1] == PWLib.Platform.Windows.Path.DirectorySeparatorChar) { onDiskOutputPath = onDiskOutputPath.Substring(0, onDiskOutputPath.Length - 1); } CopyFile(RelativePathToOnDiskPath(revision, fileRelativePath), onDiskOutputPath, archiveFileDelegate, userData); }
private VolumeSnapshotFile(VolumeSnapshot snapshot, VolumeSource source, string relativePath) { mSnapshot = snapshot; mRevision = null; mRelativePath = relativePath; mFileName = PWLib.Platform.Windows.Path.GetFileName(relativePath); mLastModified = source.GetLastWriteTimeUtc(relativePath); mFileSize = source.GetFileSize(relativePath); }
public override void CreateDirectory(VolumeSnapshotRevision revision, string relativePath) { string absPath = RelativePathToOnDiskPath(revision, relativePath); if (!PWLib.Platform.Windows.Directory.Exists(absPath)) { PWLib.Platform.Windows.Directory.CreateDirectory(absPath); } }
public void DeleteSnapshotRevision(VolumeSnapshotRevision revision) { if (mSnapshotXmlCache.ContainsKey(revision)) { mSnapshotXmlCache.Remove(revision); } if (mSnapshotDictionary.ContainsKey(revision)) { mSnapshotDictionary.Remove(revision); } }
public override void DeleteRevision(VolumeSnapshotRevision revision) { try { string revisionPath = RelativePathToOnDiskPath(revision, ""); PWLib.Platform.Windows.Path.DeletePath(revisionPath, true); PWLib.Platform.Windows.Directory.Remove(revisionPath, true); } catch (Exception) { } }
private VolumeSnapshot(VolumeSource source, XmlNode parentNode) { mRevision = VolumeSnapshotRevision.Create(PWLib.XmlHelp.GetAttribute(parentNode, VolumeSnapshotXml.XmlRevisionElement, "")); if (mRevision == null) { throw new Exception("Could not read revision from snapshot xml '" + parentNode.Name + "'"); } mRoot = VolumeSnapshotDirectory.BuildFromXml(this, PWLib.XmlHelp.GetFirstChildWithName(parentNode, "directory")); mFileCount = mRoot.CountAllFiles(ref mTotalFileSize); }
void MergeSnapshotRevisions(VolumeSnapshotDatabase database, VolumeSource source, BaseArchive archive, int numRevisionsToRemove) { try { mDatabase = database; mArchive = archive; mBusy = true; List <VolumeSnapshotRevision> revisionHistory = database.GetRevisionHistory(); if (numRevisionsToRemove == revisionHistory.Count) { // Need to remove all old revisions, delete everything FileSync.__Log(this, "Merge deleting all revisions"); database.DeleteAllRevisions(); } else { // now we know how many revisions to remove, need to rebuild the new first revision. VolumeSnapshotRevision currentRevision = revisionHistory[numRevisionsToRemove]; VolumeSnapshot currentSnapshot = database.LoadSnapshotRevision(source, currentRevision); FileSync.__Log(this, "Merge is turning revision [" + currentRevision.ToString() + "] into baseline"); TurnSnapshotIntoBaseline(currentSnapshot); // Now go through all existing snapshot .xml files and change any files referencing // a snapshot that has been removed and change it to the current snapshot revision. for (int revisionNum = numRevisionsToRemove + 1; revisionNum < revisionHistory.Count; ++revisionNum) { VolumeSnapshotRevision incrementalRevision = revisionHistory[revisionNum]; VolumeSnapshot incrementalSnapshot = database.LoadSnapshotRevision(source, incrementalRevision); FileSync.__Log(this, "Merge is reflecting revision [" + incrementalRevision.ToString() + "] into new baseline [" + currentRevision.ToString() + "]"); UpdateSnapshotToReflectBaselineRevision(incrementalSnapshot, currentRevision); } // delete old revision data for (int revisionNum = 0; revisionNum < numRevisionsToRemove; ++revisionNum) { VolumeSnapshotRevision revisionToDelete = revisionHistory[revisionNum]; FileSync.__Log(this, "Merge is deleting revision [" + revisionToDelete.ToString() + "]"); database.DeleteSnapshotRevision(revisionToDelete); } } } catch (System.Exception ex) { FileSync.__LogError(this, "Volume.CheckForExpiredSnapshotRevisions", ex); } finally { mBusy = false; } }
public void DeleteSnapshotRevision(VolumeSnapshotRevision revision) { PWLib.Platform.Windows.File.Delete(GetRevisionFileName(revision)); if (mSnapshotsStored.Contains(revision)) { mSnapshotsStored.Remove(revision); } if (mSnapshotDictionary.ContainsKey(revision)) { mSnapshotDictionary.Remove(revision); } }
private VolumeSnapshotDatabase(XmlNode parentNode) { XmlNode element = PWLib.XmlHelp.GetFirstChildWithName(parentNode, "snapshots"); foreach (XmlNode childNode in element.ChildNodes) { string lowerName = childNode.Name.ToLower(); if (lowerName == VolumeSnapshotXml.XmlSnapshotElement) { string revisionTicks = PWLib.XmlHelp.GetAttribute(childNode, VolumeSnapshotXml.XmlRevisionElement, ""); VolumeSnapshotRevision revision = VolumeSnapshotRevision.Create(revisionTicks); mSnapshotXmlCache.Add(revision, childNode.OuterXml); } } }
private VolumeSnapshotFile(VolumeSnapshot snapshot, XmlNode node) { mSnapshot = snapshot; mFileName = PWLib.XmlHelp.DirtyString(PWLib.XmlHelp.GetAttribute(node, VolumeSnapshotXml.XmlFilenameElement, "")); mRelativePath = PWLib.XmlHelp.DirtyString(PWLib.XmlHelp.GetAttribute(node, VolumeSnapshotXml.XmlRelativePathElement, "")); mRevision = VolumeSnapshotRevision.Create(PWLib.XmlHelp.GetAttribute(node, VolumeSnapshotXml.XmlRevisionElement, "")); ulong.TryParse(PWLib.XmlHelp.GetAttribute(node, VolumeSnapshotXml.XmlSizeElement, "0"), out mFileSize); long ticks; if (long.TryParse(PWLib.XmlHelp.GetAttribute(node, VolumeSnapshotXml.XmlLastModifiedElement, "0"), out ticks)) { mLastModified = new DateTime(ticks); } }
public VolumeSnapshot LoadSnapshotRevision(VolumeSource source, VolumeSnapshotRevision revision) { if (mSnapshotDictionary.ContainsKey(revision)) { return(mSnapshotDictionary[revision]); } else { XmlDocument doc = new XmlDocument(); doc.Load(GetRevisionFileName(revision)); XmlNode snapshotXmlNode = PWLib.XmlHelp.GetFirstChildWithName(doc, VolumeSnapshotXml.XmlSnapshotElement); VolumeSnapshot snapshot = VolumeSnapshot.BuildFromXml(source, snapshotXmlNode); mSnapshotDictionary.Add(revision, snapshot); return(snapshot); } }
private VolumeSnapshotDirectory(VolumeSnapshot snapshot, XmlNode parentNode) { mSnapshot = snapshot; mName = PWLib.XmlHelp.DirtyString(PWLib.XmlHelp.GetAttribute(parentNode, VolumeSnapshotXml.XmlNameElement, "")); mRelativePath = PWLib.XmlHelp.DirtyString(PWLib.XmlHelp.GetAttribute(parentNode, VolumeSnapshotXml.XmlRelativePathElement, "")); mRevision = VolumeSnapshotRevision.Create(PWLib.XmlHelp.GetAttribute(parentNode, VolumeSnapshotXml.XmlRevisionElement, "")); long ticks; if (long.TryParse(PWLib.XmlHelp.GetAttribute(parentNode, VolumeSnapshotXml.XmlLastModifiedElement, "0"), out ticks)) { mLastModified = new DateTime(ticks); } foreach (XmlNode childNode in parentNode.ChildNodes) { string lowerName = childNode.Name.ToLower(); if (lowerName == VolumeSnapshotXml.XmlDirectoryElement) // Sub directories { try { VolumeSnapshotDirectory subDirEntry = new VolumeSnapshotDirectory(mSnapshot, childNode); mDirectories.Add(subDirEntry); } catch (System.Exception e) { FileSync.__LogError(this, "VolumeSnapshotDirectory.BuildFromXml failed in directory '" + mName + "' '" + mRelativePath + "'", e); } } else if (lowerName == VolumeSnapshotXml.XmlFileElement) // Files { try { VolumeSnapshotFile fileEntry = VolumeSnapshotFile.BuildFromXml(mSnapshot, childNode); mFiles.Add(fileEntry); } catch (System.Exception e) { FileSync.__LogError(this, "VolumeSnapshotDirectory.BuildFromXml failed in directory on a file '" + mName + "' '" + mRelativePath + "'", e); } } } }
public VolumeSnapshot LoadSnapshotRevision(VolumeSource source, VolumeSnapshotRevision revision) { if (mSnapshotDictionary.ContainsKey(revision)) { return(mSnapshotDictionary[revision]); } else { if (!mSnapshotXmlCache.ContainsKey(revision)) { throw new Exception("Could not locate snapshot revision '" + revision.ToString() + "' in database"); } string xmlFragment = mSnapshotXmlCache[revision]; XmlDocument doc = new XmlDocument(); doc.LoadXml(xmlFragment); XmlNode snapshotXmlNode = PWLib.XmlHelp.GetFirstChildWithName(doc, VolumeSnapshotXml.XmlSnapshotElement); VolumeSnapshot snapshot = VolumeSnapshot.BuildFromXml(source, snapshotXmlNode); mSnapshotDictionary.Add(revision, snapshot); return(snapshot); } }
private VolumeSnapshot(VolumeSource source) { mRevision = VolumeSnapshotRevision.CreateNew(); mRoot = VolumeSnapshotDirectory.BuildFromSource(this, source, ""); mFileCount = mRoot.CountAllFiles(ref mTotalFileSize); }
public abstract void CreateDirectory(VolumeSnapshotRevision revision, string relativePath);
public abstract void MoveFileFromRevision(VolumeSnapshotRevision sourceRevision, VolumeSnapshotRevision targetRevision, string fileRelativePath);
public abstract void CopyFileFromRevision(VolumeSnapshotRevision sourceRevision, VolumeSnapshotRevision targetRevision, string fileRelativePath, ArchiveFileDelegate archiveFileDelegate, object userData);
public abstract void RestoreFile(VolumeSnapshotRevision revision, string fileRelativePath, string onDiskOutputPath, ArchiveFileDelegate archiveFileDelegate, object userData);
public abstract void DeleteRevision(VolumeSnapshotRevision revision);
private string RelativePathToOnDiskPath(VolumeSnapshotRevision revision, string relativePath) { string path = mStoragePath + PWLib.Platform.Windows.Path.DirectorySeparatorChar + revision.ToString() + relativePath; return(path); }
public override void StoreFile(VolumeSnapshotRevision revision, string relativePath, string onDiskPath, ArchiveFileDelegate archiveFileDelegate, object userData) { CopyFile(onDiskPath, RelativePathToOnDiskPath(revision, relativePath), archiveFileDelegate, userData); }
public override void CopyFileFromRevision(VolumeSnapshotRevision sourceRevision, VolumeSnapshotRevision targetRevision, string fileRelativePath, ArchiveFileDelegate archiveFileDelegate, object userData) { CopyFile(RelativePathToOnDiskPath(sourceRevision, fileRelativePath), RelativePathToOnDiskPath(targetRevision, fileRelativePath), archiveFileDelegate, userData); }
public bool DoBackup(ref bool outputToXmlRequired) { VolumeSnapshot currentSnapshot = null; bool backupSuccess = false; bool noChangesRequired = false; outputToXmlRequired = false; mCancelledByUser = false; try { mBusy = true; FileSync.__Log(this, "Building standing on disk snapshot..."); // Take a snapshot of the volume as it stands on disk currentSnapshot = VolumeSnapshot.BuildFromSource(mSource); if (!currentSnapshot.Empty) { FileSync.__Log(this, "Snapshot built, " + currentSnapshot.FileCount + " files found"); VolumeSnapshotRevision mostRecentRevision = mDatabase.GetMostRecentRevision(); // Compare to previous snapshot if (mostRecentRevision != null) { FileSync.__Log(this, "Starting incremental backup, " + mDatabase.GetRevisionHistory().Count + " revisions existing [Most recent: " + mostRecentRevision.ToString() + "]"); // Only do an incremental backup to backup whats changed since last full snapshot VolumeSnapshot mostRecentSnapshot = mDatabase.LoadSnapshotRevision(mSource, mostRecentRevision); backupSuccess = mBackupOperation.DoIncrementalBackup(currentSnapshot, mostRecentSnapshot, mSource, mArchive, out noChangesRequired); FileSync.__Log(this, "Incremental backup " + (backupSuccess ? "completed successfully" : "failed") + " " + (noChangesRequired ? "no changes required" : "changes detected")); } else { FileSync.__Log(this, "Starting full initial backup"); // Brand new volume backup, do a full backup of the volume backupSuccess = mBackupOperation.DoFullBackup(currentSnapshot, mSource, mArchive); FileSync.__Log(this, "Full backup " + (backupSuccess ? "completed successfully" : "failed")); } if (backupSuccess) { if (!noChangesRequired) { FileSync.__Log(this, "Saving snapshot revision file [" + currentSnapshot.Revision.ToString() + "]"); mDatabase.SaveSnapshotRevision(currentSnapshot); outputToXmlRequired = true; FileSync.__Log(this, "Snapshot file saved"); } else { FileSync.__Log(this, "No changes required, not saving revision [" + currentSnapshot.Revision.ToString() + "]"); } } else { FileSync.__Log(this, "Backup failed, deleting temporary files for revision [" + currentSnapshot.Revision.ToString() + "]"); mDatabase.DeleteSnapshotRevision(currentSnapshot.Revision); // remove half-copied data mArchive.DeleteRevision(currentSnapshot.Revision); outputToXmlRequired = true; } } else { FileSync.__Log(this, "Built snapshot is empty, aborting backup"); } } catch (Exception e) { backupSuccess = false; FileSync.__LogError(this, "BackupRestoreVolume.DoBackup", e); if (currentSnapshot != null) { FileSync.__Log(this, "Backup failed due to exception caught, deleting temporary files for revision [" + currentSnapshot.Revision.ToString() + "]"); mDatabase.DeleteSnapshotRevision(currentSnapshot.Revision); // remove half-copied data mArchive.DeleteRevision(currentSnapshot.Revision); } outputToXmlRequired = true; } finally { mBusy = false; } return(backupSuccess); }
public abstract void StoreFile(VolumeSnapshotRevision revision, string relativePath, string onDiskPath, ArchiveFileDelegate archiveFileDelegate, object userData);
string GetRevisionFileName(VolumeSnapshotRevision revision) { return(mXmlRootDir + PWLib.Platform.Windows.Path.DirectorySeparatorChar + revision.Value.ToString() + ".xml"); }
public override void MoveFileFromRevision(VolumeSnapshotRevision sourceRevision, VolumeSnapshotRevision targetRevision, string fileRelativePath) { PWLib.Platform.Windows.File.Move(RelativePathToOnDiskPath(sourceRevision, fileRelativePath), RelativePathToOnDiskPath(targetRevision, fileRelativePath)); }