/// <summary> /// Restores a single backup entry to the file system /// </summary> /// <param name="path"> /// The file system path to restore to /// </param> /// <param name="backupEntry"> /// The backup entry to restore /// </param> /// <param name="restoreEntry"> /// The restore entry to restore /// </param> private void RestoreFile( IO.Path path, Backup.Entry backupEntry, Restore.Entry restoreEntry) { using (var input = new IO.StreamStack()) using (var output = IO.FileSystem.Truncate(path)) { // create the input stream stack, consisting of the following // . restore stream from the archive // . read rate limiter // . decryptor // . optional decompressor input.Push( this.restore.Restore(restoreEntry) ); input.Push( this.limiter.CreateStreamFilter(input.Top) ); input.Push( new CryptoStream( input.Top, this.Crypto.CreateDecryptor(), CryptoStreamMode.Read ) ); if (backupEntry.Session.Compress) input.Push( new IO.CompressionStream( input.Top, IO.CompressionMode.Decompress ) ); copier.CopyAndFlush(input, output); } // verify the backup entry's CRC if requested if (this.Session.VerifyResults) if (IO.CrcFilter.Calculate(path) != backupEntry.Crc32) throw new InvalidOperationException( String.Format(Strings.ExecuteRestoreCrcFailed, path) ); }
/// <summary> /// Backs up a single file entry to the attached archive /// </summary> /// <param name="entry"> /// The entry to store /// </param> private void BackupEntry(SkyFloe.Backup.Entry entry) { ReportProgress( new ProgressEventArgs() { Operation = "BeginBackupEntry", BackupSession = this.Session, BackupEntry = entry } ); try { using (var input = new IO.StreamStack()) { // create the input stream stack, consisting of the following // . source file // . CRC calculation filter // . optional compressor // . encryptor // . read rate limiter input.Push( IO.FileSystem.Open(entry.Node.GetAbsolutePath()) ); input.Push( new IO.CrcFilter(input.Top) ); if (this.Session.Compress) input.Push( new IO.CompressionStream( input.Top, IO.CompressionMode.Compress ) ); input.Push( new CryptoStream( input.Top, this.Crypto.CreateEncryptor(), CryptoStreamMode.Read ) ); input.Push( this.limiter.CreateStreamFilter(input.Top) ); // send the stream stack to the backup plugin // and record the calculated CRC value in the entry this.backup.Backup(entry, input); entry.Crc32 = input.GetStream<IO.CrcFilter>().Value; } // commit the archive entry to the index // at this point, the entry is locally durable // until the next checkpoint, when it becomes permanent entry.State = SkyFloe.Backup.EntryState.Completed; entry.Blob.Length += entry.Length; this.Session.ActualLength += entry.Length; using (var txn = new TransactionScope()) { this.Archive.BackupIndex.UpdateEntry(entry); this.Archive.BackupIndex.UpdateBlob(entry.Blob); this.Archive.BackupIndex.UpdateSession(this.Session); txn.Complete(); } } catch (Exception e) { switch (ReportError("BackupEntry", e)) { case ErrorResult.Retry: // the client chose to retry, so leave the entry pending break; case ErrorResult.Fail: // the client chose to ignore the failed entry, // so mark it as failed and continue entry = this.Archive.BackupIndex.FetchEntry(entry.ID); entry.State = SkyFloe.Backup.EntryState.Failed; this.Archive.BackupIndex.UpdateEntry(entry); break; default: // the client chose to abort, so propagate the exception throw; } } if (entry.State == SkyFloe.Backup.EntryState.Completed) ReportProgress( new ProgressEventArgs() { Operation = "EndBackupEntry", BackupSession = this.Session, BackupEntry = entry } ); }