/// <summary> /// Deletes files greater than the given age /// days and of the given file specifications. /// </summary> public bool CleanupFiles() { // Return if cleanup is disabled. if ( !moProfile.bValue("-CleanupFiles", true) ) { this.LogIt(""); this.LogIt("Cleanup files is disabled."); return true; } // Return if backup is enabled and it was stopped. if ( moProfile.bValue("-BackupFiles", true) && this.bMainLoopStopped ) return true; else this.bMainLoopStopped = false; bool lbCleanupFiles = true; this.LogIt(""); this.LogIt("File cleanup started ..."); // Write the deleted file list header to disk. string lsDeletedFileListOutputPathFile = moProfile.sRelativeToProfilePathFile(this.sDeletedFileListOutputPathFile); if ( !File.Exists(lsDeletedFileListOutputPathFile) ) { // Get the column header array. string[] lsColumnHeaderArray = moProfile.sValue("-DeletedFileListOutputColumnHeaderArray", "Deleted File Time,File Size,Former File Location").Split(','); StreamWriter loStreamWriter = null; try { loStreamWriter = new StreamWriter(lsDeletedFileListOutputPathFile, false); // First, output the file header. loStreamWriter.WriteLine(string.Format(moProfile.sValue("-DeletedFileListOutputHeader" , "{0, -10:MM-dd-yyyy} File Cleanup List"), DateTime.Today)); loStreamWriter.WriteLine(); // Next output the column headers properly formatted to match the forthcoming data rows. loStreamWriter.WriteLine(string.Format( moProfile.sValue("-DeletedFileListOutputColumnFormat", "{0, -22:MM-dd-yyyy hh:mm:ss tt} {1, 13:#,#} {2}") , lsColumnHeaderArray[0], lsColumnHeaderArray[1], lsColumnHeaderArray[2])); loStreamWriter.WriteLine(); } catch (Exception ex) { this.ShowError(string.Format("File Write Failure: \"{0}\"\r\n" , lsDeletedFileListOutputPathFile) + ex.Message , "Failed Writing File" ); } finally { if ( null != loStreamWriter ) loStreamWriter.Close(); } } try { // This is used elsewhere to warn users if the software // has not been properly configured for file cleanups. this.mbHasNoDeletionGroups = true; if ( !moProfile.ContainsKey("-CleanupSet") ) { // Create the default file cleanup sets. // Get the primary backup set (ie. the 1st). tvProfile loBackupSet1Profile = new tvProfile(moProfile.sValue("-BackupSet", "(not set)")); string lsBackupOutputPathFileBase = this.sBackupOutputPathFileBase(loBackupSet1Profile); string lsBackupOutputPath = Path.GetDirectoryName(lsBackupOutputPathFileBase); string lsBackupOutputFilenameNoExt = Path.GetFileNameWithoutExtension(lsBackupOutputPathFileBase); // Initially set the cleanup of primary backups to "no cleanup" (ie. 1000 years). // The deletion limit prevents old file removal without new files to replace them. moProfile.Add("-CleanupSet", string.Format(@" -AgeDays=365000 -FilesToDelete={0}*{1} " , Path.Combine(lsBackupOutputPath, lsBackupOutputFilenameNoExt) , Path.GetExtension(lsBackupOutputPathFileBase) )); // Set the cleanup of temporary backup files to 0 days. // This is necessary to cleanup after killed processes. moProfile.Add("-CleanupSet", string.Format(@" -AgeDays=0 -FilesToDelete={0}.tmp* " , Path.Combine(this.sArchivePath(), "*" + Path.GetExtension(lsBackupOutputPathFileBase)) )); // Set the cleanup of file lists and backup / cleanup log files to 30 days. moProfile.Add("-CleanupSet", string.Format(@" -AgeDays=30 -FilesToDelete={0} -FilesToDelete={1} " , Path.Combine(Path.GetDirectoryName(this.sZipToolFileListPathFileBase) , "*" + Path.GetExtension(this.sZipToolFileListPathFileBase)) , Path.Combine(Path.GetDirectoryName(this.sLogPathFileBase) , "*" + Path.GetExtension(this.sLogPathFileBase)) )); } // Get all cleanup sets. tvProfile loCleanupSetsProfile = moProfile.oOneKeyProfile("-CleanupSet"); foreach (DictionaryEntry loEntry in loCleanupSetsProfile) { System.Windows.Forms.Application.DoEvents(); if ( this.bMainLoopStopped ) break; // Convert the current cleanup set from a command-line string to a profile oject. tvProfile loCurrentCleanupSet = new tvProfile(loEntry.Value.ToString()); // The default "LastWriteTime" is the last modified datetime. FileDateTimeTypes leFileDateTimeType; switch (loCurrentCleanupSet.sValue("-DeletedFileListDateTimeType", "LastWriteTime")) { case "CreationTime": leFileDateTimeType = FileDateTimeTypes.CreationTime; break; case "LastAccessTime": leFileDateTimeType = FileDateTimeTypes.LastAccessTime; break; default: leFileDateTimeType = FileDateTimeTypes.LastWriteTime; break; } // Use 1000 years as the default file age. int liAgeDays = loCurrentCleanupSet.iValue("-AgeDays", 365000); liAgeDays = 0 == liAgeDays ? -1 : liAgeDays; // "0" means "delete everything." -1 makes that happen. DateTime ldtOlderThan = DateTime.Now.AddDays(-liAgeDays); // Get the list of path\file specifications to delete. tvProfile loFilesToDeleteProfile = loCurrentCleanupSet.oOneKeyProfile("-FilesToDelete"); foreach (DictionaryEntry loPathFilesEntry in loFilesToDeleteProfile) { System.Windows.Forms.Application.DoEvents(); if ( this.bMainLoopStopped ) break; // Being here means there is at least one set of files to delete. this.mbHasNoDeletionGroups = false; if ( lbCleanupFiles ) lbCleanupFiles = this.CleanupPathFileSpec( moProfile.sRelativeToProfilePathFile(loPathFilesEntry.Value.ToString()) , ldtOlderThan , leFileDateTimeType , loCurrentCleanupSet ); } } if ( lbCleanupFiles ) this.DisplayDeletedFileList(); } catch (Exception ex) { this.ShowError(ex.Message, "Unanticipated Error"); lbCleanupFiles = false; } if ( this.bMainLoopStopped ) { this.LogIt("Cleanup process stopped."); this.bMainLoopStopped = false; lbCleanupFiles = false; } else { if ( lbCleanupFiles ) this.LogIt("File cleanup finished."); else this.LogIt("File cleanup failed."); } return lbCleanupFiles; }
/// <summary> /// Backup files of the given file specifications and run /// the backup scripts to copy the backup around as needed. /// </summary> public bool BackupFiles() { // Return if backup is disabled. if ( !moProfile.bValue("-BackupFiles", true) ) { this.LogIt("Backup files is disabled."); return true; } // Return if cleanup is enabled and it was stopped. if ( moProfile.bValue("-CleanupFiles", true) && this.bMainLoopStopped ) return true; else this.bMainLoopStopped = false; bool lbBackupFiles = false; int liBackupBeginScriptErrors = 0; // The error count returned by the "backup begin" script. int liBackupDoneScriptFileCopyFailures = 0; // The copy failures count returned by the "backup done" script. int liCurrentBackupDevicesBitField = 0; // The current backup devices returned by the "backup done" script. // Get the embedded zip compression tool from the EXE. tvFetchResource.ToDisk(Application.ResourceAssembly.GetName().Name, mcsZipToolExeFilename, null); tvFetchResource.ToDisk(Application.ResourceAssembly.GetName().Name, mcsZipToolDllFilename, null); // Get all backup sets. tvProfile loBackupSetsProfile = moProfile.oOneKeyProfile("-BackupSet"); miBackupSets = loBackupSetsProfile.Count; miBackupSetsRun = 0; miBackupSetsGood = 0; // Release the lock on the profile file // so that it can be backed up as well. moProfile.bEnableFileLock = false; try { lbBackupFiles = true; // Run the "backup begin" script and return any errors. if ( moProfile.bValue("-BackupBeginScriptEnabled", true) ) liBackupBeginScriptErrors = this.iBackupBeginScriptErrors(); else this.LogIt("The \"backup begin\" script is disabled."); string lsZipToolFileListPathFile = moProfile.sRelativeToProfilePathFile(this.ZipToolFileListPathFile); string lsBackupPathFiles1 = null; // The first file specification in the set (for logging). int liFileCount = 0; // The number of file specifications in the current set. foreach (DictionaryEntry loEntry in loBackupSetsProfile) { System.Windows.Forms.Application.DoEvents(); if ( this.bMainLoopStopped ) break; string lsProcessPathFile = moProfile.sRelativeToProfilePathFile(moProfile.sValue("-ZipToolEXE", mcsZipToolExeFilename)); // Increment the backup set counter. miBackupSetsRun++; // Convert the current backup set from a command-line string to a profile oject. moCurrentBackupSet = new tvProfile(loEntry.Value.ToString()); // Get the list of folders to backup within the current backup set. tvProfile loFolderToBackupProfile = moCurrentBackupSet.oOneKeyProfile( "-FolderToBackup"); StreamWriter loBackupFileListStreamWriter = null; liFileCount = 0; try { // Create the backup file list file. loBackupFileListStreamWriter = new StreamWriter(moProfile.sRelativeToProfilePathFile( lsZipToolFileListPathFile), false); // Write the list of files to compress. foreach (DictionaryEntry loFolderToBackup in loFolderToBackupProfile) { System.Windows.Forms.Application.DoEvents(); if ( this.bMainLoopStopped ) break; string lsFolderToBackup = loFolderToBackup.Value.ToString().Trim(); string lsBackupPathFiles = null; if ( Directory.Exists(lsFolderToBackup) ) lsBackupPathFiles = Path.Combine(lsFolderToBackup, this.sBackupFileSpec()); else lsBackupPathFiles = lsFolderToBackup; // If the given "lsFolderToBackup" is not actually a folder, assume it's a single file (or a file mask). if ( 1 == ++liFileCount ) { if ( moProfile.ContainsKey("-ActivateAlreadyRunningInstance") ) { // Backup just the backup profile file as well (to avoid file contention problems with the main instance). loBackupFileListStreamWriter.WriteLine(this.sExeRelativePath(lsProcessPathFile, moProfile.sLoadedPathFile)); } else { // Backup the backup as well. loBackupFileListStreamWriter.WriteLine(this.sExeRelativePath(lsProcessPathFile, Path.GetDirectoryName(moProfile.sLoadedPathFile))); // Also make an extra - easily accessible - backup of just the profile file. lsBackupPathFiles1 = moProfile.sBackupPathFile; // Discard the pathfile name. } // Save the first pathfile specification (ie. folder) for later reference. lsBackupPathFiles1 = lsBackupPathFiles; } loBackupFileListStreamWriter.WriteLine(this.sExeRelativePath(lsProcessPathFile, lsBackupPathFiles)); } } catch (Exception ex) { lbBackupFiles = false; if ( null != this.oUI ) this.oUI.bBackupRunning = false; this.ShowError(string.Format("File Write Failure: \"{0}\"\r\n" , lsZipToolFileListPathFile) + ex.Message , "Failed Writing File" ); } finally { if ( null != loBackupFileListStreamWriter ) loBackupFileListStreamWriter.Close(); } // The backup output path file will be dated and unique. msCurrentBackupOutputPathFile = this.sBackupOutputPathFile(); string lsProcessArgs = moProfile.sValue("-ZipToolEXEargs" , "a -ssw \"{BackupOutputPathFile}\" @\"{BackupPathFiles}\" -w\"{BackupOutputPath}\" ") + " " + moProfile.sValue("-ZipToolEXEargsMore", ""); lsProcessArgs = lsProcessArgs.Replace("{BackupPathFiles}", lsZipToolFileListPathFile); lsProcessArgs = lsProcessArgs.Replace("{BackupOutputPath}", Path.GetDirectoryName(msCurrentBackupOutputPathFile)); lsProcessArgs = lsProcessArgs.Replace("{BackupOutputPathFile}", msCurrentBackupOutputPathFile); string lsArchivePath = Path.GetDirectoryName(msCurrentBackupOutputPathFile); if ( !Directory.Exists(lsArchivePath) ) try { Directory.CreateDirectory(lsArchivePath); } catch (Exception ex) { lbBackupFiles = false; if ( null != this.oUI ) this.oUI.bBackupRunning = false; this.ShowError( string.Format("Folder: \"{0}\"\r\n", lsArchivePath) + ex.Message , "Error Creating Archive Folder" ); } Process loProcess = new Process(); loProcess.ErrorDataReceived += new DataReceivedEventHandler(this.BackupProcessOutputHandler); loProcess.OutputDataReceived += new DataReceivedEventHandler(this.BackupProcessOutputHandler); loProcess.StartInfo.FileName = lsProcessPathFile; loProcess.StartInfo.Arguments = lsProcessArgs; loProcess.StartInfo.WorkingDirectory = "\\"; loProcess.StartInfo.UseShellExecute = false; loProcess.StartInfo.RedirectStandardError = true; loProcess.StartInfo.RedirectStandardInput = true; loProcess.StartInfo.RedirectStandardOutput = true; loProcess.StartInfo.CreateNoWindow = true; string lsLastRunCmd = lsProcessPathFile + " " + lsProcessArgs; string lsFileAsStream = string.Format(@" cd\ @prompt $ {0} @echo. cd {1} @pause " , lsLastRunCmd , Path.GetDirectoryName(moProfile.sExePathFile) ); moProfile.Remove("-PreviousBackupOk"); moProfile.Save(); // This lets the user see what was run (or rerun it). string lsLastRunFile = moProfile.sValue("-ZipToolLastRunCmdPathFile", "Run Last Backup.cmd"); StreamWriter loLastRunFileStreamWriter = null; try { loLastRunFileStreamWriter = new StreamWriter(moProfile.sRelativeToProfilePathFile(lsLastRunFile), false); loLastRunFileStreamWriter.Write(lsFileAsStream); } catch (Exception ex) { lbBackupFiles = false; if ( null != this.oUI ) this.oUI.bBackupRunning = false; this.ShowError(string.Format("File Write Failure: \"{0}\"\r\n" , lsLastRunFile) + ex.Message , "Failed Writing File" ); } finally { if ( null != loLastRunFileStreamWriter ) loLastRunFileStreamWriter.Close(); } string lsFilesSuffix = liFileCount <= 1 ? "" : string.Format(" + {0} other file specification" + (1 == (liFileCount - 1) ? "" : "s") , liFileCount - 1); this.LogIt(""); this.LogIt("Backup started ..."); this.LogIt(""); this.LogIt(string.Format("Backup: \"{0}\"{1}", lsBackupPathFiles1, lsFilesSuffix)); this.LogIt(""); this.LogIt("Backup command: " + lsLastRunCmd); System.Windows.Forms.Application.DoEvents(); loProcess.Start(); // Start output to console also. if ( loProcess.StartInfo.RedirectStandardError ) loProcess.BeginErrorReadLine(); if ( loProcess.StartInfo.RedirectStandardOutput ) loProcess.BeginOutputReadLine(); // Wait for the backup process to finish. while ( !this.bMainLoopStopped && !loProcess.HasExited ) { System.Windows.Forms.Application.DoEvents(); System.Threading.Thread.Sleep(moProfile.iValue("-MainLoopSleepMS", 100)); } // Do final wait then call "WaitForExit()" to flush the output steams. if ( !this.bMainLoopStopped && loProcess.WaitForExit(1000 * moProfile.iValue("-KillProcessOrderlyWaitSecs", 30)) ) loProcess.WaitForExit(); // Stop output to console. if ( loProcess.StartInfo.RedirectStandardError ) loProcess.CancelErrorRead(); if ( loProcess.StartInfo.RedirectStandardOutput ) loProcess.CancelOutputRead(); // If a stop request came through, kill the backup process. if ( this.bMainLoopStopped && !this.bKillProcess(loProcess) ) this.ShowError("The backup process could not be stopped." , "Backup Failed"); // The backup process finished uninterrupted. if ( !this.bMainLoopStopped ) { if ( 0 != loProcess.ExitCode ) { // The backup process failed. this.LogIt(string.Format("The backup to \"{0}\" failed." , Path.GetFileName(msCurrentBackupOutputPathFile))); // Run the "backup failed" script. if ( moProfile.bValue("-BackupFailedScriptEnabled", true) ) this.BackupFailedScript(); else this.LogIt("The \"backup failed\" script is disabled."); } else { // The backup process finished without error. this.LogIt(string.Format("The backup to \"{0}\" was successful." , Path.GetFileName(msCurrentBackupOutputPathFile))); double ldCompositeResult = 0; // Composite result returned by the "backup done" script. // Run the "backup done" script and return the failed file count with bit field. // The exit code is defined in the script as a combination of two integers: // a bit field of found backup devices and a count of copy failures (99 max). if ( moProfile.bValue("-BackupDoneScriptEnabled", true) ) ldCompositeResult = this.iBackupDoneScriptCopyFailuresWithBitField() / 100.0; else this.LogIt("The \"backup done\" script is disabled."); // The integer part of the composite number is the bit field. // This will be used below after all backup sets are run. We // assume that the bit field remains constant between sets. liCurrentBackupDevicesBitField = (int)ldCompositeResult; // The fractional part (x 100) is the actual number of copy failures. int liCopyFailures = (int)Math.Round(100 * (ldCompositeResult - liCurrentBackupDevicesBitField)); // Add failed files from the current backup set to the total. liBackupDoneScriptFileCopyFailures += liCopyFailures; // Increment how many backup sets have succeeded so far. if ( 0 == liCopyFailures ) miBackupSetsGood++; } } loProcess.Close(); } } catch (Exception ex) { lbBackupFiles = false; if ( null != this.oUI ) this.oUI.bBackupRunning = false; this.ShowError(ex.Message, "Backup Failed"); } if ( lbBackupFiles && !this.bMainLoopStopped ) { this.LogIt(""); // Don't bother with the system tray message // if the background timer is not running. string lsSysTrayMsg = null; if ( moProfile.bValue("-AutoStart", true) ) lsSysTrayMsg = this.sSysTrayMsg; List<char> loMissingBackupDevices = new List<char>(); // Compare the bit field of current backup devices to the bit field of // devices selected by the user to be used by the "backup done" script. if ( moProfile.bValue("-BackupDoneScriptEnabled", true) ) loMissingBackupDevices = this.oMissingBackupDevices(liCurrentBackupDevicesBitField); if ( miBackupSetsGood != miBackupSetsRun || 0 != liBackupBeginScriptErrors || 0 != liBackupDoneScriptFileCopyFailures || 0 != loMissingBackupDevices.Count ) { if ( 0 != loMissingBackupDevices.Count ) moProfile["-PreviousBackupDevicesMissing"] = true; else moProfile["-PreviousBackupDevicesMissing"] = false; this.SetBackupFailed(); lbBackupFiles = false; if ( null != this.oUI ) this.oUI.bBackupRunning = false; this.ShowError("The backup failed. Check the log for errors." + lsSysTrayMsg , "Backup Failed"); } else { moProfile["-PreviousBackupDevicesMissing"] = false; moProfile["-PreviousBackupOk"] = true; moProfile["-PreviousBackupTime"] = DateTime.Now; moProfile.Save(); this.Show("Backup finished successfully." + lsSysTrayMsg , "Backup Finished" , tvMessageBoxButtons.OK , tvMessageBoxIcons.Done , "-CurrentBackupFinished" ); } } if ( this.bMainLoopStopped ) { this.LogIt("Backup process stopped."); this.bMainLoopStopped = false; lbBackupFiles = false; } // Turn on the lock that was turned off when we started. moProfile.bEnableFileLock = true; return lbBackupFiles; }
/// <summary> /// Returns the total number of files to be evaluated for cleanup. /// </summary> /// <returns></returns> public int iCleanupFilesCount() { int liCleanupFilesCount = 0; // Get all cleanup sets. tvProfile loCleanupSetsProfile = moProfile.oOneKeyProfile("-CleanupSet"); try { foreach (DictionaryEntry loEntry in loCleanupSetsProfile) { // Create a profile object from the current cleanup set. tvProfile loCleanupSetProfile = new tvProfile(loEntry.Value.ToString()); // Get all specifications of the files to delete in the current set. tvProfile loFilesToCleanupProfile = loCleanupSetProfile.oOneKeyProfile("-FilesToDelete"); foreach (DictionaryEntry loFileToCleanup in loFilesToCleanupProfile) { try { // Count all files represented by the current file // specifcation and add that number to the total. liCleanupFilesCount += Directory.GetFiles( Path.GetDirectoryName(loFileToCleanup.Value.ToString()) , Path.GetFileName(loFileToCleanup.Value.ToString()) , SearchOption.AllDirectories).Length; } catch {} } } } catch (Exception ex) { this.ShowError(ex.Message, "Cleanup Failed"); } return liCleanupFilesCount; }
/// <summary> /// Returns the total number of files to be backed up. /// </summary> /// <returns></returns> public int iBackupFilesCount() { int liBackupFilesCount = 0; // Get all backup sets. tvProfile loBackupSetsProfile = moProfile.oOneKeyProfile("-BackupSet"); try { foreach (DictionaryEntry loEntry in loBackupSetsProfile) { // Create a profile object from the current backup set. tvProfile loBackupSetProfile = new tvProfile(loEntry.Value.ToString()); // Get all specifications of the files to backup in the current set. tvProfile loFolderToBackupProfile = loBackupSetProfile.oOneKeyProfile("-FolderToBackup"); foreach (DictionaryEntry loFolderToBackup in loFolderToBackupProfile) { string lsFolderToBackup = loFolderToBackup.Value.ToString().Trim(); string lsBackupFiles = null; if ( Directory.Exists(lsFolderToBackup) ) { lsBackupFiles = this.sBackupFileSpec(loBackupSetProfile); } else { lsFolderToBackup = Path.GetDirectoryName(lsFolderToBackup); lsBackupFiles = Path.GetFileName(lsFolderToBackup); // If the given "lsFolderToBackup" is not actually a folder, // assume it's a single file (or a file mask). } // Count all files represented by the current file // specifcation and add that number to the total. liBackupFilesCount += Directory.GetFiles( lsFolderToBackup , lsBackupFiles , SearchOption.AllDirectories).Length; } } } catch (Exception ex) { this.ShowError(ex.Message, "Backup Failed"); } return liBackupFilesCount; }
private void btnSetupStep1_Click(object sender, RoutedEventArgs e) { // Currently the setup UI only handles 1 backup set (ie. the primary backup). tvProfile loBackupSet1Profile = new tvProfile(moProfile.sValue("-BackupSet", "(not set)")); if ( loBackupSet1Profile.oOneKeyProfile("-FolderToBackup").Count > 1 ) { this.ShowWarning(string.Format("The profile file (\"{0}\") has been edited manually to contain more than one folder to backup. Please remove the excess or continue to edit the profile by hand." , Path.GetFileName(moProfile.sLoadedPathFile)), "Can't Change Folder to Backup"); return; } System.Windows.Forms.FolderBrowserDialog loOpenDialog = new System.Windows.Forms.FolderBrowserDialog(); loOpenDialog.RootFolder = Environment.SpecialFolder.Desktop; loOpenDialog.SelectedPath = this.FolderToBackup.Text; System.Windows.Forms.DialogResult leDialogResult = System.Windows.Forms.DialogResult.None; if ( !this.bNoPrompts ) leDialogResult = loOpenDialog.ShowDialog(); if ( System.Windows.Forms.DialogResult.OK == leDialogResult ) this.FolderToBackup.Text = loOpenDialog.SelectedPath; }