summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2007-03-24 05:02:16 +0000
committerkientzle <kientzle@FreeBSD.org>2007-03-24 05:02:16 +0000
commitc9ae05df5cc0ead4790c6bc5a640a5de0f89dfed (patch)
tree13afc0b23299a785f50351dc36070c9d6f0d46ad
parent758c270b77e6b393d16186449a41e772d3d21c70 (diff)
downloadFreeBSD-src-c9ae05df5cc0ead4790c6bc5a640a5de0f89dfed.zip
FreeBSD-src-c9ae05df5cc0ead4790c6bc5a640a5de0f89dfed.tar.gz
Notice when mkdir() fails.
Don't change permissions on an existing dir unless _EXTRACT_PERM is requested. In particular, bsdtar -x should not edit mode of existing dirs now; bsdtar -xp will.
-rw-r--r--lib/libarchive/Makefile2
-rw-r--r--lib/libarchive/archive_write_disk.c25
-rw-r--r--lib/libarchive/test/test_write_disk_perms.c57
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);
OpenPOWER on IntegriCloud