public TreeNodeTri(TreeTraverser.FileEntry fileEntry, ImageList imageList, HashSet <string> ignoredFiles, HashSet <string> ignoredFolders, TreeView parentTree, CheckedState defaultState = CheckedState.Checked) : base(fileEntry.Filename) { this.imageList = imageList; if (ignoredFiles.Contains(fileEntry.FullPath)) { this.State = CheckedState.Unchecked; } else { this.State = defaultState; } this.StateImageIndex = (int)this.State; this.ignoredFiles = ignoredFiles; this.ignoredFolders = ignoredFolders; this.parentTree = parentTree; this.fileEntry = fileEntry; if (!imageList.Images.ContainsKey(fileEntry.Extension)) { Icon icon = Icon.ExtractAssociatedIcon(fileEntry.FullPath); imageList.Images.Add(fileEntry.Extension, icon); } this.ImageKey = fileEntry.Extension; this.SelectedImageKey = fileEntry.Extension; }
private void addFile(int folderId, TreeTraverser.FileEntry file) { string fileMD5 = file.GetMD5((percent) => { this.reportBackupAction(new BackupActionItem(null, file.RelPath, BackupActionEntity.File, BackupActionOperation.Hash, null, percent)); return(!this.Cancelled); }); if (this.Cancelled) { return; } foreach (BackendBase backend in this.backends) { // Search for alternates if (this.createFromAlternate(file, fileMD5, false, backend)) { continue; } this.reportBackupAction(new BackupActionItem(null, file.RelPath, BackupActionEntity.File, BackupActionOperation.Add, backend.Name)); backend.CreateFile(file.RelPath, file.FullPath, file.LastModified, fileMD5, file.Attributes); this.Logger.Info("{0}: Added file: {1}", backend.Name, file.RelPath); } this.fileDatabase.AddFile(folderId, file.RelPath, file.LastModified, fileMD5); }
private bool createFromAlternate(TreeTraverser.FileEntry file, string fileMD5, bool update, BackendBase backend) { // if update is true, we're updating the dest file. otherwise we're adding it // Return true if we made use of an alternate, or false if we did nothing string logAction = update ? "Updated" : "Added"; FileDatabase.FileRecord[] alternates = this.fileDatabase.SearchForAlternates(fileMD5).ToArray(); if (alternates.Length == 0) { return(false); } // Now, each alternate may not in fact exist on the backend, or may be changed. We can't assume stuff like this // So, loop through them all, and attempt to use it. Bail after the first successful one bool foundGoodAlternate = false; foreach (FileDatabase.FileRecord alternate in alternates) { // First, does it even exist on the backend? Skip to the next one if not if (!backend.TestFile(alternate.Path, file.LastModified, fileMD5)) { continue; } // Next: Is is a copy or a move? if (this.treeTraverser.FileExists(alternate.Path)) { // It's a copy this.reportBackupAction(new BackupActionItem(alternate.Path, file.RelPath, BackupActionEntity.File, BackupActionOperation.Copy, backend.Name)); if (backend.CreateFromAlternateCopy(file.RelPath, alternate.Path)) { this.Logger.Info("{0}: {1} file: {2} from alternate {3} (copy)", backend.Name, logAction, file.RelPath, alternate.Path); } else { backend.CreateFile(file.RelPath, file.FullPath, file.LastModified, fileMD5, file.Attributes); this.Logger.Info("{0}: {1} file: {2} (backend refused alternate {3})", backend.Name, logAction, file.RelPath, alternate.Path); } } else { // It's a move this.reportBackupAction(new BackupActionItem(alternate.Path, file.RelPath, BackupActionEntity.File, BackupActionOperation.Move, backend.Name)); backend.CreateFromAlternateMove(file.RelPath, alternate.Path); this.Logger.Info("{0}: {1} file: {2} from alternate {3} (move)", backend.Name, logAction, file.RelPath, alternate.Path); this.fileDatabase.DeleteFile(alternate.Id); } // We're all golden foundGoodAlternate = true; break; } return(foundGoodAlternate); }
private void updatefile(int fileId, TreeTraverser.FileEntry file, string remoteMD5) { this.reportBackupAction(new BackupActionItem(null, file.RelPath, BackupActionEntity.File, BackupActionOperation.Hash)); // Only copy if the file has actually changed string fileMD5 = file.GetMD5((percent) => { this.reportBackupAction(new BackupActionItem(null, file.RelPath, BackupActionEntity.File, BackupActionOperation.Hash, null, percent)); return(!this.Cancelled); }); if (this.Cancelled) { return; } if (remoteMD5 == fileMD5) { foreach (BackendBase backend in this.backends) { backend.TouchFile(file.RelPath, file.LastModified); } //this.Logger.Info("File mtime changed, but file unchanged. Touching: {0}", file); return; } foreach (BackendBase backend in this.backends) { if (this.createFromAlternate(file, fileMD5, true, backend)) { continue; } this.reportBackupAction(new BackupActionItem(null, file.RelPath, BackupActionEntity.File, BackupActionOperation.Update, backend.Name)); if (backend.CreateFile(file.RelPath, file.FullPath, file.LastModified, fileMD5, file.Attributes)) { this.Logger.Info("{0}: Updated file: {1}", backend.Name, file.RelPath); } else { this.Logger.Info("{0}: Skipped file {1} (mtime changed but file up-to-date)", backend.Name, file.RelPath); } } // But update the last modified time either way this.fileDatabase.UpdateFile(fileId, file.LastModified, fileMD5); }
private void testFile(TreeTraverser.FileEntry file, string fileMD5) { foreach (BackendBase backend in this.backends) { if (!backend.TestFile(file.RelPath, file.LastModified, fileMD5)) { // Aha! File's gone missing from the backend this.reportBackupAction(new BackupActionItem(null, file.RelPath, BackupActionEntity.File, BackupActionOperation.Add, backend.Name)); if (!this.createFromAlternate(file, fileMD5, true, backend)) { if (backend.CreateFile(file.RelPath, file.FullPath, file.LastModified, fileMD5, file.Attributes)) { this.Logger.Info("{0}: File on backend missing or modified, so re-creating: {1}", backend.Name, file.RelPath); } } } else { this.reportBackupAction(new BackupActionItem(null, file.RelPath, BackupActionEntity.File, BackupActionOperation.Nothing)); } } }
public void Backup() { this.Cancelled = false; this.WarningOccurred = false; FileDatabase.FolderStatus folderStatus; int newFolderLevel = -1; int prevLevel = -1; int curFolderId = -1; IEnumerable <TreeTraverser.FileEntry> files; FileDatabase.FileStatus fileStatus; // Do all the additions, then go through and do the deletions separately // This gives us a change to do renames, and makes sure that we empty folders before deleting them foreach (TreeTraverser.FolderEntry folder in this.treeTraverser.ListFolders()) { if (this.Cancelled) { break; } // files might not get assigned, so assign it now files = new TreeTraverser.FileEntry[0]; try { if (newFolderLevel >= 0 && folder.Level > newFolderLevel) { // Just automatically add it, as a parent somewhere is new curFolderId = this.addFolder(folder); } else { newFolderLevel = -1; folderStatus = this.fileDatabase.InspectFolder(folder.RelPath); switch (folderStatus.FolderModStatus) { case FileDatabase.FolderModStatus.New: newFolderLevel = folder.Level; curFolderId = this.addFolder(folder); break; case FileDatabase.FolderModStatus.Unmodified: curFolderId = folderStatus.Id; this.checkFolder(folder); break; } } // Check for files in this folder files = folder.GetFiles(); } catch (BackupOperationException e) { this.handleOperationException(e); } foreach (TreeTraverser.FileEntry file in files) { if (this.Cancelled) { break; } try { fileStatus = this.fileDatabase.InspectFile(curFolderId, file.RelPath, file.LastModified); switch (fileStatus.FileModStatus) { case FileDatabase.FileModStatus.New: this.addFile(curFolderId, file); break; case FileDatabase.FileModStatus.Newer: case FileDatabase.FileModStatus.Older: this.updatefile(fileStatus.Id, file, fileStatus.MD5); break; case FileDatabase.FileModStatus.Unmodified: // We don't think anything's changed... but make sure the file exists on the backends this.testFile(file, fileStatus.MD5); break; } } catch (BackupOperationException e) { this.handleOperationException(e); } } prevLevel = folder.Level; } if (this.Cancelled) { return; } // Now we look for file deletions IEnumerable <FileDatabase.FileRecord> recordedFiles = this.fileDatabase.RecordedFiles(); foreach (FileDatabase.FileRecord fileToCheck in recordedFiles) { if (this.Cancelled) { break; } if (!this.treeTraverser.FileExists(fileToCheck.Path)) { this.deleteFile(fileToCheck.Id, fileToCheck.Path); } } if (this.Cancelled) { return; } // And finally folder deletions foreach (FileDatabase.FolderRecord folderToCheck in this.fileDatabase.RecordedFolders()) { if (this.Cancelled) { break; } try { if (!this.treeTraverser.FolderExists(folderToCheck.Path)) { this.deleteFolder(folderToCheck.Id, folderToCheck.Path); } } catch (BackupOperationException e) { this.handleOperationException(e); } } }
public TreeNodeTri(TreeTraverser.FileEntry fileEntry, ImageList imageList, HashSet<string> ignoredFiles, HashSet<string> ignoredFolders, TreeView parentTree, CheckedState defaultState=CheckedState.Checked) : base(fileEntry.Filename) { this.imageList = imageList; if (ignoredFiles.Contains(fileEntry.FullPath)) this.State = CheckedState.Unchecked; else this.State = defaultState; this.StateImageIndex = (int)this.State; this.ignoredFiles = ignoredFiles; this.ignoredFolders = ignoredFolders; this.parentTree = parentTree; this.fileEntry = fileEntry; if (!imageList.Images.ContainsKey(fileEntry.Extension)) { Icon icon = Icon.ExtractAssociatedIcon(fileEntry.FullPath); imageList.Images.Add(fileEntry.Extension, icon); } this.ImageKey = fileEntry.Extension; this.SelectedImageKey = fileEntry.Extension; }
public void Backup() { this.Cancelled = false; this.WarningOccurred = false; FileDatabase.FolderStatus folderStatus; int newFolderLevel = -1; int prevLevel = -1; int curFolderId = -1; IEnumerable<TreeTraverser.FileEntry> files; FileDatabase.FileStatus fileStatus; // Do all the additions, then go through and do the deletions separately // This gives us a change to do renames, and makes sure that we empty folders before deleting them foreach (TreeTraverser.FolderEntry folder in this.treeTraverser.ListFolders()) { if (this.Cancelled) break; // files might not get assigned, so assign it now files = new TreeTraverser.FileEntry[0]; try { if (newFolderLevel >= 0 && folder.Level > newFolderLevel) { // Just automatically add it, as a parent somewhere is new curFolderId = this.addFolder(folder); } else { newFolderLevel = -1; folderStatus = this.fileDatabase.InspectFolder(folder.RelPath); switch (folderStatus.FolderModStatus) { case FileDatabase.FolderModStatus.New: newFolderLevel = folder.Level; curFolderId = this.addFolder(folder); break; case FileDatabase.FolderModStatus.Unmodified: curFolderId = folderStatus.Id; this.checkFolder(folder); break; } } // Check for files in this folder files = folder.GetFiles(); } catch (BackupOperationException e) { this.handleOperationException(e); } foreach (TreeTraverser.FileEntry file in files) { if (this.Cancelled) break; try { fileStatus = this.fileDatabase.InspectFile(curFolderId, file.RelPath, file.LastModified); switch (fileStatus.FileModStatus) { case FileDatabase.FileModStatus.New: this.addFile(curFolderId, file); break; case FileDatabase.FileModStatus.Newer: case FileDatabase.FileModStatus.Older: this.updatefile(fileStatus.Id, file, fileStatus.MD5); break; case FileDatabase.FileModStatus.Unmodified: // We don't think anything's changed... but make sure the file exists on the backends this.testFile(file, fileStatus.MD5); break; } } catch (BackupOperationException e) { this.handleOperationException(e); } } prevLevel = folder.Level; } if (this.Cancelled) return; // Now we look for file deletions IEnumerable<FileDatabase.FileRecord> recordedFiles = this.fileDatabase.RecordedFiles(); foreach (FileDatabase.FileRecord fileToCheck in recordedFiles) { if (this.Cancelled) break; if (!this.treeTraverser.FileExists(fileToCheck.Path)) { this.deleteFile(fileToCheck.Id, fileToCheck.Path); } } if (this.Cancelled) return; // And finally folder deletions foreach (FileDatabase.FolderRecord folderToCheck in this.fileDatabase.RecordedFolders()) { if (this.Cancelled) break; try { if (!this.treeTraverser.FolderExists(folderToCheck.Path)) { this.deleteFolder(folderToCheck.Id, folderToCheck.Path); } } catch (BackupOperationException e) { this.handleOperationException(e); } } }