void CopyFileToBackup(VolumeSnapshotFile file) { try { if (!mOperation.CanContinue) { return; } file.Revision = file.Snapshot.Revision; mArchive.StoreFile(file.Snapshot.Revision, file.RelativePath, mSource.GetOnDiskPath(file.RelativePath), new ArchiveFileDelegate(Backup_ArchiveStoreFile), file); ulong runningSize = mFilesTotalSizeRunning + file.FileSize; if (runningSize > mFilesTotalSize) { runningSize = mFilesTotalSize; } if (Progress != null) { Progress(mFileRunningCount + 1, mFileTotalCount, runningSize, mFilesTotalSize); } } catch (System.Exception e) { mOperation.Cancel(false); mComparator.Cancel(); FileSync.__LogError(this, "Copy file failed '" + file.RelativePath + "'", e); } mFileRunningCount++; mFilesTotalSizeRunning += file.FileSize; }
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); }
public bool DoIncrementalBackup(VolumeSnapshot currentSnapshot, VolumeSnapshot mostRecentSnapshot, VolumeSource source, BaseArchive archive, out bool noChangesRequired) { noChangesRequired = false; mSource = source; mArchive = archive; // see if anything's changed from the last one currentSnapshot.Root.Revision = mostRecentSnapshot.Root.Revision; if (mComparator.CompareSnapshots(mostRecentSnapshot, currentSnapshot, true)) { FileSync.__Log(this, "Incremental comparison complete, changes detected"); FileSync.__Log(this, "Total file count " + mComparator.Stats.FileCount); FileSync.__Log(this, "Total file size " + mComparator.Stats.TotalFileSize); FileSync.__Log(this, "New files " + mComparator.Stats.FilesCreated); FileSync.__Log(this, "Removed files " + mComparator.Stats.FilesRemoved); FileSync.__Log(this, "Changed files " + mComparator.Stats.FilesChanged); FileSync.__Log(this, "New directories " + mComparator.Stats.DirectoriesCreated); FileSync.__Log(this, "Removed directories " + mComparator.Stats.DirectoriesRemoved); FileSync.__Log(this, "Files unchanged " + mComparator.Stats.FilesTheSame); FileSync.__Log(this, "Directories unchanged " + mComparator.Stats.DirectoriesTheSame); mFileTotalCount = mComparator.Stats.FileCount; mFilesTotalSize = mComparator.Stats.TotalFileSize; mFileRunningCount = 0; mFilesTotalSizeRunning = 0; mComparator.CompareSnapshots(mostRecentSnapshot, currentSnapshot, false); return(!mOperation.Cancelled); } else { FileSync.__Log(this, "Incremental comparison complete, no changes detected"); noChangesRequired = true; return(true); } }
public void MergeSnapshotRevisionsByTimeLimit(VolumeSnapshotDatabase database, VolumeSource source, BaseArchive archive, TimeSpan timePeriodToKeep) { // only keep revisions within a certain time period (e.g. last 6 months) List <VolumeSnapshotRevision> revisionHistory = database.GetRevisionHistory(); int numRevisionsToRemove = 0; DateTime cutOffDate = DateTime.Now - timePeriodToKeep; foreach (VolumeSnapshotRevision revision in revisionHistory) { if (revision.CreationTime >= cutOffDate) { break; } else { numRevisionsToRemove++; } } if (numRevisionsToRemove > 0) { FileSync.__Log(this, "Merge will remove " + numRevisionsToRemove + " revisions"); MergeSnapshotRevisions(database, source, archive, numRevisionsToRemove); } else { FileSync.__Log(this, "Merge will not remove any revisions"); } }
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; } }
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 void MergeSnapshotRevisionsByLimitedRevisionCount(VolumeSnapshotDatabase database, VolumeSource source, BaseArchive archive, int maxRevisions) { // only keep a specific number of revisions List <VolumeSnapshotRevision> revisionHistory = database.GetRevisionHistory(); int numRevisionsToRemove = 0; if (revisionHistory.Count > maxRevisions) { numRevisionsToRemove = revisionHistory.Count - maxRevisions; } if (numRevisionsToRemove > 0) { FileSync.__Log(this, "Merge will remove " + numRevisionsToRemove + " revisions"); MergeSnapshotRevisions(database, source, archive, numRevisionsToRemove); } else { FileSync.__Log(this, "Merge will not remove any revisions"); } }
private VolumeSnapshotDirectory(VolumeSnapshot snapshot, VolumeSource source, string relativePath) { mSnapshot = snapshot; mRelativePath = relativePath; mName = mRelativePath.Length <= 1 ? "" : PWLib.Platform.Windows.Path.GetLeafName(relativePath); mLastModified = source.GetLastWriteTimeUtc(relativePath); // PWLib.Platform.Windows.Directory.GetLastWriteTimeUtc( rootDir ); foreach (string filename in source.GetRelativePathFiles(relativePath) /* PWLib.Platform.Windows.Directory.GetFiles( rootDir ) */) { try { VolumeSnapshotFile fileEntry = VolumeSnapshotFile.BuildFromSource(mSnapshot, source, filename); mFiles.Add(fileEntry); } catch (System.Exception e) { FileSync.__LogError(this, "VolumeSnapshotDirectory.BuildFromFileSystem failed on file '" + filename + "'", e); } } foreach (string subDir in source.GetRelativePathDirectories(relativePath)) { try { if (!IsIgnoredDirectoryName(PWLib.Platform.Windows.Path.GetLeafName(subDir))) { VolumeSnapshotDirectory subDirEntry = new VolumeSnapshotDirectory(mSnapshot, source, subDir); mDirectories.Add(subDirEntry); } } catch (System.Exception e) { FileSync.__LogError(this, "VolumeSnapshotDirectory.BuildFromFileSystem failed on directory '" + subDir + "'", e); } } }
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); }