From d204c684008fc35e8e9e6aa619c1aa034328d9f7 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Thu, 15 Jun 2023 09:56:40 +0200 Subject: [PATCH] fix: actually working incremental backup --- src/server/backups.rs | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/server/backups.rs b/src/server/backups.rs index 66c7192..2620e17 100644 --- a/src/server/backups.rs +++ b/src/server/backups.rs @@ -38,9 +38,12 @@ fn files(src_dir: PathBuf) -> io::Result> { Ok(files) } -/// Return false only if we can say with certainty that the file wasn't modified since the given -/// timestamp, true otherwise. -fn modified_since>(time: chrono::DateTime, path: T) -> bool { +/// Check whether a file has been modified since the given timestamp. +/// +/// Note that this function will *only* return true if it can determine with certainty that the +/// file has not been modified. If any errors occur while obtaining the required metadata (e.g. if +/// the file system does not support this metadata), this function will return false. +fn not_modified_since>(time: chrono::DateTime, path: T) -> bool { let path = path.as_ref(); if let Ok(metadata) = path.metadata() { @@ -50,14 +53,14 @@ fn modified_since>(time: chrono::DateTime, path: T) -> bool let t: chrono::DateTime = last_modified.into(); let t = t.with_timezone(&Local); - return t >= time; + return t < time; } } false } -#[derive(PartialEq)] +#[derive(Debug, PartialEq)] pub enum BackupType { Full, Incremental, @@ -71,6 +74,7 @@ pub enum BackupError { type BackupResult = Result; /// Represents the changes relative to the previous backup +#[derive(Debug)] pub struct BackupDelta { /// What files were added/modified in each part of the tarball. pub added: HashMap>, @@ -142,6 +146,7 @@ impl BackupDelta { } /// Represents a successful backup +#[derive(Debug)] pub struct Backup { previous: Option>, /// When the backup was started (also corresponds to the name) @@ -199,7 +204,7 @@ impl Backup { let files = files(src_dir.clone())?; for path in &files { - ar.append_path_with_name(dir_in_tar.join(path), src_dir.join(path))?; + ar.append_path_with_name(src_dir.join(path), dir_in_tar.join(path))?; } added.insert(dir_in_tar, files); @@ -231,6 +236,7 @@ impl Backup { let enc = GzEncoder::new(tar_gz, Compression::default()); let mut ar = tar::Builder::new(enc); + // TODO remove unwrap let previous_state = previous.state().unwrap(); let mut delta = BackupDelta::new(); @@ -238,12 +244,14 @@ impl Backup { let files = files(src_dir.clone())?; let added_files = files .iter() - .filter(|p| modified_since(previous.start_time, p)) + // This explicit negation is because we wish to also include files for which we + // couldn't determine the last modified time + .filter(|p| !not_modified_since(previous.start_time, src_dir.join(p))) .cloned() .collect::>(); for path in added_files.iter() { - ar.append_path_with_name(dir_in_tar.join(path), src_dir.join(path))?; + ar.append_path_with_name(src_dir.join(path), dir_in_tar.join(path))?; } delta.added.insert(dir_in_tar.clone(), added_files); @@ -295,16 +303,13 @@ impl BackupManager { (PathBuf::from("worlds"), self.world_dir.clone()), ]; - if let Some(last_backup) = &self.last_backup { - let clone = last_backup.clone(); - self.last_backup = Some(Arc::new(Backup::create_from( - clone, - &self.backup_dir, - dirs, - )?)); + let backup = if let Some(last_backup) = &self.last_backup { + Backup::create_from(Arc::clone(last_backup), &self.backup_dir, dirs)? } else { - self.last_backup = Some(Arc::new(Backup::create(&self.backup_dir, dirs)?)); - } + Backup::create(&self.backup_dir, dirs)? + }; + + self.last_backup = Some(Arc::new(backup)); Ok(()) }