🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

decmpfs

Package Overview
Dependencies
Maintainers
0
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

decmpfs - cargo Package Compare versions

Comparing version
0.1.2
to
0.1.3
+492
src/macos/streaming.rs
use super::*;
pub(super) enum StreamingState {
Encoding(StreamingEncoding),
Plain(std::fs::File),
Closed,
}
pub(super) struct StreamingEncoding {
file: std::fs::File,
fork: std::io::BufWriter<std::fs::File>,
scratch: Vec<u8>,
partial: Vec<u8>,
offsets: Vec<u32>,
encoded_offset: usize,
}
/// Incremental macOS writer used by the public streaming API. Raw input is held
/// only until the current 64 KiB block is complete; winning LZFSE blocks land
/// directly in the named resource fork. If the fork stops winning, its completed
/// blocks are decoded into a plain sibling and subsequent input streams there.
pub(crate) struct StreamingWriter {
path: std::path::PathBuf,
expected_len: usize,
written: usize,
state: StreamingState,
complete: bool,
}
impl StreamingEncoding {
fn write_block(&mut self, raw: &[u8], expected_len: usize) -> Result<bool, Error> {
let Some(encoded) = compress_block_with_codec(raw, &mut self.scratch, Codec::Lzfse) else {
return Ok(false);
};
// Verify every encoder result while the matching raw block is still in
// memory. The final kernel oracle then only has to prove the decmpfs layout.
let mut decoded = vec![0u8; raw.len()];
let decoded_len = unsafe {
compression_decode_buffer(
decoded.as_mut_ptr(),
decoded.len(),
encoded.as_ptr(),
encoded.len(),
std::ptr::null_mut(),
Codec::Lzfse.algorithm(),
)
};
if decoded_len != raw.len() || decoded != raw {
return Ok(false);
}
let Some(next_offset) = self.encoded_offset.checked_add(encoded.len()) else {
return Ok(false);
};
if next_offset >= expected_len || next_offset > u32::MAX as usize {
return Ok(false);
}
use std::io::Write;
self.fork.write_all(&encoded).map_err(|source| Error::Io {
context: "write streaming resource-fork block",
source,
})?;
self.encoded_offset = next_offset;
self
.offsets
.push(u32::try_from(next_offset).map_err(|_| resource_fork_too_large())?);
Ok(true)
}
}
pub(super) fn streaming_fallback_path(path: &Path) -> std::path::PathBuf {
static FALLBACK_SEQ: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
let seq = FALLBACK_SEQ.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let name = path.file_name().map_or_else(
|| std::borrow::Cow::Borrowed("stream"),
|n| n.to_string_lossy(),
);
path.with_file_name(format!(".{name}.plain-{}-{seq}.tmp", std::process::id()))
}
pub(super) fn decode_streaming_prefix(
path: &Path,
encoding: &mut StreamingEncoding,
current: &[u8],
expected_len: usize,
) -> Result<(std::path::PathBuf, std::fs::File), Error> {
use std::io::{Read, Seek, Write};
encoding.fork.flush().map_err(|source| Error::Io {
context: "flush streaming resource fork",
source,
})?;
encoding
.fork
.get_ref()
.sync_all()
.map_err(|source| Error::Io {
context: "sync streaming resource fork",
source,
})?;
let fork_path = path.join("..namedfork").join("rsrc");
let mut fork = std::fs::File::open(fork_path).map_err(|source| Error::Io {
context: "open streaming resource fork for fallback",
source,
})?;
let fallback = streaming_fallback_path(path);
let mut plain = std::fs::OpenOptions::new()
.read(true)
.write(true)
.create_new(true)
.open(&fallback)
.map_err(|source| Error::Io {
context: "create streaming plain fallback",
source,
})?;
let decoded = (|| -> Result<(), Error> {
for (block_index, pair) in encoding.offsets.windows(2).enumerate() {
let start = pair[0] as u64;
let encoded_len = (pair[1] - pair[0]) as usize;
let mut encoded = vec![0u8; encoded_len];
fork
.seek(std::io::SeekFrom::Start(start))
.and_then(|_| fork.read_exact(&mut encoded))
.map_err(|source| Error::Io {
context: "read streaming resource fork for fallback",
source,
})?;
let raw_len = expected_len
.saturating_sub(block_index.saturating_mul(BLOCK))
.min(BLOCK);
let mut raw = vec![0u8; raw_len];
let raw_len = unsafe {
compression_decode_buffer(
raw.as_mut_ptr(),
raw.len(),
encoded.as_ptr(),
encoded.len(),
std::ptr::null_mut(),
Codec::Lzfse.algorithm(),
)
};
if raw_len != raw.len() {
return Err(Error::Io {
context: "decode streaming resource fork for fallback",
source: std::io::Error::from(std::io::ErrorKind::InvalidData),
});
}
plain.write_all(&raw).map_err(|source| Error::Io {
context: "write streaming plain fallback",
source,
})?;
}
plain.write_all(current).map_err(|source| Error::Io {
context: "write current streaming fallback block",
source,
})
})();
if let Err(err) = decoded {
drop(plain);
let _ = std::fs::remove_file(&fallback);
return Err(err);
}
Ok((fallback, plain))
}
pub(super) fn streaming_kernel_matches(
path: &Path,
encoding: &StreamingEncoding,
expected_len: usize,
) -> Result<bool, Error> {
use std::io::{Read, Seek};
let mut logical = match std::fs::File::open(path) {
Ok(file) => file,
Err(_) => return Ok(false),
};
let fork_path = path.join("..namedfork").join("rsrc");
let mut fork = std::fs::File::open(fork_path).map_err(|source| Error::Io {
context: "open finished streaming resource fork",
source,
})?;
for (block_index, pair) in encoding.offsets.windows(2).enumerate() {
let encoded_len = (pair[1] - pair[0]) as usize;
let mut encoded = vec![0u8; encoded_len];
fork
.seek(std::io::SeekFrom::Start(pair[0] as u64))
.and_then(|_| fork.read_exact(&mut encoded))
.map_err(|source| Error::Io {
context: "read finished streaming resource fork",
source,
})?;
let raw_len = expected_len
.saturating_sub(block_index.saturating_mul(BLOCK))
.min(BLOCK);
let mut decoded = vec![0u8; raw_len];
let decoded_len = unsafe {
compression_decode_buffer(
decoded.as_mut_ptr(),
decoded.len(),
encoded.as_ptr(),
encoded.len(),
std::ptr::null_mut(),
Codec::Lzfse.algorithm(),
)
};
if decoded_len != raw_len {
return Ok(false);
}
let mut kernel = vec![0u8; raw_len];
if logical.read_exact(&mut kernel).is_err() || kernel != decoded {
return Ok(false);
}
}
let mut extra = [0u8; 1];
Ok(logical.read(&mut extra).is_ok_and(|len| len == 0))
}
impl StreamingWriter {
pub(crate) fn new(path: &Path, expected_len: usize) -> Result<Self, Error> {
let num_blocks = expected_len.div_ceil(BLOCK).max(1);
let table_len = resource_fork_table_len(num_blocks)?;
if expected_len == 0 || table_len >= expected_len || table_len > u32::MAX as usize {
let file = std::fs::OpenOptions::new()
.read(true)
.write(true)
.create_new(true)
.open(path)
.map_err(|source| Error::Io {
context: "create streaming plain temp",
source,
})?;
return Ok(Self {
path: path.to_path_buf(),
expected_len,
written: 0,
state: StreamingState::Plain(file),
complete: false,
});
}
let file = std::fs::OpenOptions::new()
.read(true)
.write(true)
.create_new(true)
.open(path)
.map_err(|source| Error::Io {
context: "create streaming decmpfs temp",
source,
})?;
let fork_file = (|| -> Result<std::fs::File, Error> {
let fork_path = path.join("..namedfork").join("rsrc");
let mut fork_file = std::fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(true)
.open(fork_path)
.map_err(|source| Error::Io {
context: "open streaming resource fork",
source,
})?;
use std::io::Seek;
fork_file
.set_len(table_len as u64)
.map_err(|source| Error::Io {
context: "reserve streaming resource-fork table",
source,
})?;
fork_file
.seek(std::io::SeekFrom::Start(table_len as u64))
.map_err(|source| Error::Io {
context: "seek streaming resource-fork payload",
source,
})?;
Ok(fork_file)
})();
let fork_file = match fork_file {
Ok(fork_file) => fork_file,
Err(error) => {
drop(file);
let _ = std::fs::remove_file(path);
return Err(error);
}
};
let scratch_len = unsafe { compression_encode_scratch_buffer_size(Codec::Lzfse.algorithm()) };
Ok(Self {
path: path.to_path_buf(),
expected_len,
written: 0,
state: StreamingState::Encoding(StreamingEncoding {
file,
fork: std::io::BufWriter::with_capacity(1 << 20, fork_file),
scratch: vec![0u8; scratch_len],
partial: Vec::with_capacity(BLOCK),
offsets: vec![u32::try_from(table_len).map_err(|_| resource_fork_too_large())?],
encoded_offset: table_len,
}),
complete: false,
})
}
fn switch_to_plain(&mut self, current: &[u8]) -> Result<(), Error> {
let StreamingState::Encoding(mut encoding) =
std::mem::replace(&mut self.state, StreamingState::Closed)
else {
return Err(Error::Io {
context: "switch streaming writer to plain",
source: std::io::Error::from(std::io::ErrorKind::InvalidInput),
});
};
let (fallback, mut plain) =
decode_streaming_prefix(&self.path, &mut encoding, current, self.expected_len)?;
drop(encoding);
if let Err(source) = std::fs::remove_file(&self.path) {
let _ = std::fs::remove_file(&fallback);
return Err(Error::Io {
context: "remove streaming decmpfs temp",
source,
});
}
if let Err(source) = std::fs::rename(&fallback, &self.path) {
let _ = std::fs::remove_file(&fallback);
return Err(Error::Io {
context: "adopt streaming plain fallback",
source,
});
}
use std::io::Seek;
plain
.seek(std::io::SeekFrom::End(0))
.map_err(|source| Error::Io {
context: "seek streaming plain fallback",
source,
})?;
self.state = StreamingState::Plain(plain);
Ok(())
}
pub(crate) fn write_all(&mut self, mut input: &[u8]) -> Result<(), Error> {
let next_written = self
.written
.checked_add(input.len())
.filter(|&len| len <= self.expected_len)
.ok_or_else(|| Error::Io {
context: "stream exceeds expected length",
source: std::io::Error::from(std::io::ErrorKind::InvalidData),
})?;
while !input.is_empty() {
match &mut self.state {
StreamingState::Plain(file) => {
use std::io::Write;
file.write_all(input).map_err(|source| Error::Io {
context: "write streaming plain temp",
source,
})?;
input = &[];
}
StreamingState::Encoding(encoding) => {
let take = (BLOCK - encoding.partial.len()).min(input.len());
encoding.partial.extend_from_slice(&input[..take]);
input = &input[take..];
if encoding.partial.len() == BLOCK {
let block = std::mem::replace(&mut encoding.partial, Vec::with_capacity(BLOCK));
if !encoding.write_block(&block, self.expected_len)? {
self.switch_to_plain(&block)?;
}
}
}
StreamingState::Closed => {
return Err(Error::Io {
context: "write closed streaming writer",
source: std::io::Error::from(std::io::ErrorKind::BrokenPipe),
});
}
}
}
self.written = next_written;
Ok(())
}
pub(crate) fn finish(&mut self) -> Result<bool, Error> {
if self.written != self.expected_len {
return Err(Error::Io {
context: "finish incomplete streaming writer",
source: std::io::Error::from(std::io::ErrorKind::UnexpectedEof),
});
}
let partial = match &mut self.state {
StreamingState::Encoding(encoding) if !encoding.partial.is_empty() => Some(
std::mem::replace(&mut encoding.partial, Vec::with_capacity(BLOCK)),
),
_ => None,
};
if let Some(block) = partial {
let won = match &mut self.state {
StreamingState::Encoding(encoding) => encoding.write_block(&block, self.expected_len)?,
_ => false,
};
if !won {
self.switch_to_plain(&block)?;
}
}
let compressed = match std::mem::replace(&mut self.state, StreamingState::Closed) {
StreamingState::Plain(file) => {
file.sync_all().map_err(|source| Error::Io {
context: "sync streaming plain temp",
source,
})?;
false
}
StreamingState::Encoding(mut encoding) => {
use std::io::{Seek, Write};
let mut table = Vec::with_capacity(encoding.offsets.len() * std::mem::size_of::<u32>());
for offset in &encoding.offsets {
table.extend_from_slice(&offset.to_le_bytes());
}
encoding
.fork
.seek(std::io::SeekFrom::Start(0))
.and_then(|_| encoding.fork.write_all(&table))
.and_then(|_| encoding.fork.flush())
.map_err(|source| Error::Io {
context: "finish streaming resource fork",
source,
})?;
encoding
.fork
.get_ref()
.sync_all()
.map_err(|source| Error::Io {
context: "sync finished streaming resource fork",
source,
})?;
let cpath = cstring(&self.path)?;
setxattr(
&cpath,
c"com.apple.decmpfs",
&decmpfs_header(Codec::Lzfse, self.expected_len),
)?;
if unsafe { libc::fchflags(encoding.file.as_raw_fd(), UF_COMPRESSED) } != 0 {
return Err(io("fchflags streaming temp"));
}
encoding.file.sync_all().map_err(|source| Error::Io {
context: "sync streaming decmpfs temp",
source,
})?;
if streaming_kernel_matches(&self.path, &encoding, self.expected_len)? {
true
} else {
let (fallback, plain) =
decode_streaming_prefix(&self.path, &mut encoding, &[], self.expected_len)?;
drop(encoding);
std::fs::remove_file(&self.path).map_err(|source| Error::Io {
context: "remove failed streaming decmpfs oracle",
source,
})?;
if let Err(source) = std::fs::rename(&fallback, &self.path) {
let _ = std::fs::remove_file(&fallback);
return Err(Error::Io {
context: "publish streaming oracle fallback",
source,
});
}
plain.sync_all().map_err(|source| Error::Io {
context: "sync streaming oracle fallback",
source,
})?;
false
}
}
StreamingState::Closed => {
return Err(Error::Io {
context: "finish closed streaming writer",
source: std::io::Error::from(std::io::ErrorKind::BrokenPipe),
});
}
};
self.complete = true;
Ok(compressed)
}
}
impl Drop for StreamingWriter {
fn drop(&mut self) {
if !self.complete {
self.state = StreamingState::Closed;
let _ = std::fs::remove_file(&self.path);
}
}
}
use super::*;
// The kernel-roundtrip oracle. decmpfs is undocumented — the only proof the
// format is right is that a normal read() returns identical bytes after apply.
#[test]
fn kernel_roundtrips_decmpfs() {
let dir = std::env::temp_dir().join(format!("decmpfs-oracle-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("f.bin");
// > 1 block (64 KiB) of compressible data, so the offset table + LZVN blocks
// are both exercised.
let mut raw = Vec::new();
let pat = b"the quick brown fox decmpfs lzvn resource-fork oracle line ";
while raw.len() < 2_000_000 {
raw.extend_from_slice(pat);
}
std::fs::write(&path, &raw).unwrap();
assert!(
matches!(detect(&path).unwrap(), Support::Supported),
"temp dir is local APFS/HFS+"
);
apply_inplace(&path, &raw).unwrap();
assert!(is_already_compressed(&path).unwrap(), "UF_COMPRESSED set");
assert_eq!(
compressed_on_disk(&path).unwrap(),
Some(true),
"reports compressed"
);
// THE ORACLE: the kernel decompresses our resource fork on read().
assert_eq!(
std::fs::read(&path).unwrap(),
raw,
"kernel read-back must equal the original bytes"
);
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn incremental_writer_streams_lzfse_blocks_into_a_kernel_readable_file() {
let dir = std::env::temp_dir().join(format!("decmpfs-incremental-oracle-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("model.bin");
let raw = b"incremental lzfse resource fork ".repeat((2 << 20) / 34 + 1);
let mut writer = StreamingWriter::new(&path, raw.len()).unwrap();
for chunk in raw.chunks(17_003) {
writer.write_all(chunk).unwrap();
}
assert!(writer.finish().unwrap(), "compressible stream must win");
assert!(is_already_compressed(&path).unwrap());
assert_eq!(std::fs::read(&path).unwrap(), raw);
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn incremental_writer_reconstructs_plain_bytes_when_compression_loses() {
let dir = std::env::temp_dir().join(format!(
"decmpfs-incremental-fallback-{}",
std::process::id()
));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("random.bin");
let mut raw = Vec::with_capacity(2 << 20);
let mut x: u64 = 0x9e37_79b9_7f4a_7c15;
while raw.len() < (2 << 20) {
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
raw.extend_from_slice(&x.to_le_bytes());
}
let mut writer = StreamingWriter::new(&path, raw.len()).unwrap();
for chunk in raw.chunks(17_003) {
writer.write_all(chunk).unwrap();
}
assert!(
!writer.finish().unwrap(),
"incompressible stream stays plain"
);
assert!(!is_already_compressed(&path).unwrap());
assert_eq!(std::fs::read(&path).unwrap(), raw);
std::fs::remove_dir_all(&dir).ok();
}
// Opt-in perf probe (ignored in CI — timing is machine-specific). Reports the
// decmpfs write time for a ~40 MiB addon; run serial vs parallel with
// cargo test -p decmpfs write_time -- --ignored --nocapture
// DECMPFS_SERIAL=1 cargo test -p decmpfs write_time -- --ignored --nocapture
#[test]
#[ignore]
fn write_time_probe() {
let dir = std::env::temp_dir().join(format!("decmpfs-time-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("addon.node");
let mut raw: Vec<u8> = Vec::with_capacity(40 << 20);
let mut x: u64 = 0x9e37_79b9_7f4a_7c15;
while raw.len() < (40 << 20) {
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
raw.extend_from_slice(&x.to_le_bytes());
raw.extend_from_slice(b"native addon .node text segment padding ");
}
if !matches!(detect(&dir), Ok(Support::Supported)) {
std::fs::remove_dir_all(&dir).ok();
return;
}
let cores = std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(1);
let serial = std::env::var_os("DECMPFS_SERIAL").is_some();
let start = std::time::Instant::now();
apply_bytes(&path, &raw, None).unwrap();
let ms = start.elapsed().as_secs_f64() * 1e3;
eprintln!(
"decmpfs write {}MiB — {} ({} cores): {:.1} ms",
raw.len() >> 20,
if serial { "serial" } else { "parallel" },
cores,
ms,
);
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn detect_and_flags_error_on_a_missing_path() {
let p = std::path::Path::new("/no/such/decmpfs/path/x.bin");
assert!(detect(p).is_err(), "statfs of a missing path errors");
assert!(
is_already_compressed(p).is_err(),
"lstat of a missing path errors"
);
}
#[test]
fn apply_inplace_errors_when_the_file_cannot_be_read() {
// A 0-perm file: apply_inplace's initial read fails before any apply. Root
// bypasses mode bits, so skip there.
if unsafe { libc::geteuid() } == 0 {
return;
}
use std::os::unix::fs::PermissionsExt;
let dir = std::env::temp_dir().join(format!("decmpfs-noread-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("f.bin");
let content = b"\x7fELF unreadable";
std::fs::write(&path, content).unwrap();
std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o000)).unwrap();
// apply_inplace no longer reads the file (the caller passes the snapshot it
// already holds); the fail-soft guard is now the W_OK access check, which
// rejects a file we cannot write before the temp+rename would replace it.
let out = apply_inplace(&path, content);
std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o644)).ok();
assert!(matches!(
out,
Err(Error::Io {
context: "access",
..
})
));
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn setxattr_errors_on_a_missing_path() {
let out = setxattr(c"/no/such/decmpfs/path", c"com.apple.decmpfs", b"x");
assert!(matches!(
out,
Err(Error::Io {
context: "setxattr",
..
})
));
}
#[test]
fn compress_block_returns_none_for_empty_input() {
// libcompression encodes zero bytes to nothing → the n == 0 guard returns None.
let scratch_len = unsafe { compression_encode_scratch_buffer_size(COMPRESSION_LZVN) };
let mut scratch = vec![0u8; scratch_len];
assert!(compress_block(b"", &mut scratch).is_none());
}
#[test]
fn build_resource_fork_zero_length_is_no_gain() {
assert!(
build_resource_fork(&[]).unwrap().is_none(),
"a resource fork cannot make an empty file smaller"
);
}
#[test]
fn streaming_threshold_keeps_vite_native_addons_on_the_fast_path() {
// The largest Darwin ARM64 addon in the 2026-07-16 Vite-family sample was
// SWC at 36.563 MiB. The complete observed set must stay comfortably below
// the in-memory cutoff, while the first byte beyond it streams.
assert!(!should_stream_resource_fork(37 << 20, STREAMING_THRESHOLD));
assert!(!should_stream_resource_fork(
STREAMING_THRESHOLD,
STREAMING_THRESHOLD
));
assert!(should_stream_resource_fork(
STREAMING_THRESHOLD + 1,
STREAMING_THRESHOLD
));
}
#[test]
fn kernel_roundtrips_forced_streaming_lzfse() {
let dir = std::env::temp_dir().join(format!("decmpfs-streaming-oracle-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("f.bin");
let raw = b"streamed lzfse decmpfs resource fork oracle ".repeat((2 << 20) / 46 + 1);
std::fs::write(&path, &raw).unwrap();
if matches!(detect(&path).unwrap(), Support::Supported) {
apply_bytes_with_streaming_threshold(&path, &raw, None, 0).unwrap();
assert!(is_already_compressed(&path).unwrap(), "UF_COMPRESSED set");
assert_eq!(
std::fs::read(&path).unwrap(),
raw,
"kernel read-back must decode the streamed type-12 resource fork"
);
let cpath = cstring(&path).unwrap();
let mut header = [0u8; 16];
let len = unsafe {
libc::getxattr(
cpath.as_ptr(),
c"com.apple.decmpfs".as_ptr(),
header.as_mut_ptr().cast(),
header.len(),
0,
XATTR_NOFOLLOW | 0x0020, // XATTR_SHOWCOMPRESSION
)
};
assert_eq!(len, header.len() as isize);
assert_eq!(u32::from_le_bytes(header[4..8].try_into().unwrap()), 12);
}
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn in_memory_path_falls_back_to_lzfse_when_lzvn_has_no_gain() {
// Skewed symbol frequencies give LZFSE's entropy coder something to exploit
// without manufacturing the repeated strings that LZVN specializes in.
let mut raw = Vec::with_capacity(1 << 20);
let mut x: u64 = 0x9e37_79b9_7f4a_7c15;
while raw.len() < raw.capacity() {
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
raw.push(if x.is_multiple_of(4) {
0
} else {
(x >> 32) as u8
});
}
assert!(
build_resource_fork_with_codec(&raw, Codec::Lzvn)
.unwrap()
.is_none(),
"fixture must reach the fallback"
);
let candidate = build_in_memory_resource_fork(&raw)
.unwrap()
.expect("LZFSE should exploit the skewed symbols");
assert_eq!(candidate.codec, Codec::Lzfse);
assert!(candidate.bytes.len() < raw.len());
}
#[test]
fn build_resource_fork_last_offset_equals_length() {
// Invariant across sizes that actually encode: the final table offset equals
// the total blob length. (Tiny/incompressible inputs return None — the codec
// declines — which is a separate, correct path.)
for size in [512usize, BLOCK, BLOCK + 1, BLOCK * 3 + 7] {
let raw = vec![0x41u8; size];
let Some(rf) = build_resource_fork(&raw).unwrap() else {
continue;
};
let num_blocks = size.div_ceil(BLOCK);
let last_idx = num_blocks * 4; // offset[num_blocks] is the last entry
let last = u32::from_le_bytes(rf[last_idx..last_idx + 4].try_into().unwrap()) as usize;
assert_eq!(last, rf.len(), "size {size}: last offset != buffer length");
}
}
#[test]
fn cstring_rejects_an_interior_nul() {
use std::os::unix::ffi::OsStrExt;
let p = std::path::Path::new(std::ffi::OsStr::from_bytes(b"a\0b"));
assert!(cstring(p).is_err());
}
#[test]
fn detect_rejects_a_non_apfs_filesystem() {
// /dev is devfs (local, but not apfs/hfs) → Unsupported(Filesystem).
assert!(matches!(
detect(std::path::Path::new("/dev")),
Ok(Support::Unsupported(UnsupportedReason::Filesystem))
));
}
#[test]
fn classify_fs_covers_every_branch() {
// Non-local (e.g. a network mount) — no real mount needed.
assert!(matches!(
classify_fs(false, b"nfs"),
Support::Unsupported(UnsupportedReason::NetworkOrOverlay)
));
assert!(matches!(classify_fs(true, b"apfs"), Support::Supported));
assert!(matches!(classify_fs(true, b"hfs"), Support::Supported));
assert!(matches!(
classify_fs(true, b"ext4"),
Support::Unsupported(UnsupportedReason::Filesystem)
));
}
#[test]
fn resource_fork_plan_accepts_raw_files_beyond_the_old_limit() {
// The raw byte count is stored as u64. Only resource-fork offsets are u32,
// so a >3.9 GB input is valid whenever its encoded fork fits in u32.
let raw_len = 4_100_000_000usize;
let num_blocks = raw_len.div_ceil(BLOCK);
assert!(matches!(
plan_resource_fork(raw_len, num_blocks, 3_000_000_000).unwrap(),
ResourceForkPlan::Compressed { .. }
));
}
#[test]
fn resource_fork_plan_accepts_raw_files_beyond_four_gib_when_the_fork_fits() {
let raw_len = 5_000_000_000usize;
let num_blocks = raw_len.div_ceil(BLOCK);
assert!(matches!(
plan_resource_fork(raw_len, num_blocks, 3_000_000_000).unwrap(),
ResourceForkPlan::Compressed { .. }
));
}
#[test]
fn resource_fork_plan_rejects_a_compressed_fork_past_u32() {
let raw_len = 5_000_000_000usize;
let num_blocks = raw_len.div_ceil(BLOCK);
match plan_resource_fork(raw_len, num_blocks, 4_400_000_000).unwrap_err() {
Error::Io { source, .. } => assert_eq!(source.raw_os_error(), Some(libc::EFBIG)),
other => panic!("expected EFBIG Io, got {other:?}"),
}
}
#[test]
fn gemini_nano_lzvn_resource_fork_is_no_gain() {
// Chrome 150's v3Nano weights.bin measured with this exact 64 KiB LZVN
// encoder: the encoded blocks expand enough to cross the u32 fork ceiling.
assert_eq!(
plan_resource_fork(4_269_932_544, 65_154, 4_364_775_458).unwrap(),
ResourceForkPlan::Plain
);
}
#[test]
fn gemini_nano_lzfse_resource_fork_fits_and_wins() {
// The streamed type-12 run encoded the same 65,154 blocks to this payload;
// with its 260,620-byte offset table the fork is safely below u32::MAX.
assert_eq!(
plan_resource_fork(4_269_932_544, 65_154, 3_598_249_560).unwrap(),
ResourceForkPlan::Compressed {
table_len: 260_620,
total_len: 3_598_510_180,
}
);
}
// Incompressible data → LZVN would expand the resource fork, so keep an
// ordinary data fork. The bytes and compression-state signal must agree.
#[test]
fn kernel_roundtrips_incompressible_blocks() {
let dir = std::env::temp_dir().join(format!("decmpfs-raw-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("f.bin");
let mut raw = Vec::new();
let mut x: u32 = 0x9e37_79b9;
while raw.len() < 200_000 {
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
raw.extend_from_slice(&x.to_le_bytes());
}
std::fs::write(&path, &raw).unwrap();
if matches!(detect(&path).unwrap(), Support::Supported) {
assert!(matches!(
crate::compress_file(&path).unwrap(),
crate::Outcome::NoGain { .. }
));
assert_eq!(
std::fs::read(&path).unwrap(),
raw,
"plain fallback reads back identically"
);
assert!(
!is_already_compressed(&path).unwrap(),
"no-gain input must not carry UF_COMPRESSED"
);
}
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn apply_bytes_preserves_ownership_of_an_overwritten_file() {
// Non-root exercises the chown path over an existing file — owner is our own
// uid, so preservation is a no-op we assert stays stable + non-corrupting.
// The root path (a file owned by a different uid) is verified in CI.
let dir = std::env::temp_dir().join(format!("decmpfs-own-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("f");
std::fs::write(&path, vec![0u8; 4096]).unwrap();
if !matches!(detect(&path), Ok(Support::Supported)) {
std::fs::remove_dir_all(&dir).ok();
return;
}
use std::os::unix::fs::MetadataExt;
let before_uid = std::fs::metadata(&path).unwrap().uid();
let content = vec![0xABu8; 8192];
apply_bytes(&path, &content, None).unwrap();
let meta = std::fs::metadata(&path).unwrap();
assert_eq!(meta.uid(), before_uid, "owner preserved across the rewrite");
assert_eq!(std::fs::read(&path).unwrap(), content, "content intact");
std::fs::remove_dir_all(&dir).ok();
}
use super::*;
fn scratch(tag: &str) -> std::path::PathBuf {
let dir = std::env::temp_dir().join(format!("decmpfs-{tag}-{}", std::process::id()));
// A pid-recycled leftover FILE at this path makes create_dir_all fail
// with AlreadyExists; clear it so the scratch dir always materializes.
let _ = std::fs::remove_file(&dir);
std::fs::create_dir_all(&dir).unwrap();
dir
}
// A minimal native-magic payload (ELF header) so a backend will attempt to
// compress it rather than skip a trivially-small file.
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() {
// "/" has no parent directory → the no-parent guard fires before any write.
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() {
// probe never errors on an existing path — it returns a Support.
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() {
// /dev/null exists but devfs has no compression backend → Unsupported.
let out = compress_file(std::path::Path::new("/dev/null"));
assert!(
matches!(out, Ok(Outcome::Unsupported { .. })),
"devfs → Unsupported, got {out:?}"
);
}
// APFS is always a compressing FS, so macOS exercises the full success path:
// compress_file → apply_guarded → backend::apply_inplace → verify → classify.
#[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:?}"
);
// Transparent: the kernel hands back the exact original bytes.
assert_eq!(std::fs::read(&path).unwrap(), fake_addon());
// Idempotent: a second pass detects it's already compressed.
assert!(matches!(
compress_file(&path),
Ok(Outcome::AlreadyCompressed { .. })
));
std::fs::remove_dir_all(&dir).ok();
}
// compress_bytes one-pass: write bytes directly as an APFS-compressed file with
// no pre-existing original, then prove the kernel hands the exact bytes back.
#[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();
// No file at `path` yet — compress_bytes creates it in one pass.
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");
// Transparent: kernel read-back equals the bytes we asked to store.
assert_eq!(std::fs::read(&path).unwrap(), content);
// It really carries the compression flag (not a plain fallback write).
assert!(matches!(
compress_file(&path),
Ok(Outcome::AlreadyCompressed { .. })
));
std::fs::remove_dir_all(&dir).ok();
}
// A file the gate excludes is written PLAIN (never compressed) and reports
// Skipped(GateExcluded) — the install still gets the file.
#[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(); // **/*.node
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() {
// A non-compressing FS (devfs) → plain write, Unsupported Outcome, file lands.
// /dev isn't writable by us, so target a temp path but force the gate to pass;
// temp on macOS is APFS (compresses) — instead assert the API never errors and
// the bytes land for the supported case is covered above. Here just exercise
// the gate-passing path lands bytes on any unix temp.
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() {
// On a compressing FS a read-only file can't be opened rw → fail-soft turns the
// EACCES into Skipped(PermissionDenied). Root bypasses mode bits, so skip there.
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();
}
// An existing target exercises the `path.exists()` probe-target branch and the
// fresh-inode rename that replaces the old contents.
#[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();
}
// `path` is an existing directory: the backend builds its temp then can't rename
// a file over a directory, and the plain-write fallback can't either → a hard
// `Err` (genuine I/O failure), never a corrupt success. Exercises the backend
// rename-error cleanup and the `Err(_)` fallback arm of compress_bytes.
#[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"
);
// Where the FS actually compressed (APFS / btrfs / NTFS), stat must reflect
// it; on an unsupported FS the outcome isn't Compressed and we only assert
// the size + content invariants above.
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();
}
// A read-only parent dir: the guarded backend write hits EACCES (classify_skip →
// Skipped), then the plain-write fallback also can't write → `Err`. Root bypasses
// mode bits, so skip there.
#[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());
// Restore write perms so the tree can be cleaned up.
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();
}
// The `Support::AlreadyCompressed`-from-detect arm: a real macOS detect never
// returns it (it reports already-compressed via the apply path), so a fake drives
// it. Needs a real file for the on-disk-bytes read.
#[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();
}
// detect → Unsupported: the bytes still land via a plain write, Outcome::Unsupported.
#[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();
}
// detect → Supported but the guarded apply is skipped (faked permission failure):
// the bytes land via a plain write, Outcome::Skipped(IntegrityRevert).
#[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();
}
/// A fallback fake: no clone path (trait default), reports the source
/// compressed, and its apply actually writes — so the guarded one-pass copy
/// arm runs end to end and classifies via the backend signal.
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() {
// mockall MockBackend mocks the fs backend seam (no real syscalls); tempfile
// gives a real, isolated, auto-cleaned src fixture. clone_file → true
// short-circuits copy_file_with to the zero-cost Cloned outcome.
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();
// A directory at `dest` makes the replace step's remove_file fail.
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");
// clonefile refuses an existing destination — reported as cannot-clone,
// never an error.
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();
// Only meaningful when the scratch volume actually compressed the source.
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();
}
+1
-1
{
"git": {
"sha1": "9e4134a23d4805e2e2c4b739f33847728f600dd4"
"sha1": "57e9795d90bcd9acbe224a968318e759f05d396b"
},
"path_in_vcs": "crates/decmpfs"
}

@@ -86,3 +86,3 @@ # This file is automatically @generated by Cargo.

name = "decmpfs"
version = "0.1.2"
version = "0.1.3"
dependencies = [

@@ -89,0 +89,0 @@ "libc",

@@ -15,3 +15,3 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO

name = "decmpfs"
version = "0.1.2"
version = "0.1.3"
build = "build.rs"

@@ -34,3 +34,3 @@ autolib = false

license = "MIT"
repository = "https://github.com/decmpfs/decmpfs"
repository = "https://github.com/SocketDev/decmpfs"

@@ -37,0 +37,0 @@ [features]

@@ -620,664 +620,2 @@ //! `decmpfs` — apply the operating system's transparent per-file compression to a file

#[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()));
// A pid-recycled leftover FILE at this path makes create_dir_all fail
// with AlreadyExists; clear it so the scratch dir always materializes.
let _ = std::fs::remove_file(&dir);
std::fs::create_dir_all(&dir).unwrap();
dir
}
// A minimal native-magic payload (ELF header) so a backend will attempt to
// compress it rather than skip a trivially-small file.
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() {
// "/" has no parent directory → the no-parent guard fires before any write.
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() {
// probe never errors on an existing path — it returns a Support.
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() {
// /dev/null exists but devfs has no compression backend → Unsupported.
let out = compress_file(std::path::Path::new("/dev/null"));
assert!(
matches!(out, Ok(Outcome::Unsupported { .. })),
"devfs → Unsupported, got {out:?}"
);
}
// APFS is always a compressing FS, so macOS exercises the full success path:
// compress_file → apply_guarded → backend::apply_inplace → verify → classify.
#[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:?}"
);
// Transparent: the kernel hands back the exact original bytes.
assert_eq!(std::fs::read(&path).unwrap(), fake_addon());
// Idempotent: a second pass detects it's already compressed.
assert!(matches!(
compress_file(&path),
Ok(Outcome::AlreadyCompressed { .. })
));
std::fs::remove_dir_all(&dir).ok();
}
// compress_bytes one-pass: write bytes directly as an APFS-compressed file with
// no pre-existing original, then prove the kernel hands the exact bytes back.
#[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();
// No file at `path` yet — compress_bytes creates it in one pass.
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");
// Transparent: kernel read-back equals the bytes we asked to store.
assert_eq!(std::fs::read(&path).unwrap(), content);
// It really carries the compression flag (not a plain fallback write).
assert!(matches!(
compress_file(&path),
Ok(Outcome::AlreadyCompressed { .. })
));
std::fs::remove_dir_all(&dir).ok();
}
// A file the gate excludes is written PLAIN (never compressed) and reports
// Skipped(GateExcluded) — the install still gets the file.
#[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(); // **/*.node
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() {
// A non-compressing FS (devfs) → plain write, Unsupported Outcome, file lands.
// /dev isn't writable by us, so target a temp path but force the gate to pass;
// temp on macOS is APFS (compresses) — instead assert the API never errors and
// the bytes land for the supported case is covered above. Here just exercise
// the gate-passing path lands bytes on any unix temp.
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() {
// On a compressing FS a read-only file can't be opened rw → fail-soft turns the
// EACCES into Skipped(PermissionDenied). Root bypasses mode bits, so skip there.
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();
}
// An existing target exercises the `path.exists()` probe-target branch and the
// fresh-inode rename that replaces the old contents.
#[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();
}
// `path` is an existing directory: the backend builds its temp then can't rename
// a file over a directory, and the plain-write fallback can't either → a hard
// `Err` (genuine I/O failure), never a corrupt success. Exercises the backend
// rename-error cleanup and the `Err(_)` fallback arm of compress_bytes.
#[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"
);
// Where the FS actually compressed (APFS / btrfs / NTFS), stat must reflect
// it; on an unsupported FS the outcome isn't Compressed and we only assert
// the size + content invariants above.
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();
}
// A read-only parent dir: the guarded backend write hits EACCES (classify_skip →
// Skipped), then the plain-write fallback also can't write → `Err`. Root bypasses
// mode bits, so skip there.
#[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());
// Restore write perms so the tree can be cleaned up.
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();
}
// The `Support::AlreadyCompressed`-from-detect arm: a real macOS detect never
// returns it (it reports already-compressed via the apply path), so a fake drives
// it. Needs a real file for the on-disk-bytes read.
#[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();
}
// detect → Unsupported: the bytes still land via a plain write, Outcome::Unsupported.
#[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();
}
// detect → Supported but the guarded apply is skipped (faked permission failure):
// the bytes land via a plain write, Outcome::Skipped(IntegrityRevert).
#[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();
}
/// A fallback fake: no clone path (trait default), reports the source
/// compressed, and its apply actually writes — so the guarded one-pass copy
/// arm runs end to end and classifies via the backend signal.
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() {
// mockall MockBackend mocks the fs backend seam (no real syscalls); tempfile
// gives a real, isolated, auto-cleaned src fixture. clone_file → true
// short-circuits copy_file_with to the zero-cost Cloned outcome.
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();
// A directory at `dest` makes the replace step's remove_file fail.
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");
// clonefile refuses an existing destination — reported as cannot-clone,
// never an error.
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();
// Only meaningful when the scratch volume actually compressed the source.
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();
}
}
mod tests;

@@ -472,493 +472,6 @@ //! macOS backend — APFS/HFS+ decmpfs transparent compression.

enum StreamingState {
Encoding(StreamingEncoding),
Plain(std::fs::File),
Closed,
}
#[path = "macos/streaming.rs"]
mod streaming;
pub(crate) use streaming::StreamingWriter;
struct StreamingEncoding {
file: std::fs::File,
fork: std::io::BufWriter<std::fs::File>,
scratch: Vec<u8>,
partial: Vec<u8>,
offsets: Vec<u32>,
encoded_offset: usize,
}
/// Incremental macOS writer used by the public streaming API. Raw input is held
/// only until the current 64 KiB block is complete; winning LZFSE blocks land
/// directly in the named resource fork. If the fork stops winning, its completed
/// blocks are decoded into a plain sibling and subsequent input streams there.
pub(crate) struct StreamingWriter {
path: std::path::PathBuf,
expected_len: usize,
written: usize,
state: StreamingState,
complete: bool,
}
impl StreamingEncoding {
fn write_block(&mut self, raw: &[u8], expected_len: usize) -> Result<bool, Error> {
let Some(encoded) = compress_block_with_codec(raw, &mut self.scratch, Codec::Lzfse) else {
return Ok(false);
};
// Verify every encoder result while the matching raw block is still in
// memory. The final kernel oracle then only has to prove the decmpfs layout.
let mut decoded = vec![0u8; raw.len()];
let decoded_len = unsafe {
compression_decode_buffer(
decoded.as_mut_ptr(),
decoded.len(),
encoded.as_ptr(),
encoded.len(),
std::ptr::null_mut(),
Codec::Lzfse.algorithm(),
)
};
if decoded_len != raw.len() || decoded != raw {
return Ok(false);
}
let Some(next_offset) = self.encoded_offset.checked_add(encoded.len()) else {
return Ok(false);
};
if next_offset >= expected_len || next_offset > u32::MAX as usize {
return Ok(false);
}
use std::io::Write;
self.fork.write_all(&encoded).map_err(|source| Error::Io {
context: "write streaming resource-fork block",
source,
})?;
self.encoded_offset = next_offset;
self
.offsets
.push(u32::try_from(next_offset).map_err(|_| resource_fork_too_large())?);
Ok(true)
}
}
fn streaming_fallback_path(path: &Path) -> std::path::PathBuf {
static FALLBACK_SEQ: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
let seq = FALLBACK_SEQ.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let name = path.file_name().map_or_else(
|| std::borrow::Cow::Borrowed("stream"),
|n| n.to_string_lossy(),
);
path.with_file_name(format!(".{name}.plain-{}-{seq}.tmp", std::process::id()))
}
fn decode_streaming_prefix(
path: &Path,
encoding: &mut StreamingEncoding,
current: &[u8],
expected_len: usize,
) -> Result<(std::path::PathBuf, std::fs::File), Error> {
use std::io::{Read, Seek, Write};
encoding.fork.flush().map_err(|source| Error::Io {
context: "flush streaming resource fork",
source,
})?;
encoding
.fork
.get_ref()
.sync_all()
.map_err(|source| Error::Io {
context: "sync streaming resource fork",
source,
})?;
let fork_path = path.join("..namedfork").join("rsrc");
let mut fork = std::fs::File::open(fork_path).map_err(|source| Error::Io {
context: "open streaming resource fork for fallback",
source,
})?;
let fallback = streaming_fallback_path(path);
let mut plain = std::fs::OpenOptions::new()
.read(true)
.write(true)
.create_new(true)
.open(&fallback)
.map_err(|source| Error::Io {
context: "create streaming plain fallback",
source,
})?;
let decoded = (|| -> Result<(), Error> {
for (block_index, pair) in encoding.offsets.windows(2).enumerate() {
let start = pair[0] as u64;
let encoded_len = (pair[1] - pair[0]) as usize;
let mut encoded = vec![0u8; encoded_len];
fork
.seek(std::io::SeekFrom::Start(start))
.and_then(|_| fork.read_exact(&mut encoded))
.map_err(|source| Error::Io {
context: "read streaming resource fork for fallback",
source,
})?;
let raw_len = expected_len
.saturating_sub(block_index.saturating_mul(BLOCK))
.min(BLOCK);
let mut raw = vec![0u8; raw_len];
let raw_len = unsafe {
compression_decode_buffer(
raw.as_mut_ptr(),
raw.len(),
encoded.as_ptr(),
encoded.len(),
std::ptr::null_mut(),
Codec::Lzfse.algorithm(),
)
};
if raw_len != raw.len() {
return Err(Error::Io {
context: "decode streaming resource fork for fallback",
source: std::io::Error::from(std::io::ErrorKind::InvalidData),
});
}
plain.write_all(&raw).map_err(|source| Error::Io {
context: "write streaming plain fallback",
source,
})?;
}
plain.write_all(current).map_err(|source| Error::Io {
context: "write current streaming fallback block",
source,
})
})();
if let Err(err) = decoded {
drop(plain);
let _ = std::fs::remove_file(&fallback);
return Err(err);
}
Ok((fallback, plain))
}
fn streaming_kernel_matches(
path: &Path,
encoding: &StreamingEncoding,
expected_len: usize,
) -> Result<bool, Error> {
use std::io::{Read, Seek};
let mut logical = match std::fs::File::open(path) {
Ok(file) => file,
Err(_) => return Ok(false),
};
let fork_path = path.join("..namedfork").join("rsrc");
let mut fork = std::fs::File::open(fork_path).map_err(|source| Error::Io {
context: "open finished streaming resource fork",
source,
})?;
for (block_index, pair) in encoding.offsets.windows(2).enumerate() {
let encoded_len = (pair[1] - pair[0]) as usize;
let mut encoded = vec![0u8; encoded_len];
fork
.seek(std::io::SeekFrom::Start(pair[0] as u64))
.and_then(|_| fork.read_exact(&mut encoded))
.map_err(|source| Error::Io {
context: "read finished streaming resource fork",
source,
})?;
let raw_len = expected_len
.saturating_sub(block_index.saturating_mul(BLOCK))
.min(BLOCK);
let mut decoded = vec![0u8; raw_len];
let decoded_len = unsafe {
compression_decode_buffer(
decoded.as_mut_ptr(),
decoded.len(),
encoded.as_ptr(),
encoded.len(),
std::ptr::null_mut(),
Codec::Lzfse.algorithm(),
)
};
if decoded_len != raw_len {
return Ok(false);
}
let mut kernel = vec![0u8; raw_len];
if logical.read_exact(&mut kernel).is_err() || kernel != decoded {
return Ok(false);
}
}
let mut extra = [0u8; 1];
Ok(logical.read(&mut extra).is_ok_and(|len| len == 0))
}
impl StreamingWriter {
pub(crate) fn new(path: &Path, expected_len: usize) -> Result<Self, Error> {
let num_blocks = expected_len.div_ceil(BLOCK).max(1);
let table_len = resource_fork_table_len(num_blocks)?;
if expected_len == 0 || table_len >= expected_len || table_len > u32::MAX as usize {
let file = std::fs::OpenOptions::new()
.read(true)
.write(true)
.create_new(true)
.open(path)
.map_err(|source| Error::Io {
context: "create streaming plain temp",
source,
})?;
return Ok(Self {
path: path.to_path_buf(),
expected_len,
written: 0,
state: StreamingState::Plain(file),
complete: false,
});
}
let file = std::fs::OpenOptions::new()
.read(true)
.write(true)
.create_new(true)
.open(path)
.map_err(|source| Error::Io {
context: "create streaming decmpfs temp",
source,
})?;
let fork_file = (|| -> Result<std::fs::File, Error> {
let fork_path = path.join("..namedfork").join("rsrc");
let mut fork_file = std::fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(true)
.open(fork_path)
.map_err(|source| Error::Io {
context: "open streaming resource fork",
source,
})?;
use std::io::Seek;
fork_file
.set_len(table_len as u64)
.map_err(|source| Error::Io {
context: "reserve streaming resource-fork table",
source,
})?;
fork_file
.seek(std::io::SeekFrom::Start(table_len as u64))
.map_err(|source| Error::Io {
context: "seek streaming resource-fork payload",
source,
})?;
Ok(fork_file)
})();
let fork_file = match fork_file {
Ok(fork_file) => fork_file,
Err(error) => {
drop(file);
let _ = std::fs::remove_file(path);
return Err(error);
}
};
let scratch_len = unsafe { compression_encode_scratch_buffer_size(Codec::Lzfse.algorithm()) };
Ok(Self {
path: path.to_path_buf(),
expected_len,
written: 0,
state: StreamingState::Encoding(StreamingEncoding {
file,
fork: std::io::BufWriter::with_capacity(1 << 20, fork_file),
scratch: vec![0u8; scratch_len],
partial: Vec::with_capacity(BLOCK),
offsets: vec![u32::try_from(table_len).map_err(|_| resource_fork_too_large())?],
encoded_offset: table_len,
}),
complete: false,
})
}
fn switch_to_plain(&mut self, current: &[u8]) -> Result<(), Error> {
let StreamingState::Encoding(mut encoding) =
std::mem::replace(&mut self.state, StreamingState::Closed)
else {
return Err(Error::Io {
context: "switch streaming writer to plain",
source: std::io::Error::from(std::io::ErrorKind::InvalidInput),
});
};
let (fallback, mut plain) =
decode_streaming_prefix(&self.path, &mut encoding, current, self.expected_len)?;
drop(encoding);
if let Err(source) = std::fs::remove_file(&self.path) {
let _ = std::fs::remove_file(&fallback);
return Err(Error::Io {
context: "remove streaming decmpfs temp",
source,
});
}
if let Err(source) = std::fs::rename(&fallback, &self.path) {
let _ = std::fs::remove_file(&fallback);
return Err(Error::Io {
context: "adopt streaming plain fallback",
source,
});
}
use std::io::Seek;
plain
.seek(std::io::SeekFrom::End(0))
.map_err(|source| Error::Io {
context: "seek streaming plain fallback",
source,
})?;
self.state = StreamingState::Plain(plain);
Ok(())
}
pub(crate) fn write_all(&mut self, mut input: &[u8]) -> Result<(), Error> {
let next_written = self
.written
.checked_add(input.len())
.filter(|&len| len <= self.expected_len)
.ok_or_else(|| Error::Io {
context: "stream exceeds expected length",
source: std::io::Error::from(std::io::ErrorKind::InvalidData),
})?;
while !input.is_empty() {
match &mut self.state {
StreamingState::Plain(file) => {
use std::io::Write;
file.write_all(input).map_err(|source| Error::Io {
context: "write streaming plain temp",
source,
})?;
input = &[];
}
StreamingState::Encoding(encoding) => {
let take = (BLOCK - encoding.partial.len()).min(input.len());
encoding.partial.extend_from_slice(&input[..take]);
input = &input[take..];
if encoding.partial.len() == BLOCK {
let block = std::mem::replace(&mut encoding.partial, Vec::with_capacity(BLOCK));
if !encoding.write_block(&block, self.expected_len)? {
self.switch_to_plain(&block)?;
}
}
}
StreamingState::Closed => {
return Err(Error::Io {
context: "write closed streaming writer",
source: std::io::Error::from(std::io::ErrorKind::BrokenPipe),
});
}
}
}
self.written = next_written;
Ok(())
}
pub(crate) fn finish(&mut self) -> Result<bool, Error> {
if self.written != self.expected_len {
return Err(Error::Io {
context: "finish incomplete streaming writer",
source: std::io::Error::from(std::io::ErrorKind::UnexpectedEof),
});
}
let partial = match &mut self.state {
StreamingState::Encoding(encoding) if !encoding.partial.is_empty() => Some(
std::mem::replace(&mut encoding.partial, Vec::with_capacity(BLOCK)),
),
_ => None,
};
if let Some(block) = partial {
let won = match &mut self.state {
StreamingState::Encoding(encoding) => encoding.write_block(&block, self.expected_len)?,
_ => false,
};
if !won {
self.switch_to_plain(&block)?;
}
}
let compressed = match std::mem::replace(&mut self.state, StreamingState::Closed) {
StreamingState::Plain(file) => {
file.sync_all().map_err(|source| Error::Io {
context: "sync streaming plain temp",
source,
})?;
false
}
StreamingState::Encoding(mut encoding) => {
use std::io::{Seek, Write};
let mut table = Vec::with_capacity(encoding.offsets.len() * std::mem::size_of::<u32>());
for offset in &encoding.offsets {
table.extend_from_slice(&offset.to_le_bytes());
}
encoding
.fork
.seek(std::io::SeekFrom::Start(0))
.and_then(|_| encoding.fork.write_all(&table))
.and_then(|_| encoding.fork.flush())
.map_err(|source| Error::Io {
context: "finish streaming resource fork",
source,
})?;
encoding
.fork
.get_ref()
.sync_all()
.map_err(|source| Error::Io {
context: "sync finished streaming resource fork",
source,
})?;
let cpath = cstring(&self.path)?;
setxattr(
&cpath,
c"com.apple.decmpfs",
&decmpfs_header(Codec::Lzfse, self.expected_len),
)?;
if unsafe { libc::fchflags(encoding.file.as_raw_fd(), UF_COMPRESSED) } != 0 {
return Err(io("fchflags streaming temp"));
}
encoding.file.sync_all().map_err(|source| Error::Io {
context: "sync streaming decmpfs temp",
source,
})?;
if streaming_kernel_matches(&self.path, &encoding, self.expected_len)? {
true
} else {
let (fallback, plain) =
decode_streaming_prefix(&self.path, &mut encoding, &[], self.expected_len)?;
drop(encoding);
std::fs::remove_file(&self.path).map_err(|source| Error::Io {
context: "remove failed streaming decmpfs oracle",
source,
})?;
if let Err(source) = std::fs::rename(&fallback, &self.path) {
let _ = std::fs::remove_file(&fallback);
return Err(Error::Io {
context: "publish streaming oracle fallback",
source,
});
}
plain.sync_all().map_err(|source| Error::Io {
context: "sync streaming oracle fallback",
source,
})?;
false
}
}
StreamingState::Closed => {
return Err(Error::Io {
context: "finish closed streaming writer",
source: std::io::Error::from(std::io::ErrorKind::BrokenPipe),
});
}
};
self.complete = true;
Ok(compressed)
}
}
impl Drop for StreamingWriter {
fn drop(&mut self) {
if !self.complete {
self.state = StreamingState::Closed;
let _ = std::fs::remove_file(&self.path);
}
}
}
fn decmpfs_header(codec: Codec, raw_len: usize) -> [u8; 16] {

@@ -1151,433 +664,3 @@ let mut header = [0u8; 16];

#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use super::*;
// The kernel-roundtrip oracle. decmpfs is undocumented — the only proof the
// format is right is that a normal read() returns identical bytes after apply.
#[test]
fn kernel_roundtrips_decmpfs() {
let dir = std::env::temp_dir().join(format!("decmpfs-oracle-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("f.bin");
// > 1 block (64 KiB) of compressible data, so the offset table + LZVN blocks
// are both exercised.
let mut raw = Vec::new();
let pat = b"the quick brown fox decmpfs lzvn resource-fork oracle line ";
while raw.len() < 2_000_000 {
raw.extend_from_slice(pat);
}
std::fs::write(&path, &raw).unwrap();
assert!(
matches!(detect(&path).unwrap(), Support::Supported),
"temp dir is local APFS/HFS+"
);
apply_inplace(&path, &raw).unwrap();
assert!(is_already_compressed(&path).unwrap(), "UF_COMPRESSED set");
assert_eq!(
compressed_on_disk(&path).unwrap(),
Some(true),
"reports compressed"
);
// THE ORACLE: the kernel decompresses our resource fork on read().
assert_eq!(
std::fs::read(&path).unwrap(),
raw,
"kernel read-back must equal the original bytes"
);
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn incremental_writer_streams_lzfse_blocks_into_a_kernel_readable_file() {
let dir =
std::env::temp_dir().join(format!("decmpfs-incremental-oracle-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("model.bin");
let raw = b"incremental lzfse resource fork ".repeat((2 << 20) / 34 + 1);
let mut writer = StreamingWriter::new(&path, raw.len()).unwrap();
for chunk in raw.chunks(17_003) {
writer.write_all(chunk).unwrap();
}
assert!(writer.finish().unwrap(), "compressible stream must win");
assert!(is_already_compressed(&path).unwrap());
assert_eq!(std::fs::read(&path).unwrap(), raw);
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn incremental_writer_reconstructs_plain_bytes_when_compression_loses() {
let dir = std::env::temp_dir().join(format!(
"decmpfs-incremental-fallback-{}",
std::process::id()
));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("random.bin");
let mut raw = Vec::with_capacity(2 << 20);
let mut x: u64 = 0x9e37_79b9_7f4a_7c15;
while raw.len() < (2 << 20) {
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
raw.extend_from_slice(&x.to_le_bytes());
}
let mut writer = StreamingWriter::new(&path, raw.len()).unwrap();
for chunk in raw.chunks(17_003) {
writer.write_all(chunk).unwrap();
}
assert!(
!writer.finish().unwrap(),
"incompressible stream stays plain"
);
assert!(!is_already_compressed(&path).unwrap());
assert_eq!(std::fs::read(&path).unwrap(), raw);
std::fs::remove_dir_all(&dir).ok();
}
// Opt-in perf probe (ignored in CI — timing is machine-specific). Reports the
// decmpfs write time for a ~40 MiB addon; run serial vs parallel with
// cargo test -p decmpfs write_time -- --ignored --nocapture
// DECMPFS_SERIAL=1 cargo test -p decmpfs write_time -- --ignored --nocapture
#[test]
#[ignore]
fn write_time_probe() {
let dir = std::env::temp_dir().join(format!("decmpfs-time-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("addon.node");
let mut raw: Vec<u8> = Vec::with_capacity(40 << 20);
let mut x: u64 = 0x9e37_79b9_7f4a_7c15;
while raw.len() < (40 << 20) {
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
raw.extend_from_slice(&x.to_le_bytes());
raw.extend_from_slice(b"native addon .node text segment padding ");
}
if !matches!(detect(&dir), Ok(Support::Supported)) {
std::fs::remove_dir_all(&dir).ok();
return;
}
let cores = std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(1);
let serial = std::env::var_os("DECMPFS_SERIAL").is_some();
let start = std::time::Instant::now();
apply_bytes(&path, &raw, None).unwrap();
let ms = start.elapsed().as_secs_f64() * 1e3;
eprintln!(
"decmpfs write {}MiB — {} ({} cores): {:.1} ms",
raw.len() >> 20,
if serial { "serial" } else { "parallel" },
cores,
ms,
);
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn detect_and_flags_error_on_a_missing_path() {
let p = std::path::Path::new("/no/such/decmpfs/path/x.bin");
assert!(detect(p).is_err(), "statfs of a missing path errors");
assert!(
is_already_compressed(p).is_err(),
"lstat of a missing path errors"
);
}
#[test]
fn apply_inplace_errors_when_the_file_cannot_be_read() {
// A 0-perm file: apply_inplace's initial read fails before any apply. Root
// bypasses mode bits, so skip there.
if unsafe { libc::geteuid() } == 0 {
return;
}
use std::os::unix::fs::PermissionsExt;
let dir = std::env::temp_dir().join(format!("decmpfs-noread-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("f.bin");
let content = b"\x7fELF unreadable";
std::fs::write(&path, content).unwrap();
std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o000)).unwrap();
// apply_inplace no longer reads the file (the caller passes the snapshot it
// already holds); the fail-soft guard is now the W_OK access check, which
// rejects a file we cannot write before the temp+rename would replace it.
let out = apply_inplace(&path, content);
std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o644)).ok();
assert!(matches!(
out,
Err(Error::Io {
context: "access",
..
})
));
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn setxattr_errors_on_a_missing_path() {
let out = setxattr(c"/no/such/decmpfs/path", c"com.apple.decmpfs", b"x");
assert!(matches!(
out,
Err(Error::Io {
context: "setxattr",
..
})
));
}
#[test]
fn compress_block_returns_none_for_empty_input() {
// libcompression encodes zero bytes to nothing → the n == 0 guard returns None.
let scratch_len = unsafe { compression_encode_scratch_buffer_size(COMPRESSION_LZVN) };
let mut scratch = vec![0u8; scratch_len];
assert!(compress_block(b"", &mut scratch).is_none());
}
#[test]
fn build_resource_fork_zero_length_is_no_gain() {
assert!(
build_resource_fork(&[]).unwrap().is_none(),
"a resource fork cannot make an empty file smaller"
);
}
#[test]
fn streaming_threshold_keeps_vite_native_addons_on_the_fast_path() {
// The largest Darwin ARM64 addon in the 2026-07-16 Vite-family sample was
// SWC at 36.563 MiB. The complete observed set must stay comfortably below
// the in-memory cutoff, while the first byte beyond it streams.
assert!(!should_stream_resource_fork(37 << 20, STREAMING_THRESHOLD));
assert!(!should_stream_resource_fork(
STREAMING_THRESHOLD,
STREAMING_THRESHOLD
));
assert!(should_stream_resource_fork(
STREAMING_THRESHOLD + 1,
STREAMING_THRESHOLD
));
}
#[test]
fn kernel_roundtrips_forced_streaming_lzfse() {
let dir = std::env::temp_dir().join(format!("decmpfs-streaming-oracle-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("f.bin");
let raw = b"streamed lzfse decmpfs resource fork oracle ".repeat((2 << 20) / 46 + 1);
std::fs::write(&path, &raw).unwrap();
if matches!(detect(&path).unwrap(), Support::Supported) {
apply_bytes_with_streaming_threshold(&path, &raw, None, 0).unwrap();
assert!(is_already_compressed(&path).unwrap(), "UF_COMPRESSED set");
assert_eq!(
std::fs::read(&path).unwrap(),
raw,
"kernel read-back must decode the streamed type-12 resource fork"
);
let cpath = cstring(&path).unwrap();
let mut header = [0u8; 16];
let len = unsafe {
libc::getxattr(
cpath.as_ptr(),
c"com.apple.decmpfs".as_ptr(),
header.as_mut_ptr().cast(),
header.len(),
0,
XATTR_NOFOLLOW | 0x0020, // XATTR_SHOWCOMPRESSION
)
};
assert_eq!(len, header.len() as isize);
assert_eq!(u32::from_le_bytes(header[4..8].try_into().unwrap()), 12);
}
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn in_memory_path_falls_back_to_lzfse_when_lzvn_has_no_gain() {
// Skewed symbol frequencies give LZFSE's entropy coder something to exploit
// without manufacturing the repeated strings that LZVN specializes in.
let mut raw = Vec::with_capacity(1 << 20);
let mut x: u64 = 0x9e37_79b9_7f4a_7c15;
while raw.len() < raw.capacity() {
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
raw.push(if x.is_multiple_of(4) {
0
} else {
(x >> 32) as u8
});
}
assert!(
build_resource_fork_with_codec(&raw, Codec::Lzvn)
.unwrap()
.is_none(),
"fixture must reach the fallback"
);
let candidate = build_in_memory_resource_fork(&raw)
.unwrap()
.expect("LZFSE should exploit the skewed symbols");
assert_eq!(candidate.codec, Codec::Lzfse);
assert!(candidate.bytes.len() < raw.len());
}
#[test]
fn build_resource_fork_last_offset_equals_length() {
// Invariant across sizes that actually encode: the final table offset equals
// the total blob length. (Tiny/incompressible inputs return None — the codec
// declines — which is a separate, correct path.)
for size in [512usize, BLOCK, BLOCK + 1, BLOCK * 3 + 7] {
let raw = vec![0x41u8; size];
let Some(rf) = build_resource_fork(&raw).unwrap() else {
continue;
};
let num_blocks = size.div_ceil(BLOCK);
let last_idx = num_blocks * 4; // offset[num_blocks] is the last entry
let last = u32::from_le_bytes(rf[last_idx..last_idx + 4].try_into().unwrap()) as usize;
assert_eq!(last, rf.len(), "size {size}: last offset != buffer length");
}
}
#[test]
fn cstring_rejects_an_interior_nul() {
use std::os::unix::ffi::OsStrExt;
let p = std::path::Path::new(std::ffi::OsStr::from_bytes(b"a\0b"));
assert!(cstring(p).is_err());
}
#[test]
fn detect_rejects_a_non_apfs_filesystem() {
// /dev is devfs (local, but not apfs/hfs) → Unsupported(Filesystem).
assert!(matches!(
detect(std::path::Path::new("/dev")),
Ok(Support::Unsupported(UnsupportedReason::Filesystem))
));
}
#[test]
fn classify_fs_covers_every_branch() {
// Non-local (e.g. a network mount) — no real mount needed.
assert!(matches!(
classify_fs(false, b"nfs"),
Support::Unsupported(UnsupportedReason::NetworkOrOverlay)
));
assert!(matches!(classify_fs(true, b"apfs"), Support::Supported));
assert!(matches!(classify_fs(true, b"hfs"), Support::Supported));
assert!(matches!(
classify_fs(true, b"ext4"),
Support::Unsupported(UnsupportedReason::Filesystem)
));
}
#[test]
fn resource_fork_plan_accepts_raw_files_beyond_the_old_limit() {
// The raw byte count is stored as u64. Only resource-fork offsets are u32,
// so a >3.9 GB input is valid whenever its encoded fork fits in u32.
let raw_len = 4_100_000_000usize;
let num_blocks = raw_len.div_ceil(BLOCK);
assert!(matches!(
plan_resource_fork(raw_len, num_blocks, 3_000_000_000).unwrap(),
ResourceForkPlan::Compressed { .. }
));
}
#[test]
fn resource_fork_plan_accepts_raw_files_beyond_four_gib_when_the_fork_fits() {
let raw_len = 5_000_000_000usize;
let num_blocks = raw_len.div_ceil(BLOCK);
assert!(matches!(
plan_resource_fork(raw_len, num_blocks, 3_000_000_000).unwrap(),
ResourceForkPlan::Compressed { .. }
));
}
#[test]
fn resource_fork_plan_rejects_a_compressed_fork_past_u32() {
let raw_len = 5_000_000_000usize;
let num_blocks = raw_len.div_ceil(BLOCK);
match plan_resource_fork(raw_len, num_blocks, 4_400_000_000).unwrap_err() {
Error::Io { source, .. } => assert_eq!(source.raw_os_error(), Some(libc::EFBIG)),
other => panic!("expected EFBIG Io, got {other:?}"),
}
}
#[test]
fn gemini_nano_lzvn_resource_fork_is_no_gain() {
// Chrome 150's v3Nano weights.bin measured with this exact 64 KiB LZVN
// encoder: the encoded blocks expand enough to cross the u32 fork ceiling.
assert_eq!(
plan_resource_fork(4_269_932_544, 65_154, 4_364_775_458).unwrap(),
ResourceForkPlan::Plain
);
}
#[test]
fn gemini_nano_lzfse_resource_fork_fits_and_wins() {
// The streamed type-12 run encoded the same 65,154 blocks to this payload;
// with its 260,620-byte offset table the fork is safely below u32::MAX.
assert_eq!(
plan_resource_fork(4_269_932_544, 65_154, 3_598_249_560).unwrap(),
ResourceForkPlan::Compressed {
table_len: 260_620,
total_len: 3_598_510_180,
}
);
}
// Incompressible data → LZVN would expand the resource fork, so keep an
// ordinary data fork. The bytes and compression-state signal must agree.
#[test]
fn kernel_roundtrips_incompressible_blocks() {
let dir = std::env::temp_dir().join(format!("decmpfs-raw-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("f.bin");
let mut raw = Vec::new();
let mut x: u32 = 0x9e37_79b9;
while raw.len() < 200_000 {
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
raw.extend_from_slice(&x.to_le_bytes());
}
std::fs::write(&path, &raw).unwrap();
if matches!(detect(&path).unwrap(), Support::Supported) {
assert!(matches!(
crate::compress_file(&path).unwrap(),
crate::Outcome::NoGain { .. }
));
assert_eq!(
std::fs::read(&path).unwrap(),
raw,
"plain fallback reads back identically"
);
assert!(
!is_already_compressed(&path).unwrap(),
"no-gain input must not carry UF_COMPRESSED"
);
}
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn apply_bytes_preserves_ownership_of_an_overwritten_file() {
// Non-root exercises the chown path over an existing file — owner is our own
// uid, so preservation is a no-op we assert stays stable + non-corrupting.
// The root path (a file owned by a different uid) is verified in CI.
let dir = std::env::temp_dir().join(format!("decmpfs-own-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("f");
std::fs::write(&path, vec![0u8; 4096]).unwrap();
if !matches!(detect(&path), Ok(Support::Supported)) {
std::fs::remove_dir_all(&dir).ok();
return;
}
use std::os::unix::fs::MetadataExt;
let before_uid = std::fs::metadata(&path).unwrap().uid();
let content = vec![0xABu8; 8192];
apply_bytes(&path, &content, None).unwrap();
let meta = std::fs::metadata(&path).unwrap();
assert_eq!(meta.uid(), before_uid, "owner preserved across the rewrite");
assert_eq!(std::fs::read(&path).unwrap(), content, "content intact");
std::fs::remove_dir_all(&dir).ok();
}
}
#[path = "macos/tests.rs"]
mod tests;

Sorry, the diff of this file is not supported yet