diff --git a/Cargo.lock b/Cargo.lock index aa08a7c3..55391984 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -261,6 +261,7 @@ dependencies = [ "miette", "normalize-path", "once_cell", + "reflink-copy", "semver", "serde", "serde_json", @@ -2005,6 +2006,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "ioctl-sys" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bd11f3a29434026f5ff98c730b668ba74b1033637b8817940b54d040696133c" + [[package]] name = "ipconfig" version = "0.3.2" @@ -2750,6 +2757,18 @@ dependencies = [ "thiserror", ] +[[package]] +name = "reflink-copy" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9c6f4912869a1c9abaf4038e7051d88544960da7c9560b8baeaabfa3c95e05b" +dependencies = [ + "cfg-if", + "ioctl-sys", + "libc", + "windows 0.48.0", +] + [[package]] name = "regex" version = "1.9.0" diff --git a/crates/binstalk/Cargo.toml b/crates/binstalk/Cargo.toml index 527766d8..bc5c9cd4 100644 --- a/crates/binstalk/Cargo.toml +++ b/crates/binstalk/Cargo.toml @@ -29,6 +29,7 @@ maybe-owned = "0.3.4" miette = "5.9.0" normalize-path = { version = "0.2.1", path = "../normalize-path" } once_cell = "1.18.0" +reflink-copy = "0.1.5" semver = { version = "1.0.17", features = ["serde"] } serde = { version = "1.0.163", features = ["derive"] } serde_json = "1.0.99" diff --git a/crates/binstalk/src/fs.rs b/crates/binstalk/src/fs.rs index 7681c569..87d9ed28 100644 --- a/crates/binstalk/src/fs.rs +++ b/crates/binstalk/src/fs.rs @@ -1,24 +1,27 @@ use std::{fs, io, path::Path}; +use reflink_copy::reflink_or_copy; use tempfile::{NamedTempFile, TempPath}; use tracing::{debug, warn}; fn copy_to_tempfile(src: &Path, dst: &Path) -> io::Result { - let mut src_file = fs::File::open(src)?; - let parent = dst.parent().unwrap(); debug!("Creating named tempfile at '{}'", parent.display()); - let mut tempfile = NamedTempFile::new_in(parent)?; + let tempfile = NamedTempFile::new_in(parent)?; debug!( "Copying from '{}' to '{}'", src.display(), tempfile.path().display() ); - io::copy(&mut src_file, tempfile.as_file_mut())?; + // src and dst is likely to be on the same filesystem. + // Uses reflink if the fs support it, or fallback to + // `fs::copy` if it doesn't support it or it is not on the + // same filesystem. + reflink_or_copy(src, tempfile.path())?; debug!("Retrieving permissions of '{}'", src.display()); - let permissions = src_file.metadata()?.permissions(); + let permissions = src.metadata()?.permissions(); debug!( "Setting permissions of '{}' to '{permissions:#?}'",