diff options
author | Ben Bridle <ben@derelict.engineering> | 2025-02-01 17:25:42 +1300 |
---|---|---|
committer | Ben Bridle <ben@derelict.engineering> | 2025-02-01 17:25:42 +1300 |
commit | 6b76c382117f5551b90507cea9121c9cbd500e60 (patch) | |
tree | 8562428540ab9d4d72557638f6b753828601c702 /src | |
parent | fb80ee168e1977230680115304103b80ccf7f1ac (diff) | |
download | vagabond-6b76c382117f5551b90507cea9121c9cbd500e60.zip |
Only copy modified files
When copying a file, if a file already exists at the destination path
with the same last-modified date and the same size, the file is not
copied.
Diffstat (limited to 'src')
-rw-r--r-- | src/entry.rs | 8 | ||||
-rw-r--r-- | src/operations/cp.rs | 33 |
2 files changed, 38 insertions, 3 deletions
diff --git a/src/entry.rs b/src/entry.rs index 72eeb7e..1b6b577 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -1,6 +1,9 @@ -use std::path::{Path, PathBuf}; use crate::*; +use std::path::{Path, PathBuf}; +use std::time::SystemTime; + + #[derive(PartialEq)] pub enum EntryType { File, @@ -17,6 +20,8 @@ pub struct Entry { pub path: PathBuf, /// The file path as originally presented to the [Entry] constructor. pub original_path: PathBuf, + /// Not available on all platforms. + pub last_modified: Option<SystemTime>, } impl Entry { @@ -51,6 +56,7 @@ impl Entry { path: canonical_path, original_path: path.to_path_buf(), is_symlink: metadata.is_symlink(), + last_modified: metadata.modified().ok(), }) } diff --git a/src/operations/cp.rs b/src/operations/cp.rs index 33d4d04..6037b67 100644 --- a/src/operations/cp.rs +++ b/src/operations/cp.rs @@ -1,5 +1,8 @@ use crate::*; +use std::time::SystemTime; + + #[must_use] pub fn copy(source_path: impl AsRef<Path>, destination_path: impl AsRef<Path>) -> WriteResult<()> { let source = get_entry(&source_path)?; @@ -40,8 +43,16 @@ pub fn copy(source_path: impl AsRef<Path>, destination_path: impl AsRef<Path>) - #[must_use] fn copy_file(source_path: impl AsRef<Path>, destination_path: impl AsRef<Path>) -> WriteResult<()> { - let copy_result = std::fs::copy(&source_path, &destination_path); - io_result_to_write_result(copy_result, &destination_path.as_ref())?; + // Only copy file if size or last modified time is different to file at destination. + if let Comparison::Different(last_modified) = compare_files(&source_path, &destination_path) { + let copy_result = std::fs::copy(&source_path, &destination_path); + io_result_to_write_result(copy_result, &destination_path.as_ref())?; + if let Some(time) = last_modified { + if let Ok(dest) = std::fs::File::open(&destination_path) { + let _ = dest.set_modified(time); + } + } + } Ok(()) } @@ -53,3 +64,21 @@ fn copy_directory(source_path: impl AsRef<Path>, destination_path: impl AsRef<Pa } Ok(()) } + +enum Comparison { + Same, + Different(Option<SystemTime>), +} + +fn compare_files(source_path: impl AsRef<Path>, destination_path: impl AsRef<Path>) -> Comparison { + let Ok(source) = std::fs::File::open(&source_path) else { return Comparison::Different(None) }; + let Ok(source_metadata) = source.metadata() else { return Comparison::Different(None) }; + let Ok(source_modified) = source_metadata.modified() else { return Comparison::Different(None) }; + let Ok(dest) = std::fs::File::open(&destination_path) else { return Comparison::Different(Some(source_modified)) }; + let Ok(dest_metadata) = dest.metadata() else { return Comparison::Different(Some(source_modified)) }; + let Ok(dest_modified) = dest_metadata.modified() else { return Comparison::Different(Some(source_modified)) }; + match source_modified == dest_modified && source_metadata.len() == dest_metadata.len() { + true => Comparison::Same, + false => Comparison::Different(Some(source_modified)), + } +} |