Skip to content

Commit

Permalink
Ensure directory permissions are correctly applied. (#372)
Browse files Browse the repository at this point in the history
* Add link ownership rules.

* Reorder directories when creating.
  • Loading branch information
stswidwinski authored Aug 22, 2024
1 parent f952189 commit 9f9ce52
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,15 @@ impl Archive<dyn Read + '_> {
file.unpack_in(dst)?;
}
}

// Apply the directories.
//
// Note: the order of application is important to permissions. That is, we must traverse
// the filesystem graph in topological ordering or else we risk not being able to create
// child directories within those of more restrictive permissions. See [0] for details.
//
// [0]: <https://github.com/alexcrichton/tar-rs/issues/242>
directories.sort_by(|a, b| b.path_bytes().cmp(&a.path_bytes()));
for mut dir in directories {
dir.unpack_in(dst)?;
}
Expand Down
37 changes: 37 additions & 0 deletions tests/all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,43 @@ fn writing_and_extracting_directories() {
check_dirtree(&td);
}

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

// Archive with complex permissions which would fail to unpack if one attempted to do so
// without reordering of entries.
let mut ar = Builder::new(Vec::new());
let tmppath = td.path().join("tmpfile");
t!(t!(File::create(&tmppath)).write_all(b"c"));

// Root dir with very stringent permissions
let data: &[u8] = &[];
let mut header = Header::new_gnu();
header.set_mode(0o555);
header.set_entry_type(EntryType::Directory);
t!(header.set_path("a"));
header.set_size(0);
header.set_cksum();
t!(ar.append(&header, data));

// Nested dir
header.set_mode(0o777);
header.set_entry_type(EntryType::Directory);
t!(header.set_path("a/b"));
header.set_cksum();
t!(ar.append(&header, data));

// Nested file.
t!(ar.append_file("a/c", &mut t!(File::open(&tmppath))));
t!(ar.finish());

let rdr = Cursor::new(t!(ar.into_inner()));
let mut ar = Archive::new(rdr);
ar.unpack(td.path()).unwrap();
check_dirtree(&td);
}

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

0 comments on commit 9f9ce52

Please sign in to comment.