summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBen Bridle <ben@derelict.engineering>2025-02-01 17:25:42 +1300
committerBen Bridle <ben@derelict.engineering>2025-02-01 17:25:42 +1300
commit6b76c382117f5551b90507cea9121c9cbd500e60 (patch)
tree8562428540ab9d4d72557638f6b753828601c702 /src
parentfb80ee168e1977230680115304103b80ccf7f1ac (diff)
downloadvagabond-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.rs8
-rw-r--r--src/operations/cp.rs33
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)),
+ }
+}