Esempio n. 1
0
        /// <summary>
        /// Generates the backup completion info file and adds the backup to the backup index.
        /// </summary>
        /// <param name="sourcePath">The path of the backup source directory.</param>
        /// <param name="targetPath">The path of the backup target directory.</param>
        /// <param name="backupName">The name of the backup directory.</param>
        /// <param name="results">The results of the backup.</param>
        /// <returns><c>true</c> if all the operations completed successfully, otherwise <c>false</c>.</returns>
        public bool CompleteBackup(string sourcePath, string targetPath, string backupName, BackupResults results)
        {
            var backupPath = BackupMeta.BackupPath(targetPath, backupName);

            bool success = true;

            BackupCompleteInfo completionInfo = new(DateTime.UtcNow, results.PathsSkipped, results.ManifestComplete);
            var completionInfoFilePath        = BackupMeta.CompleteInfoFilePath(backupPath);

            try {
                BackupCompleteInfoWriter.Write(completionInfoFilePath, completionInfo);
                Logger.Info($"Created backup completion info file \"{completionInfoFilePath}\"");
            }
            catch (BackupCompleteInfoFileIOException e) {
                Logger.Warning(
                    $"Failed to write backup completion info \"{completionInfoFilePath}\": {e.InnerException.Reason}");
                success = false;
            }

            var indexFilePath = BackupMeta.IndexFilePath(targetPath);

            try {
                BackupIndexWriter.AddEntry(indexFilePath, backupName, sourcePath);
                Logger.Info($"Added this backup to backup index");
            }
            catch (BackupIndexFileIOException e) {
                Logger.Warning($"Failed to add backup to backup index \"{indexFilePath}\": {e.InnerException.Reason}");
                success = false;
            }

            return(success);
        }
Esempio n. 2
0
        /// <summary>
        /// Reads the existing backup manifests matching the given source directory.
        /// </summary>
        /// <remarks>
        /// Manifests are matched by comparing their source directories to <paramref name="sourcePath"/>. <br/>
        /// The comparison ignores case, so this only works on Windows. <br/>
        /// The comparison only considers the literal path, e.g. symbolic links are not resolved.
        /// </remarks>
        /// <param name="sourcePath">The source directory to match.</param>
        /// <param name="targetPath">The target directory which is being examined.</param>
        /// <param name="index">The backup index detailing all the existing backups in <paramref name="targetPath"/>.
        /// If <c>null</c>, no manifests are matched.</param>
        /// <returns>A list of the matched backups, in unspecified order.</returns>
        private List <BackupMetadata> ReadPreviousBackups(string sourcePath, string targetPath, BackupIndex?index)
        {
            if (index is null)
            {
                return(new());
            }

            List <BackupMetadata> previousBackups = new();

            foreach (var pair in index.Backups)
            {
                var backupName       = pair.Key;
                var backupSourcePath = pair.Value;

                // Paths are assumed to be already normalised.
                if (Utility.PathEqual(sourcePath, backupSourcePath))
                {
                    var backupPath = Path.Join(targetPath, backupName);

                    var             startInfoFilePath = BackupMeta.StartInfoFilePath(backupPath);
                    BackupStartInfo startInfo;
                    try {
                        startInfo = BackupStartInfoReader.Read(startInfoFilePath);
                    }
                    catch (BackupStartInfoFileException e) {
                        Logger.Warning($"Failed to read metadata of previous backup \"{backupName}\": {e.Message}");
                        continue;
                    }

                    // We could just assume the index file and start info file are consistent, but it might be a
                    // good idea to check just in case something goes particularly wrong.
                    if (!Utility.PathEqual(sourcePath, startInfo.SourcePath))
                    {
                        Logger.Warning(
                            $"Source directory of backup start info in previous backup \"{backupName}\" doesn't match backup index");
                        continue;
                    }

                    var            manifestFilePath = BackupMeta.ManifestFilePath(backupPath);
                    BackupManifest manifest;
                    try {
                        manifest = BackupManifestReader.Read(manifestFilePath);
                    }
                    catch (BackupManifestFileException e) {
                        Logger.Warning($"Failed to read metadata of previous backup \"{backupName}\": {e.Message}");
                        continue;
                    }

                    previousBackups.Add(new(backupName, startInfo, manifest));
                }
            }

            Logger.Info(
                $"{previousBackups.Count} previous backups found in target directory for this source directory");
            return(previousBackups);
        }
