summaryrefslogtreecommitdiffstats
path: root/lib/libarchive/archive_read_extract.c
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2004-06-27 16:44:51 +0000
committerkientzle <kientzle@FreeBSD.org>2004-06-27 16:44:51 +0000
commit3d735ceae416dc73900e05b0bf98721fe0a4a60d (patch)
tree00020e3b78c13cfba94077e9bd4be93977ceb291 /lib/libarchive/archive_read_extract.c
parentd3e5b0992d4508937c5801f98a39fa97c5407ac0 (diff)
downloadFreeBSD-src-3d735ceae416dc73900e05b0bf98721fe0a4a60d.zip
FreeBSD-src-3d735ceae416dc73900e05b0bf98721fe0a4a60d.tar.gz
More tweaks to implicit directory creation. Even such abominations as
a/././b/../b/../c/./../d/e/f now work correctly. And yes, a/b and a/c both get created in this example; if you want, you can create an entire dir heirarchy from a tar archive with only one entry. More tweaks to umask support: umasks are now obeyed for all objects, not just directories; the umask used is now the one in effect at the corresponding call to archive_read_extract(), so clients that want to tinker with umask during extract should get the expected behavior.
Diffstat (limited to 'lib/libarchive/archive_read_extract.c')
-rw-r--r--lib/libarchive/archive_read_extract.c31
1 files changed, 27 insertions, 4 deletions
diff --git a/lib/libarchive/archive_read_extract.c b/lib/libarchive/archive_read_extract.c
index f20a75b..c473980 100644
--- a/lib/libarchive/archive_read_extract.c
+++ b/lib/libarchive/archive_read_extract.c
@@ -70,6 +70,7 @@ struct fixup_entry {
#define FIXUP_FFLAGS 4
struct extract {
+ mode_t umask;
struct archive_string mkdirpath;
struct fixup_entry *fixup_list;
};
@@ -149,6 +150,7 @@ archive_read_extract(struct archive *a, struct archive_entry *entry, int flags)
memset(a->extract, 0, sizeof(*a->extract));
}
extract = a->extract;
+ umask(extract->umask = umask(0)); /* Read the current umask. */
restore_pwd = -1;
@@ -221,12 +223,10 @@ void archive_extract_cleanup(struct archive *a)
{
struct fixup_entry *next, *p;
struct extract *extract;
- mode_t mask;
/* Sort dir list so directories are fixed up in depth-first order. */
extract = a->extract;
p = sort_dir_list(extract->fixup_list);
- umask(mask = umask(0)); /* Read the current umask. */
while (p != NULL) {
if (p->fixup & FIXUP_TIMES) {
@@ -238,7 +238,7 @@ void archive_extract_cleanup(struct archive *a)
utimes(p->name, times);
}
if (p->fixup & FIXUP_MODE)
- chmod(p->name, p->mode & ~mask);
+ chmod(p->name, p->mode);
if (p->fixup & FIXUP_FFLAGS)
set_fflags(a, p->name, p->mode, p->fflags_set, 0);
@@ -453,7 +453,7 @@ mkdirpath_recursive(struct archive *a, char *path, const struct stat *st,
le->name = strdup(path);
if (mode != writable_mode) {
- le->mode = mode;
+ le->mode = mode & ~extract->umask;
le->fixup |= FIXUP_MODE;
mode = writable_mode;
}
@@ -466,6 +466,11 @@ mkdirpath_recursive(struct archive *a, char *path, const struct stat *st,
}
}
+ /*
+ * Try to make the longest dir first. Most archives are
+ * written in a reasonable order, so this will almost always
+ * save us from having to inspect the parent dirs.
+ */
if (mkdir(path, mode) == 0)
return (ARCHIVE_OK);
/*
@@ -509,8 +514,23 @@ mkdirpath_recursive(struct archive *a, char *path, const struct stat *st,
*p = '/'; /* Restore the '/' we just overwrote. */
if (r != ARCHIVE_OK)
return (r);
+ /* Parent exists now; let's create the last component. */
+ p++;
+ /* Of course, "", ".", and ".." are easy. */
+ if (p[0] == '\0')
+ return (ARCHIVE_OK);
+ if (p[0] == '.' && p[1] == '\0')
+ return (ARCHIVE_OK);
+ if (p[0] == '.' && p[1] == '.' && p[2] == '\0')
+ return (ARCHIVE_OK);
if (mkdir(path, mode) == 0)
return (ARCHIVE_OK);
+ /*
+ * Without the following check, a/b/../b/c/d fails at
+ * the second visit to 'b', so 'd' can't be created.
+ */
+ if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode))
+ return (ARCHIVE_OK);
}
archive_set_error(a, errno, "Failed to create dir '%s'", path);
return (ARCHIVE_WARN);
@@ -762,11 +782,14 @@ set_time(struct archive *a, struct archive_entry *entry, int flags)
static int
set_perm(struct archive *a, struct archive_entry *entry, int mode, int flags)
{
+ struct extract *extract;
const char *name;
if ((flags & ARCHIVE_EXTRACT_PERM) == 0)
return (ARCHIVE_OK);
+ extract = a->extract;
+ mode &= ~extract->umask; /* Enforce umask. */
name = archive_entry_pathname(entry);
#ifdef HAVE_LCHMOD
if (lchmod(name, mode) != 0) {
OpenPOWER on IntegriCloud