]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
archive_write_disk_{posix,windows}.c: Don't modify attributes for existing directorie...
authorPaul Spangler <paul.spangler@ni.com>
Thu, 19 Oct 2017 19:33:12 +0000 (14:33 -0500)
committerPaul Spangler <paul.spangler@ni.com>
Fri, 20 Oct 2017 17:34:58 +0000 (12:34 -0500)
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>
libarchive/archive_write_disk_posix.c
libarchive/archive_write_disk_windows.c
libarchive/test/test_write_disk_perms.c

index 61961278b9488ee8df589c6b610519b9b6552117..3fd5f57985149b238e2d8140b5eea52f51843649 100644 (file)
@@ -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);
        }
index 8fe99a07fabe41edca3255da106d8933040d304d..b09c2712f83ba8a956b887e2974b6d547822bd56 100644 (file)
@@ -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);
        }
index 4b68e52b4ee5e96fb427082d6133d772be241f31..0872138c5300b914ba8cadafecc8b104a54ea470 100644 (file)
@@ -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");