Skip to content

Commit

Permalink
Handle creating temp directories when destination is a file
Browse files Browse the repository at this point in the history
When applesauce is passed a file on a different device than /tmp, it
should try to make a tempdir in the _parent_ of the path, not somehow
inside the file.

Also, handle errors in adding a tempdir destination: we already handle
the case where we don't have a common directory for a temp file by
creating a tempfile in the same directory.
  • Loading branch information
Dr-Emann committed Apr 10, 2024
1 parent 7991f60 commit 8d02764
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 11 deletions.
46 changes: 39 additions & 7 deletions crates/applesauce/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,25 +426,57 @@ mod tests {

#[test]
fn compress_single_file() {
let mut big_compressable_file = tempfile::NamedTempFile::new().unwrap();
big_compressable_file.write_all(&[0; 16 * 1024]).unwrap();
big_compressable_file.flush().unwrap();
let hash = recursive_hash(big_compressable_file.path());
let mut compressible_file = tempfile::NamedTempFile::new().unwrap();
compressible_file.write_all(&[0; 16 * 1024]).unwrap();
compressible_file.flush().unwrap();
let hash = recursive_hash(compressible_file.path());

let mut fc = FileCompressor::new();
fc.recursive_compress(
iter::once(big_compressable_file.path()),
iter::once(compressible_file.path()),
Kind::default(),
1.0,
2,
&NoProgress,
true,
);

let new_hash = recursive_hash(big_compressable_file.path());
let new_hash = recursive_hash(compressible_file.path());
assert_eq!(hash, new_hash);

let info = info::get_recursive(big_compressable_file.path()).unwrap();
let info = info::get_recursive(compressible_file.path()).unwrap();
// These are very compressible files
assert!(info.compression_savings_fraction() > 0.5);
}

#[test]
fn compress_dir_and_file() {
let outer_dir = TempDir::new().unwrap();
let inner_dir = outer_dir.path().join("inner");
let inner_file_path = inner_dir.join("file");
fs::create_dir(&inner_dir).unwrap();

let mut compressible_file = File::create(&inner_file_path).unwrap();
compressible_file.write_all(&[0; 16 * 1024]).unwrap();
compressible_file.flush().unwrap();

populate_dir(&inner_dir);
let hash = recursive_hash(outer_dir.path());

let mut fc = FileCompressor::new();
fc.recursive_compress(
[inner_dir.as_path(), inner_file_path.as_path()].into_iter(),
Kind::default(),
1.0,
2,
&NoProgress,
false,
);

let new_hash = recursive_hash(outer_dir.path());
assert_eq!(hash, new_hash);

let info = info::get_recursive(outer_dir.path()).unwrap();
// These are very compressible files
assert!(info.compression_savings_fraction() > 0.5);
}
Expand Down
12 changes: 9 additions & 3 deletions crates/applesauce/src/threads/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::thread::{self, JoinHandle};
use std::{fmt, io, mem};
use tracing::warn;

pub mod compressing;
pub mod reader;
Expand Down Expand Up @@ -141,9 +142,14 @@ impl BackgroundThreads {
let (finished_stats, finished_stats_rx) = crossbeam_channel::bounded(1);
let mut operation = OperationContext::new(mode, finished_stats, verify);
let walker = scan::Walker::new(
paths
.into_iter()
.inspect(|path| operation.add_dst(path).unwrap()),
paths.into_iter().inspect(|path| {
if let Err(e) = operation.add_dst(path) {
warn!(
"failed to find a temp directory for {}: {e}",
path.display()
);
}
}),
progress,
);
let operation = Arc::new(operation);
Expand Down
17 changes: 16 additions & 1 deletion crates/applesauce/src/tmpdir_paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,22 @@ impl TmpdirPaths {
match self.dirs.entry(device) {
Entry::Occupied(_) => {}
Entry::Vacant(entry) => {
let dir = TempDir::with_prefix_in(TEMPDIR_PREFIX, dst)?;
let tmpdir_parent = if metadata.is_dir() {
dst
} else {
let parent = dst
.parent()
.ok_or_else(|| io::Error::other("path to file has no parent?"))?;

if parent.metadata()?.st_dev() != device {
return Err(io::Error::other(
"parent directory of file is on a different device?",
));
}

parent
};
let dir = TempDir::with_prefix_in(TEMPDIR_PREFIX, tmpdir_parent)?;
entry.insert(dir);
}
}
Expand Down

0 comments on commit 8d02764

Please sign in to comment.