Skip to content

Commit

Permalink
archive: work from leaves up when unpacking direcories
Browse files Browse the repository at this point in the history
  • Loading branch information
jeckersb committed Apr 13, 2023
1 parent f4f439c commit 5236efb
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 1 deletion.
11 changes: 10 additions & 1 deletion src/archive.rs
Expand Up @@ -222,7 +222,16 @@ impl Archive<dyn Read + '_> {
file.unpack_in(dst)?;
}
}
for mut dir in directories {

// Work from leaves up, with the assumption* that entries for
// parent directories preceed their children. Otherwise when
// a parent directory has no write permission, any empty
// subdirectories beneath it cannot be created.
//
// [*] If sufficiently motivated, one can create an archive
// which violates this. In practice, archives typically are
// structured this way.
for mut dir in directories.into_iter().rev() {
dir.unpack_in(dst)?;
}

Expand Down
27 changes: 27 additions & 0 deletions tests/all.rs
Expand Up @@ -1317,6 +1317,33 @@ fn read_only_directory_containing_files() {
assert!(ar.unpack(td.path()).is_ok());
}

#[test]
fn read_only_directory_containing_empty_directory() {
let td = t!(TempBuilder::new().prefix("tar-rs").tempdir());

let mut b = Builder::new(Vec::<u8>::new());

let mut h = Header::new_gnu();
t!(h.set_path("dir/"));
h.set_size(0);
h.set_entry_type(EntryType::dir());
h.set_mode(0o444);
h.set_cksum();
t!(b.append(&h, "".as_bytes()));

let mut h = Header::new_gnu();
t!(h.set_path("dir/subdir"));
h.set_size(0);
h.set_entry_type(EntryType::dir());
h.set_mode(0o755);
h.set_cksum();
t!(b.append(&h, "".as_bytes()));

let contents = t!(b.into_inner());
let mut ar = Archive::new(&contents[..]);
assert!(ar.unpack(td.path()).is_ok());
}

// This test was marked linux only due to macOS CI can't handle `set_current_dir` correctly
#[test]
#[cfg(target_os = "linux")]
Expand Down

0 comments on commit 5236efb

Please sign in to comment.