diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libarchive/Makefile | 2 | ||||
-rw-r--r-- | lib/libarchive/archive_write_disk.c | 25 | ||||
-rw-r--r-- | lib/libarchive/test/test_write_disk_perms.c | 57 |
3 files changed, 73 insertions, 11 deletions
diff --git a/lib/libarchive/Makefile b/lib/libarchive/Makefile index e66d374..fdf4a70 100644 --- a/lib/libarchive/Makefile +++ b/lib/libarchive/Makefile @@ -9,7 +9,7 @@ LDADD= -lbz2 -lz # Major: Bumped ONLY when API/ABI breakage happens (see SHLIB_MAJOR) # Minor: Bumped when significant new features are added # Revision: Bumped on any notable change -VERSION= 2.0.24 +VERSION= 2.0.25 ARCHIVE_API_MAJOR!= echo ${VERSION} | sed -e 's/[^0-9]/./g' -e 's/\..*//' ARCHIVE_API_MINOR!= echo ${VERSION} | sed -e 's/[^0-9]/./g' -e 's/[0-9]*\.//' -e 's/\..*//' diff --git a/lib/libarchive/archive_write_disk.c b/lib/libarchive/archive_write_disk.c index 02fabd6..0f2e173 100644 --- a/lib/libarchive/archive_write_disk.c +++ b/lib/libarchive/archive_write_disk.c @@ -111,6 +111,7 @@ struct fixup_entry { * that verification can occur explicitly through a stat() call or * implicitly because of a successful chown() call. */ +#define TODO_MODE_FORCE 0x40000000 #define TODO_MODE_BASE 0x20000000 #define TODO_SUID 0x10000000 #define TODO_SUID_CHECK 0x08000000 @@ -320,6 +321,7 @@ _archive_write_header(struct archive *_a, struct archive_entry *entry) /* Figure out what we need to do for this entry. */ a->todo = TODO_MODE_BASE; if (a->flags & ARCHIVE_EXTRACT_PERM) { + a->todo |= TODO_MODE_FORCE; /* Be pushy about permissions. */ /* * SGID requires an extra "check" step because we * cannot easily predict the GID that the system will @@ -732,9 +734,12 @@ restore_entry(struct archive_write_disk *a) * There's a dir in the way of a dir. Don't * waste time with rmdir()/mkdir(), just fix * up the permissions on the existing dir. + * Note that we don't change perms on existing + * dirs unless _EXTRACT_PERM is specified. */ - if (a->mode != a->st.st_mode) - a->deferred |= TODO_MODE; + if ((a->mode != a->st.st_mode) + && (a->todo & TODO_MODE_FORCE)) + a->deferred |= (a->todo & TODO_MODE); /* Ownership doesn't need deferred fixup. */ en = 0; /* Forget the EEXIST. */ } @@ -806,13 +811,15 @@ create_filesystem_object(struct archive_write_disk *a) case S_IFDIR: mode = (mode | MINIMUM_DIR_MODE) & MAXIMUM_DIR_MODE; r = mkdir(a->name, mode); - /* Defer setting dir times. */ - a->deferred |= (a->todo & TODO_TIMES); - a->todo &= ~TODO_TIMES; - /* Never use an immediate chmod(). */ - if (mode != final_mode) - a->deferred |= (a->todo & TODO_MODE); - a->todo &= ~TODO_MODE; + if (r == 0) { + /* Defer setting dir times. */ + a->deferred |= (a->todo & TODO_TIMES); + a->todo &= ~TODO_TIMES; + /* Never use an immediate chmod(). */ + if (mode != final_mode) + a->deferred |= (a->todo & TODO_MODE); + a->todo &= ~TODO_MODE; + } break; case S_IFIFO: r = mkfifo(a->name, mode); diff --git a/lib/libarchive/test/test_write_disk_perms.c b/lib/libarchive/test/test_write_disk_perms.c index 285b516..f8cea11 100644 --- a/lib/libarchive/test/test_write_disk_perms.c +++ b/lib/libarchive/test/test_write_disk_perms.c @@ -57,7 +57,7 @@ searchgid(void) return; _searched = 1; - /* Create a file on disk. */ + /* Create a file on disk in the current default dir. */ fd = open("test_gid", O_CREAT, 0664); failure("Couldn't create a file for gid testing."); assert(fd > 0); @@ -136,6 +136,49 @@ DEFINE_TEST(test_write_disk_perms) assert(0 == archive_write_header(a, ae)); assert(0 == archive_write_finish_entry(a)); + /* Write a regular file, then write over it. */ + /* For files, the perms should get updated. */ + assert((ae = archive_entry_new()) != NULL); + archive_entry_copy_pathname(ae, "file_overwrite_0144"); + archive_entry_set_mode(ae, S_IFREG | 0777); + assert(0 == archive_write_header(a, ae)); + assert(0 == archive_write_finish_entry(a)); + /* Check that file was created with different perms. */ + assert(0 == stat("file_overwrite_0144", &st)); + failure("file_overwrite_0144: st.st_mode=%o", st.st_mode); + assert((st.st_mode & 07777) != 0144); + /* Overwrite, this should change the perms. */ + assert((ae = archive_entry_new()) != NULL); + archive_entry_copy_pathname(ae, "file_overwrite_0144"); + archive_entry_set_mode(ae, S_IFREG | 0144); + assert(0 == archive_write_header(a, ae)); + assert(0 == archive_write_finish_entry(a)); + + /* Write a regular dir. */ + assert((ae = archive_entry_new()) != NULL); + archive_entry_copy_pathname(ae, "dir_0514"); + archive_entry_set_mode(ae, S_IFDIR | 0514); + assert(0 == archive_write_header(a, ae)); + assert(0 == archive_write_finish_entry(a)); + + /* Overwrite an existing dir. */ + /* For dir, the first perms should get left. */ + assert(mkdir("dir_overwrite_0744", 0744) == 0); + /* Check original perms. */ + assert(0 == stat("dir_overwrite_0744", &st)); + failure("dir_overwrite_0744: st.st_mode=%o", st.st_mode); + assert((st.st_mode & 07777) == 0744); + /* Overwrite shouldn't edit perms. */ + assert((ae = archive_entry_new()) != NULL); + archive_entry_copy_pathname(ae, "dir_overwrite_0744"); + archive_entry_set_mode(ae, S_IFDIR | 0777); + assert(0 == archive_write_header(a, ae)); + assert(0 == archive_write_finish_entry(a)); + /* Make sure they're unchanged. */ + assert(0 == stat("dir_overwrite_0744", &st)); + failure("dir_overwrite_0744: st.st_mode=%o", st.st_mode); + assert((st.st_mode & 07777) == 0744); + /* 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"); @@ -268,6 +311,18 @@ DEFINE_TEST(test_write_disk_perms) failure("file_0755: st.st_mode=%o", st.st_mode); assert((st.st_mode & 07777) == 0755); + assert(0 == stat("file_overwrite_0144", &st)); + failure("file_overwrite_0144: st.st_mode=%o", st.st_mode); + assert((st.st_mode & 07777) == 0144); + + assert(0 == stat("dir_0514", &st)); + failure("dir_0514: st.st_mode=%o", st.st_mode); + assert((st.st_mode & 07777) == 0514); + + assert(0 == stat("dir_overwrite_0744", &st)); + failure("dir_overwrite_0744: st.st_mode=%o", st.st_mode); + assert((st.st_mode & 07777) == 0744); + assert(0 == stat("file_no_suid", &st)); failure("file_0755: st.st_mode=%o", st.st_mode); assert((st.st_mode & 07777) == 0755); |