#![cfg_attr(not(test), deny(clippy::unwrap_used, clippy::expect_used))]
#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
use std::path::Path;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Outcome {
Compressed { before: u64, after: u64 },
NoGain { before: u64, after: u64 },
AlreadyCompressed { before: u64 },
Unsupported { reason: UnsupportedReason },
Skipped { reason: SkipReason },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnsupportedReason {
Filesystem,
NetworkOrOverlay,
PlatformBuild,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SkipReason {
PermissionDenied,
Busy,
Immutable,
Encrypted,
IntegrityRevert,
NotLoadable,
TooLarge,
GateExcluded,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Support {
Supported,
AlreadyCompressed,
Unsupported(UnsupportedReason),
}
#[derive(Debug)]
pub enum Error {
Io {
context: &'static str,
source: std::io::Error,
},
NotFound(std::path::PathBuf),
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::Io { context, source } => write!(f, "io error at {context}: {source}"),
Error::NotFound(p) => write!(f, "file not found: {}", p.display()),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::Io { source, .. } => Some(source),
Error::NotFound(_) => None,
}
}
}
pub(crate) fn io(context: &'static str) -> Error {
Error::Io {
context,
source: std::io::Error::last_os_error(),
}
}
#[cfg(unix)]
pub(crate) fn cstring(path: &Path) -> Result<std::ffi::CString, Error> {
use std::os::unix::ffi::OsStrExt;
std::ffi::CString::new(path.as_os_str().as_bytes()).map_err(|_| Error::Io {
context: "path has interior NUL",
source: std::io::Error::from(std::io::ErrorKind::InvalidInput),
})
}
pub fn probe(path: &Path) -> Result<Support, Error> {
backend::detect(path)
}
pub fn compress_file(path: &Path) -> Result<Outcome, Error> {
compress_file_with(&Os, path)
}
fn compress_file_with<B: Backend>(backend: &B, path: &Path) -> Result<Outcome, Error> {
if !path.exists() {
return Err(Error::NotFound(path.to_path_buf()));
}
match backend.detect(path)? {
Support::Unsupported(reason) => Ok(Outcome::Unsupported { reason }),
Support::AlreadyCompressed => Ok(Outcome::AlreadyCompressed {
before: verify::on_disk_bytes(path)?,
}),
Support::Supported => safety::apply_guarded(backend, path),
}
}
pub fn compress_bytes(path: &Path, content: &[u8], gate: &Gate) -> Result<Outcome, Error> {
compress_bytes_with(&Os, path, content, gate)
}
fn compress_bytes_with<B: Backend>(
backend: &B,
path: &Path,
content: &[u8],
gate: &Gate,
) -> Result<Outcome, Error> {
let name = path.to_string_lossy();
let normalized = name.replace('\\', "/");
if !gate.matches(&normalized, content.len() as u64) {
plain_write(path, content)?;
return Ok(Outcome::Skipped {
reason: SkipReason::GateExcluded,
});
}
let probe_target = if path.exists() {
path.to_path_buf()
} else {
match path.parent() {
Some(dir) => dir.to_path_buf(),
None => path.to_path_buf(),
}
};
match backend.detect(&probe_target) {
Ok(Support::Supported) => match safety::compress_bytes_guarded(backend, path, content) {
Ok(Outcome::Skipped { .. }) | Err(_) => {
plain_write(path, content)?;
Ok(Outcome::Skipped {
reason: SkipReason::IntegrityRevert,
})
}
other => other,
},
Ok(Support::AlreadyCompressed) | Ok(Support::Unsupported(_)) | Err(_) => {
plain_write(path, content)?;
Ok(Outcome::Unsupported {
reason: UnsupportedReason::Filesystem,
})
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CopyOutcome {
Cloned { compressed: bool },
CopiedCompressed { before: u64, after: u64 },
CopiedPlain { skipped: Option<SkipReason> },
}
pub fn try_clone_file(src: &Path, dest: &Path) -> Result<bool, Error> {
if !src.exists() {
return Err(Error::NotFound(src.to_path_buf()));
}
Os.clone_file(src, dest)
}
pub fn copy_file(src: &Path, dest: &Path) -> Result<CopyOutcome, Error> {
copy_file_with(&Os, src, dest)
}
fn copy_file_with<B: Backend>(backend: &B, src: &Path, dest: &Path) -> Result<CopyOutcome, Error> {
if !src.exists() {
return Err(Error::NotFound(src.to_path_buf()));
}
if dest.exists() {
if is_same_file(src, dest) {
return Ok(CopyOutcome::Cloned {
compressed: backend.is_already_compressed(src).unwrap_or(false),
});
}
std::fs::remove_file(dest).map_err(|source| Error::Io {
context: "replace existing destination",
source,
})?;
}
let compressed_src = backend.is_already_compressed(src).unwrap_or(false);
if backend.clone_file(src, dest)? {
return Ok(CopyOutcome::Cloned {
compressed: compressed_src,
});
}
let content = std::fs::read(src).map_err(|source| Error::Io {
context: "read copy source",
source,
})?;
let mode = std::fs::metadata(src).ok().map(|meta| meta.permissions());
if !compressed_src {
plain_write(dest, &content)?;
if let Some(mode) = mode {
let _ = std::fs::set_permissions(dest, mode);
}
return Ok(CopyOutcome::CopiedPlain { skipped: None });
}
let outcome = compress_bytes_with(backend, dest, &content, &Gate::any())?;
if let Some(mode) = mode {
let _ = std::fs::set_permissions(dest, mode);
}
Ok(match outcome {
Outcome::Compressed { before, after } | Outcome::NoGain { before, after } => {
CopyOutcome::CopiedCompressed { before, after }
}
Outcome::AlreadyCompressed { before } => CopyOutcome::CopiedCompressed {
before,
after: before,
},
Outcome::Unsupported { .. } => CopyOutcome::CopiedPlain { skipped: None },
Outcome::Skipped { reason } => CopyOutcome::CopiedPlain {
skipped: Some(reason),
},
})
}
#[cfg(unix)]
fn is_same_file(a: &Path, b: &Path) -> bool {
use std::os::unix::fs::MetadataExt;
match (std::fs::metadata(a), std::fs::metadata(b)) {
(Ok(meta_a), Ok(meta_b)) => meta_a.dev() == meta_b.dev() && meta_a.ino() == meta_b.ino(),
_ => false,
}
}
#[cfg(windows)]
fn is_same_file(a: &Path, b: &Path) -> bool {
use std::os::windows::io::AsRawHandle;
use windows_sys::Win32::Storage::FileSystem::{
GetFileInformationByHandle, BY_HANDLE_FILE_INFORMATION,
};
fn identity(path: &Path) -> Option<(u32, u64)> {
let file = std::fs::File::open(path).ok()?;
let mut info = unsafe { std::mem::zeroed::<BY_HANDLE_FILE_INFORMATION>() };
if unsafe { GetFileInformationByHandle(file.as_raw_handle() as _, &mut info) } == 0 {
return None;
}
Some((
info.dwVolumeSerialNumber,
(u64::from(info.nFileIndexHigh) << 32) | u64::from(info.nFileIndexLow),
))
}
match (identity(a), identity(b)) {
(Some(id_a), Some(id_b)) => id_a == id_b,
_ => match (std::fs::canonicalize(a), std::fs::canonicalize(b)) {
(Ok(canon_a), Ok(canon_b)) => canon_a == canon_b,
_ => false,
},
}
}
#[cfg(not(any(unix, windows)))]
fn is_same_file(a: &Path, b: &Path) -> bool {
match (std::fs::canonicalize(a), std::fs::canonicalize(b)) {
(Ok(canon_a), Ok(canon_b)) => canon_a == canon_b,
_ => false,
}
}
fn plain_write(path: &Path, content: &[u8]) -> Result<(), Error> {
use std::io::Write;
let dir = path.parent().ok_or_else(|| Error::Io {
context: "no parent dir",
source: std::io::Error::from(std::io::ErrorKind::InvalidInput),
})?;
let name = path
.file_name()
.map(|n| n.to_string_lossy().into_owned())
.unwrap_or_else(|| "addon".to_string());
let tmp = dir.join(format!(".{name}.plain-{}.tmp", std::process::id()));
let res = (|| -> std::io::Result<()> {
let mut file = std::fs::File::create(&tmp)?;
file.write_all(content)?;
file.sync_all()
})();
if let Err(source) = res {
let _ = std::fs::remove_file(&tmp);
return Err(Error::Io {
context: "plain write temp",
source,
});
}
std::fs::rename(&tmp, path).map_err(|source| {
let _ = std::fs::remove_file(&tmp);
Error::Io {
context: "plain write rename",
source,
}
})
}
pub struct Stat {
pub compressed: bool,
pub logical: u64,
pub physical: u64,
}
pub fn stat(path: &Path) -> Result<Stat, Error> {
stat_with(&Os, path)
}
fn stat_with<B: Backend>(backend: &B, path: &Path) -> Result<Stat, Error> {
let meta = std::fs::metadata(path).map_err(|source| Error::Io {
context: "stat",
source,
})?;
let logical = meta.len();
#[cfg(unix)]
let physical = {
use std::os::unix::fs::MetadataExt;
meta.blocks().saturating_mul(512)
};
#[cfg(not(unix))]
let physical = verify::on_disk_bytes(path)?;
let compressed = match backend.compressed_on_disk(path) {
Ok(Some(signal)) => signal,
Ok(None) | Err(_) => logical > 0 && physical < logical,
};
Ok(Stat {
compressed,
logical,
physical,
})
}
#[cfg(feature = "addon")]
pub mod addon;
#[cfg(feature = "exe")]
pub mod exe;
mod gate;
mod remove;
mod safety;
mod stream;
mod verify;
pub use gate::{Gate, GateParseError, SizePredicate, DEFAULT_GLOB};
pub use remove::{rm, RmOptions};
pub use stream::DecmpfsWriter;
#[cfg(target_os = "linux")]
#[path = "linux.rs"]
mod backend;
#[cfg(target_os = "macos")]
#[path = "macos.rs"]
mod backend;
#[cfg(target_os = "windows")]
#[path = "windows.rs"]
mod backend;
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
#[path = "unsupported.rs"]
mod backend;
#[cfg_attr(test, mockall::automock)]
pub(crate) trait Backend {
fn detect(&self, path: &Path) -> Result<Support, Error>;
fn is_already_compressed(&self, path: &Path) -> Result<bool, Error>;
fn apply_inplace(&self, path: &Path, snapshot: &[u8]) -> Result<(), Error>;
fn apply_bytes(
&self,
path: &Path,
content: &[u8],
mode: Option<std::fs::Permissions>,
) -> Result<(), Error>;
fn compressed_on_disk(&self, path: &Path) -> Result<Option<bool>, Error>;
fn clone_file(&self, _src: &Path, _dest: &Path) -> Result<bool, Error> {
Ok(false)
}
}
pub(crate) struct Os;
impl Backend for Os {
fn detect(&self, path: &Path) -> Result<Support, Error> {
backend::detect(path)
}
fn is_already_compressed(&self, path: &Path) -> Result<bool, Error> {
backend::is_already_compressed(path)
}
fn apply_inplace(&self, path: &Path, snapshot: &[u8]) -> Result<(), Error> {
backend::apply_inplace(path, snapshot)
}
fn apply_bytes(
&self,
path: &Path,
content: &[u8],
mode: Option<std::fs::Permissions>,
) -> Result<(), Error> {
backend::apply_bytes(path, content, mode)
}
fn compressed_on_disk(&self, path: &Path) -> Result<Option<bool>, Error> {
backend::compressed_on_disk(path)
}
fn clone_file(&self, src: &Path, dest: &Path) -> Result<bool, Error> {
backend::clone_file(src, dest)
}
}
#[cfg(test)]
pub(crate) struct FakeBackend {
pub(crate) detect: Support,
pub(crate) apply_error: Option<std::io::ErrorKind>,
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
impl FakeBackend {
fn apply_result(&self) -> Result<(), Error> {
match self.apply_error {
None => Ok(()),
Some(kind) => Err(Error::Io {
context: "fake apply",
source: std::io::Error::from(kind),
}),
}
}
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
impl Backend for FakeBackend {
fn detect(&self, _path: &Path) -> Result<Support, Error> {
Ok(self.detect)
}
fn is_already_compressed(&self, _path: &Path) -> Result<bool, Error> {
Ok(false)
}
fn apply_inplace(&self, _path: &Path, _snapshot: &[u8]) -> Result<(), Error> {
self.apply_result()
}
fn apply_bytes(
&self,
_path: &Path,
_content: &[u8],
_mode: Option<std::fs::Permissions>,
) -> Result<(), Error> {
self.apply_result()
}
fn compressed_on_disk(&self, _path: &Path) -> Result<Option<bool>, Error> {
Ok(Some(false))
}
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use super::*;
fn scratch(tag: &str) -> std::path::PathBuf {
let dir = std::env::temp_dir().join(format!("decmpfs-{tag}-{}", std::process::id()));
let _ = std::fs::remove_file(&dir);
std::fs::create_dir_all(&dir).unwrap();
dir
}
fn fake_addon() -> Vec<u8> {
let mut raw = vec![0x7f, 0x45, 0x4c, 0x46];
raw.extend_from_slice(&[7u8; 9000]);
raw
}
#[test]
fn compress_file_errors_when_missing() {
let p = std::path::Path::new("/no/such/addon.node");
assert!(matches!(compress_file(p), Err(Error::NotFound(_))));
}
#[test]
fn plain_write_errors_when_the_path_has_no_parent() {
let out = plain_write(std::path::Path::new("/"), b"x");
assert!(matches!(
out,
Err(Error::Io {
context: "no parent dir",
..
})
));
}
#[test]
fn error_display_and_source() {
let nf = Error::NotFound(std::path::PathBuf::from("/x"));
assert!(nf.to_string().contains("not found"));
assert!(std::error::Error::source(&nf).is_none());
let io = Error::Io {
context: "ctx",
source: std::io::Error::from(std::io::ErrorKind::PermissionDenied),
};
assert!(io.to_string().contains("ctx"));
assert!(std::error::Error::source(&io).is_some());
}
#[cfg(unix)]
#[test]
fn probe_reports_a_support_variant_without_mutating() {
assert!(matches!(
probe(std::path::Path::new("/dev/null")),
Ok(Support::Supported | Support::AlreadyCompressed | Support::Unsupported(_))
));
}
#[cfg(unix)]
#[test]
fn compress_file_reports_unsupported_on_a_non_compressing_fs() {
let out = compress_file(std::path::Path::new("/dev/null"));
assert!(
matches!(out, Ok(Outcome::Unsupported { .. })),
"devfs → Unsupported, got {out:?}"
);
}
#[cfg(target_os = "macos")]
#[test]
fn compress_file_compresses_then_is_idempotent_and_transparent() {
let dir = scratch("ok");
let path = dir.join("addon.node");
std::fs::write(&path, fake_addon()).unwrap();
let out = compress_file(&path);
assert!(
matches!(
out,
Ok(Outcome::Compressed { .. } | Outcome::NoGain { .. } | Outcome::AlreadyCompressed { .. })
),
"writable addon on APFS → applied, got {out:?}"
);
assert_eq!(std::fs::read(&path).unwrap(), fake_addon());
assert!(matches!(
compress_file(&path),
Ok(Outcome::AlreadyCompressed { .. })
));
std::fs::remove_dir_all(&dir).ok();
}
#[cfg(target_os = "macos")]
#[test]
fn compress_bytes_one_pass_writes_compressed_and_reads_back_identical() {
let dir = scratch("bytes");
let path = dir.join("fresh.node");
let content = fake_addon();
let out = compress_bytes(&path, &content, &Gate::any());
assert!(
matches!(out, Ok(Outcome::Compressed { .. } | Outcome::NoGain { .. })),
"one-pass APFS write → applied, got {out:?}"
);
assert!(path.exists(), "file was created");
assert_eq!(std::fs::read(&path).unwrap(), content);
assert!(matches!(
compress_file(&path),
Ok(Outcome::AlreadyCompressed { .. })
));
std::fs::remove_dir_all(&dir).ok();
}
#[cfg(unix)]
#[test]
fn compress_bytes_gate_excluded_writes_plain() {
let dir = scratch("gate");
let path = dir.join("not-an-addon.txt");
let content = b"plain text, not a .node".to_vec();
let gate = Gate::default(); let out = compress_bytes(&path, &content, &gate);
assert!(
matches!(
out,
Ok(Outcome::Skipped {
reason: SkipReason::GateExcluded
})
),
"non-.node → GateExcluded, got {out:?}"
);
assert_eq!(std::fs::read(&path).unwrap(), content);
std::fs::remove_dir_all(&dir).ok();
}
#[cfg(unix)]
#[test]
fn compress_bytes_falls_back_to_plain_on_unsupported_fs() {
let dir = scratch("fallback");
let path = dir.join("x.node");
let content = fake_addon();
let out = compress_bytes(&path, &content, &Gate::any());
assert!(out.is_ok(), "never errors on a normal temp, got {out:?}");
assert_eq!(std::fs::read(&path).unwrap(), content, "bytes always land");
std::fs::remove_dir_all(&dir).ok();
}
#[cfg(unix)]
#[test]
fn compress_file_skips_a_read_only_file() {
if unsafe { libc::geteuid() } == 0 {
return;
}
let dir = scratch("ro");
let path = dir.join("addon.node");
std::fs::write(&path, fake_addon()).unwrap();
if !matches!(probe(&path), Ok(Support::Supported)) {
std::fs::remove_dir_all(&dir).ok();
return;
}
let mut perm = std::fs::metadata(&path).unwrap().permissions();
perm.set_readonly(true);
std::fs::set_permissions(&path, perm).unwrap();
let outcome = compress_file(&path);
use std::os::unix::fs::PermissionsExt;
std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o644)).ok();
assert!(
matches!(
outcome,
Ok(Outcome::Skipped {
reason: SkipReason::PermissionDenied
})
),
"read-only → Skipped(PermissionDenied), got {outcome:?}"
);
std::fs::remove_dir_all(&dir).ok();
}
#[cfg(target_os = "macos")]
#[test]
fn compress_bytes_overwrites_an_existing_file() {
let dir = scratch("overwrite");
let path = dir.join("addon.node");
std::fs::write(&path, b"stale contents").unwrap();
let content = fake_addon();
let out = compress_bytes(&path, &content, &Gate::any());
assert!(out.is_ok(), "overwrite never errors, got {out:?}");
assert_eq!(
std::fs::read(&path).unwrap(),
content,
"new bytes replace the old"
);
std::fs::remove_dir_all(&dir).ok();
}
#[cfg(target_os = "macos")]
#[test]
fn compress_bytes_onto_a_directory_path_is_a_hard_error() {
let dir = scratch("dir-target");
let target = dir.join("a-dir");
std::fs::create_dir_all(&target).unwrap();
let out = compress_bytes(&target, &fake_addon(), &Gate::any());
assert!(
out.is_err(),
"cannot write a file over a directory, got {out:?}"
);
assert!(target.is_dir(), "the directory is left intact");
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn stat_reports_size_and_uncompressed_for_a_plain_file() {
let dir = scratch("stat-plain");
let path = dir.join("f");
std::fs::write(&path, vec![0u8; 4096]).unwrap();
let s = stat(&path).unwrap();
assert_eq!(s.logical, 4096, "logical == the written bytes");
assert!(s.physical > 0, "allocated bytes reported");
assert!(
!s.compressed,
"a freshly-written plain file is not FS-compressed"
);
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn stat_reflects_a_compressed_file_where_supported() {
let dir = scratch("stat-comp");
let path = dir.join("addon.node");
let content = vec![0xABu8; 128 * 1024];
let outcome = compress_bytes(&path, &content, &Gate::any()).unwrap();
let s = stat(&path).unwrap();
assert_eq!(
s.logical,
content.len() as u64,
"logical == the written bytes"
);
assert_eq!(
std::fs::read(&path).unwrap(),
content,
"content round-trips"
);
if matches!(outcome, Outcome::Compressed { .. }) {
assert!(
s.compressed,
"a Compressed outcome → stat reports compressed"
);
assert!(
s.physical < s.logical,
"allocation shrank below the logical size"
);
}
std::fs::remove_dir_all(&dir).ok();
}
#[cfg(target_os = "macos")]
#[test]
fn compress_bytes_into_a_read_only_dir_is_fail_soft() {
if unsafe { libc::geteuid() } == 0 {
return;
}
use std::os::unix::fs::PermissionsExt;
let dir = scratch("ro-dir");
let locked = dir.join("locked");
std::fs::create_dir_all(&locked).unwrap();
std::fs::set_permissions(&locked, std::fs::Permissions::from_mode(0o555)).unwrap();
let out = compress_bytes(&locked.join("x.node"), &fake_addon(), &Gate::any());
std::fs::set_permissions(&locked, std::fs::Permissions::from_mode(0o755)).ok();
assert!(out.is_err(), "a read-only dir admits no write, got {out:?}");
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn compress_file_reports_already_compressed_from_detect() {
let dir = scratch("already-detect");
let path = dir.join("f.node");
std::fs::write(&path, fake_addon()).unwrap();
let backend = FakeBackend {
detect: Support::AlreadyCompressed,
apply_error: None,
};
assert!(matches!(
compress_file_with(&backend, &path),
Ok(Outcome::AlreadyCompressed { .. })
));
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn compress_bytes_falls_back_to_plain_on_an_unsupported_fs() {
let dir = scratch("unsup");
let path = dir.join("x.node");
let content = fake_addon();
let backend = FakeBackend {
detect: Support::Unsupported(UnsupportedReason::Filesystem),
apply_error: None,
};
let out = compress_bytes_with(&backend, &path, &content, &Gate::any());
assert!(
matches!(out, Ok(Outcome::Unsupported { .. })),
"got {out:?}"
);
assert_eq!(std::fs::read(&path).unwrap(), content, "bytes landed plain");
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn compress_bytes_falls_back_to_plain_on_a_guarded_skip() {
let dir = scratch("guard-skip");
let path = dir.join("x.node");
let content = fake_addon();
let backend = FakeBackend {
detect: Support::Supported,
apply_error: Some(std::io::ErrorKind::PermissionDenied),
};
let out = compress_bytes_with(&backend, &path, &content, &Gate::any());
assert!(
matches!(
out,
Ok(Outcome::Skipped {
reason: SkipReason::IntegrityRevert
})
),
"got {out:?}"
);
assert_eq!(std::fs::read(&path).unwrap(), content, "bytes landed plain");
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn copy_file_errors_when_the_source_is_missing() {
let dir = scratch("copy-missing");
let out = copy_file(&dir.join("absent.node"), &dir.join("dest.node"));
assert!(matches!(out, Err(Error::NotFound(_))));
std::fs::remove_dir_all(&dir).ok();
}
struct RecompressingFake;
impl Backend for RecompressingFake {
fn detect(&self, _path: &Path) -> Result<Support, Error> {
Ok(Support::Supported)
}
fn is_already_compressed(&self, _path: &Path) -> Result<bool, Error> {
Ok(true)
}
fn apply_inplace(&self, _path: &Path, _snapshot: &[u8]) -> Result<(), Error> {
Ok(())
}
fn apply_bytes(
&self,
path: &Path,
content: &[u8],
_mode: Option<std::fs::Permissions>,
) -> Result<(), Error> {
std::fs::write(path, content).map_err(|source| Error::Io {
context: "fake write",
source,
})
}
fn compressed_on_disk(&self, _path: &Path) -> Result<Option<bool>, Error> {
Ok(Some(true))
}
}
#[test]
fn copy_file_recompresses_at_the_destination_when_it_cannot_clone() {
let dir = scratch("copy-recompress");
let src = dir.join("src.node");
let dest = dir.join("dest.node");
let content = fake_addon();
std::fs::write(&src, &content).unwrap();
let out = copy_file_with(&RecompressingFake, &src, &dest).unwrap();
assert!(
matches!(out, CopyOutcome::CopiedCompressed { .. }),
"got {out:?}"
);
assert_eq!(
std::fs::read(&dest).unwrap(),
content,
"bytes are identical"
);
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn copy_file_with_mock_backend_takes_the_clone_fast_path() {
let dir = tempfile::tempdir().unwrap();
let src = dir.path().join("a.node");
std::fs::write(&src, b"native").unwrap();
let dest = dir.path().join("b.node");
let mut backend = MockBackend::new();
backend
.expect_is_already_compressed()
.returning(|_| Ok(true));
backend.expect_clone_file().returning(|_, _| Ok(true));
let out = copy_file_with(&backend, &src, &dest).unwrap();
assert!(
matches!(out, CopyOutcome::Cloned { compressed: true }),
"clone fast-path → Cloned; got {out:?}"
);
}
#[test]
fn copy_file_copies_a_plain_source_plain_and_replaces_the_destination() {
let dir = scratch("copy-plain");
let src = dir.join("src.node");
let dest = dir.join("dest.node");
let content = fake_addon();
std::fs::write(&src, &content).unwrap();
std::fs::write(&dest, b"stale destination").unwrap();
let backend = FakeBackend {
detect: Support::Supported,
apply_error: None,
};
let out = copy_file_with(&backend, &src, &dest).unwrap();
assert_eq!(out, CopyOutcome::CopiedPlain { skipped: None });
assert_eq!(
std::fs::read(&dest).unwrap(),
content,
"destination replaced"
);
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn copy_file_lands_plain_and_reports_the_skip_when_recompression_fails() {
struct SkippingFake;
impl Backend for SkippingFake {
fn detect(&self, _path: &Path) -> Result<Support, Error> {
Ok(Support::Supported)
}
fn is_already_compressed(&self, _path: &Path) -> Result<bool, Error> {
Ok(true)
}
fn apply_inplace(&self, _path: &Path, _snapshot: &[u8]) -> Result<(), Error> {
Ok(())
}
fn apply_bytes(
&self,
_path: &Path,
_content: &[u8],
_mode: Option<std::fs::Permissions>,
) -> Result<(), Error> {
Err(Error::Io {
context: "fake apply",
source: std::io::Error::from(std::io::ErrorKind::PermissionDenied),
})
}
fn compressed_on_disk(&self, _path: &Path) -> Result<Option<bool>, Error> {
Ok(Some(false))
}
}
let dir = scratch("copy-skip");
let src = dir.join("src.node");
let dest = dir.join("dest.node");
let content = fake_addon();
std::fs::write(&src, &content).unwrap();
let out = copy_file_with(&SkippingFake, &src, &dest).unwrap();
assert!(
matches!(out, CopyOutcome::CopiedPlain { skipped: Some(_) }),
"got {out:?}"
);
assert_eq!(std::fs::read(&dest).unwrap(), content, "bytes still landed");
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn copy_file_onto_itself_is_a_noop_reported_as_cloned() {
let dir = scratch("copy-self");
let src = dir.join("src.node");
let content = fake_addon();
std::fs::write(&src, &content).unwrap();
let backend = FakeBackend {
detect: Support::Supported,
apply_error: None,
};
let out = copy_file_with(&backend, &src, &src).unwrap();
assert!(matches!(out, CopyOutcome::Cloned { .. }), "got {out:?}");
assert_eq!(std::fs::read(&src).unwrap(), content, "source untouched");
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn is_same_file_sees_hardlinks_and_distinct_files() {
let dir = scratch("same-file");
let a = dir.join("a.node");
let b = dir.join("b.node");
std::fs::write(&a, b"bytes").unwrap();
std::fs::write(&b, b"bytes").unwrap();
assert!(is_same_file(&a, &a), "identical path");
assert!(!is_same_file(&a, &b), "distinct files");
let link = dir.join("a-link.node");
std::fs::hard_link(&a, &link).unwrap();
assert!(is_same_file(&a, &link), "hardlink shares the inode");
assert!(
!is_same_file(&a, &dir.join("absent.node")),
"a missing path is never the same file"
);
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn copy_file_onto_a_hardlink_is_a_noop_reported_as_cloned() {
let dir = scratch("copy-hardlink");
let src = dir.join("src.node");
let dest = dir.join("dest.node");
let content = fake_addon();
std::fs::write(&src, &content).unwrap();
std::fs::hard_link(&src, &dest).unwrap();
let out = copy_file(&src, &dest).unwrap();
assert!(matches!(out, CopyOutcome::Cloned { .. }), "got {out:?}");
assert_eq!(std::fs::read(&src).unwrap(), content, "source untouched");
assert_eq!(std::fs::read(&dest).unwrap(), content, "hardlink untouched");
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn copy_file_errors_when_the_destination_cannot_be_replaced() {
let dir = scratch("copy-dest-dir");
let src = dir.join("src.node");
std::fs::write(&src, fake_addon()).unwrap();
let dest = dir.join("dest.node");
std::fs::create_dir(&dest).unwrap();
let backend = FakeBackend {
detect: Support::Supported,
apply_error: None,
};
let out = copy_file_with(&backend, &src, &dest);
assert!(
matches!(
out,
Err(Error::Io {
context: "replace existing destination",
..
})
),
"got {out:?}"
);
std::fs::remove_dir_all(&dir).ok();
}
#[cfg(unix)]
#[test]
fn copy_file_errors_when_the_source_is_unreadable() {
use std::os::unix::fs::PermissionsExt;
let dir = scratch("copy-unreadable");
let src = dir.join("src.node");
let dest = dir.join("dest.node");
std::fs::write(&src, fake_addon()).unwrap();
std::fs::set_permissions(&src, std::fs::Permissions::from_mode(0o000)).unwrap();
let backend = FakeBackend {
detect: Support::Supported,
apply_error: None,
};
let out = copy_file_with(&backend, &src, &dest);
std::fs::set_permissions(&src, std::fs::Permissions::from_mode(0o644)).ok();
assert!(
matches!(
out,
Err(Error::Io {
context: "read copy source",
..
})
),
"got {out:?}"
);
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn try_clone_file_errors_when_the_source_is_missing() {
let dir = scratch("clone-missing");
let out = try_clone_file(&dir.join("absent.node"), &dir.join("dest.node"));
assert!(matches!(out, Err(Error::NotFound(_))));
std::fs::remove_dir_all(&dir).ok();
}
#[cfg(target_os = "macos")]
#[test]
fn try_clone_file_clones_on_apfs_and_declines_an_existing_destination() {
let dir = scratch("clone-try");
let src = dir.join("src.node");
let dest = dir.join("dest.node");
std::fs::write(&src, fake_addon()).unwrap();
assert!(try_clone_file(&src, &dest).unwrap(), "fresh clone");
assert!(!try_clone_file(&src, &dest).unwrap());
std::fs::remove_dir_all(&dir).ok();
}
#[cfg(target_os = "macos")]
#[test]
fn copy_file_clones_a_compressed_source_on_apfs() {
let dir = scratch("copy-clone");
let src = dir.join("src.node");
let dest = dir.join("dest.node");
let content = fake_addon();
let wrote = compress_bytes(&src, &content, &Gate::any()).unwrap();
if !matches!(wrote, Outcome::Compressed { .. }) {
std::fs::remove_dir_all(&dir).ok();
return;
}
let out = copy_file(&src, &dest).unwrap();
assert_eq!(out, CopyOutcome::Cloned { compressed: true });
assert!(backend::is_already_compressed(&dest).unwrap());
assert_eq!(
std::fs::read(&dest).unwrap(),
content,
"bytes are identical"
);
std::fs::remove_dir_all(&dir).ok();
}
}