Skip to content

Commit

Permalink
archive_write_disk_{posix,windows}.c: Don't modify attributes for exi…
Browse files Browse the repository at this point in the history
…sting directories when ARCHIVE_EXTRACT_NO_OVERWRITE is set

Enables unpacking multiple archives into a single directory whose permissions,
owner, and other attributes are pre-configured or otherwise determined ahead
of time by a single archive without the need to repeat the same attributes in
every archive, such as in package installation scenarios.

Signed-off-by: Paul Spangler <paul.spangler@ni.com>
  • Loading branch information
spanglerco committed Oct 20, 2017
1 parent f5e11ac commit 6674b4a
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 0 deletions.
4 changes: 4 additions & 0 deletions libarchive/archive_write_disk_posix.c
Expand Up @@ -1981,6 +1981,10 @@ restore_entry(struct archive_write_disk *a)
if ((en == EISDIR || en == EEXIST)
&& (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
/* If we're not overwriting, we're done. */
if (S_ISDIR(a->mode)) {
/* Don't overwrite any settings on existing directories. */
a->todo = 0;
}
archive_entry_unset_size(a->entry);
return (ARCHIVE_OK);
}
Expand Down
4 changes: 4 additions & 0 deletions libarchive/archive_write_disk_windows.c
Expand Up @@ -1325,6 +1325,10 @@ restore_entry(struct archive_write_disk *a)
if ((en == EISDIR || en == EEXIST)
&& (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
/* If we're not overwriting, we're done. */
if (S_ISDIR(a->mode)) {
/* Don't overwrite any settings on existing directories. */
a->todo = 0;
}
archive_entry_unset_size(a->entry);
return (ARCHIVE_OK);
}
Expand Down
43 changes: 43 additions & 0 deletions libarchive/test/test_write_disk_perms.c
Expand Up @@ -201,6 +201,49 @@ DEFINE_TEST(test_write_disk_perms)
failure("dir_overwrite_0744: st.st_mode=%o", st.st_mode);
assertEqualInt(st.st_mode & 0777, 0744);

/* For dir, the owner should get left when not overwritting. */
assertMakeDir("dir_owner", 0744);
if (getuid() == 0) {
assertEqualInt(0, chown("dir_owner", getuid()+1, getgid()));
/* Check original owner. */
assertEqualInt(0, stat("dir_owner", &st));
failure("dir_owner: st.st_uid=%d", st.st_uid);
assertEqualInt(st.st_uid, getuid()+1);
/* Shouldn't edit the owner when no overwrite option is set. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "dir_owner");
archive_entry_set_mode(ae, S_IFDIR | 0744);
archive_entry_set_uid(ae, getuid());
archive_write_disk_set_options(a,
ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_NO_OVERWRITE);
assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
archive_entry_free(ae);
assertEqualIntA(a, ARCHIVE_OK, archive_write_finish_entry(a));
/* Make sure they're unchanged. */
assertEqualInt(0, stat("dir_owner", &st));
failure("dir_owner: st.st_uid=%d", st.st_uid);
assertEqualInt(st.st_uid, getuid()+1);
} else {
/* Check original owner. */
assertEqualInt(0, stat("dir_owner", &st));
failure("dir_owner: st.st_uid=%d", st.st_uid);
assertEqualInt(st.st_uid, getuid());
/* Shouldn't fail to set owner when no overwrite option is set. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "dir_owner");
archive_entry_set_mode(ae, S_IFDIR | 0744);
archive_entry_set_uid(ae, getuid()+1);
archive_write_disk_set_options(a,
ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_NO_OVERWRITE);
assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
archive_entry_free(ae);
assertEqualIntA(a, ARCHIVE_OK, archive_write_finish_entry(a));
/* Make sure they're unchanged. */
assertEqualInt(0, stat("dir_owner", &st));
failure("dir_owner: st.st_uid=%d", st.st_uid);
assertEqualInt(st.st_uid, getuid());
}

/* Write a regular file with SUID bit, but don't use _EXTRACT_PERM. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "file_no_suid");
Expand Down

0 comments on commit 6674b4a

Please sign in to comment.