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.
This commit is contained in:
Tim Kientzle 2007-03-24 05:02:16 +00:00
parent ac6b4cf110
commit e2d97e54d0
3 changed files with 73 additions and 11 deletions

View file

@ -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/\..*//'

View file

@ -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);

View file

@ -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);