Esempio n. 3
0
        /// <summary>
        /// Creates the backup directory, the log file, the start info file, and the manifest writer.
        /// </summary>
        /// <param name="sourcePath">The path of the backup source directory.</param>
        /// <param name="targetPath">The path of the backup target directory.</param>
        /// <returns>A tuple of the backup directory name and manifest writer.</returns>
        /// <exception cref="ApplicationRuntimeError">If the backup directory, start info file, or manifest writer
        /// can't be created.</exception>
        public (string, BackupManifestWriter) InitialiseBackup(string sourcePath, string targetPath)
        {
            string backupName;

            try {
                backupName = BackupMeta.CreateBackupDirectory(targetPath);
            }
            catch (BackupDirectoryCreateException) {
                throw new ApplicationRuntimeError("Failed to create new backup directory");
            }
            Logger.Info($"Backup name: {backupName}");
            var backupPath = BackupMeta.BackupPath(targetPath, backupName);

            Logger.Info($"Created backup directory \"{backupPath}\"");

            var logFilePath = BackupMeta.LogFilePath(backupPath);

            try {
                Logger.FileHandler = new(logFilePath);
                Logger.Info($"Created log file \"{logFilePath}\"");
            }
            catch (LoggingException e) {
                // Not much we can do if we can't create the log file, just ignore and continue.
                Logger.Warning(e.Message);
            }

            var manifestFilePath = BackupMeta.ManifestFilePath(backupPath);
            BackupManifestWriter manifestWriter;

            try {
                manifestWriter = new(manifestFilePath);
            }
            catch (BackupManifestFileIOException e) {
                throw new ApplicationRuntimeError(
                          $"Failed to create backup manifest file \"{manifestFilePath}\": {e.InnerException.Reason}");
            }
            Logger.Info($"Created backup manifest file \"{manifestFilePath}\"");

            BackupStartInfo startInfo         = new(sourcePath, DateTime.UtcNow);
            var             startInfoFilePath = BackupMeta.StartInfoFilePath(backupPath);

            try {
                BackupStartInfoWriter.Write(startInfoFilePath, startInfo);
            }
            catch (BackupStartInfoFileIOException e) {
                throw new ApplicationRuntimeError(
                          $"Failed to write backup start info file \"{startInfoFilePath}\": {e.InnerException.Reason}");
            }
            Logger.Info($"Created backup start info file \"{startInfoFilePath}\"");

            return(backupName, manifestWriter);
        }
 private BackupService(string sourcePath, IReadOnlyList <string> excludePaths, BackupSum previousBackupSum,
                       string backupPath, BackupManifestWriter manifestWriter, Logger logger)
 {
     SourcePath = sourcePath;
     // Trim trailing directory separator for efficient matching later.
     ExcludePaths      = excludePaths.Select(p => Utility.RemoveTrailingDirSep(p)).ToList();
     PreviousBackupSum = previousBackupSum;
     BackupPath        = backupPath;
     BackupDataPath    = BackupMeta.BackupDataPath(backupPath);
     ManifestWriter    = manifestWriter;
     Logger            = logger;
     Results           = new(false, true, 0, 0, 0, 0);
 }
Esempio n. 5
0
        /// <summary>
        /// Runs the backup.
        /// </summary>
        /// <param name="config">The configuration of this backup.</param>
        /// <param name="previousBackupSum">Sum of the existing backup data for this source directory.</param>
        /// <param name="backupName">The name of the new backup directory.</param>
        /// <param name="manifestWriter">Writes the backup manifest. Must be in a newly-constructed state.</param>
        /// <returns>Results of the backup.</returns>
        /// <exception cref="ApplicationRuntimeError">If the backup fails.</exception>
        private BackupResults DoBackup(AppConfig config, BackupSum previousBackupSum, string backupName,
                                       BackupManifestWriter manifestWriter)
        {
            var backupPath = BackupMeta.BackupPath(config.TargetPath, backupName);

            Logger.Info("Running backup operation");
            try {
                return(BackupService.Run(config.SourcePath, config.ExcludePaths, previousBackupSum, backupPath,
                                         manifestWriter, Logger));
            }
            catch (BackupServiceException e) {
                throw new ApplicationRuntimeError(e.Message);
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Reads the backup index from a target directory.
        /// </summary>
        /// <param name="targetPath">The target directory to read from.</param>
        /// <returns>The read backup index, or <c>null</c> if the index file does not exist.</returns>
        /// <exception cref="ApplicationRuntimeError">If the index file exists, but could not be read/parsed.
        /// </exception>
        /// <seealso cref="BackupMeta.ReadIndexFile(string)"/>
        private BackupIndex?ReadBackupIndex(string targetPath)
        {
            var indexFilePath = BackupMeta.IndexFilePath(targetPath);

            try {
                var index = BackupIndexReader.Read(indexFilePath);
                Logger.Info($"Read backup index \"{indexFilePath}\"");
                return(index);
            }
            catch (BackupIndexFileIOException e) when(e.InnerException is PathNotFoundException)
            {
                Logger.Info("No existing backup index found");
                return(null);
            }
            catch (BackupIndexFileException e) {
                throw new ApplicationRuntimeError(e.Message);
            }
        }