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.
This commit is contained in:
parent
e2e364aea2
commit
79db8f55f8
@ -70,6 +70,7 @@ struct fixup_entry {
|
|||||||
#define FIXUP_FFLAGS 4
|
#define FIXUP_FFLAGS 4
|
||||||
|
|
||||||
struct extract {
|
struct extract {
|
||||||
|
mode_t umask;
|
||||||
struct archive_string mkdirpath;
|
struct archive_string mkdirpath;
|
||||||
struct fixup_entry *fixup_list;
|
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));
|
memset(a->extract, 0, sizeof(*a->extract));
|
||||||
}
|
}
|
||||||
extract = a->extract;
|
extract = a->extract;
|
||||||
|
umask(extract->umask = umask(0)); /* Read the current umask. */
|
||||||
|
|
||||||
restore_pwd = -1;
|
restore_pwd = -1;
|
||||||
|
|
||||||
@ -221,12 +223,10 @@ void archive_extract_cleanup(struct archive *a)
|
|||||||
{
|
{
|
||||||
struct fixup_entry *next, *p;
|
struct fixup_entry *next, *p;
|
||||||
struct extract *extract;
|
struct extract *extract;
|
||||||
mode_t mask;
|
|
||||||
|
|
||||||
/* Sort dir list so directories are fixed up in depth-first order. */
|
/* Sort dir list so directories are fixed up in depth-first order. */
|
||||||
extract = a->extract;
|
extract = a->extract;
|
||||||
p = sort_dir_list(extract->fixup_list);
|
p = sort_dir_list(extract->fixup_list);
|
||||||
umask(mask = umask(0)); /* Read the current umask. */
|
|
||||||
|
|
||||||
while (p != NULL) {
|
while (p != NULL) {
|
||||||
if (p->fixup & FIXUP_TIMES) {
|
if (p->fixup & FIXUP_TIMES) {
|
||||||
@ -238,7 +238,7 @@ void archive_extract_cleanup(struct archive *a)
|
|||||||
utimes(p->name, times);
|
utimes(p->name, times);
|
||||||
}
|
}
|
||||||
if (p->fixup & FIXUP_MODE)
|
if (p->fixup & FIXUP_MODE)
|
||||||
chmod(p->name, p->mode & ~mask);
|
chmod(p->name, p->mode);
|
||||||
|
|
||||||
if (p->fixup & FIXUP_FFLAGS)
|
if (p->fixup & FIXUP_FFLAGS)
|
||||||
set_fflags(a, p->name, p->mode, p->fflags_set, 0);
|
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);
|
le->name = strdup(path);
|
||||||
|
|
||||||
if (mode != writable_mode) {
|
if (mode != writable_mode) {
|
||||||
le->mode = mode;
|
le->mode = mode & ~extract->umask;
|
||||||
le->fixup |= FIXUP_MODE;
|
le->fixup |= FIXUP_MODE;
|
||||||
mode = writable_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)
|
if (mkdir(path, mode) == 0)
|
||||||
return (ARCHIVE_OK);
|
return (ARCHIVE_OK);
|
||||||
/*
|
/*
|
||||||
@ -509,8 +514,23 @@ mkdirpath_recursive(struct archive *a, char *path, const struct stat *st,
|
|||||||
*p = '/'; /* Restore the '/' we just overwrote. */
|
*p = '/'; /* Restore the '/' we just overwrote. */
|
||||||
if (r != ARCHIVE_OK)
|
if (r != ARCHIVE_OK)
|
||||||
return (r);
|
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)
|
if (mkdir(path, mode) == 0)
|
||||||
return (ARCHIVE_OK);
|
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);
|
archive_set_error(a, errno, "Failed to create dir '%s'", path);
|
||||||
return (ARCHIVE_WARN);
|
return (ARCHIVE_WARN);
|
||||||
@ -762,11 +782,14 @@ set_time(struct archive *a, struct archive_entry *entry, int flags)
|
|||||||
static int
|
static int
|
||||||
set_perm(struct archive *a, struct archive_entry *entry, int mode, int flags)
|
set_perm(struct archive *a, struct archive_entry *entry, int mode, int flags)
|
||||||
{
|
{
|
||||||
|
struct extract *extract;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
if ((flags & ARCHIVE_EXTRACT_PERM) == 0)
|
if ((flags & ARCHIVE_EXTRACT_PERM) == 0)
|
||||||
return (ARCHIVE_OK);
|
return (ARCHIVE_OK);
|
||||||
|
|
||||||
|
extract = a->extract;
|
||||||
|
mode &= ~extract->umask; /* Enforce umask. */
|
||||||
name = archive_entry_pathname(entry);
|
name = archive_entry_pathname(entry);
|
||||||
#ifdef HAVE_LCHMOD
|
#ifdef HAVE_LCHMOD
|
||||||
if (lchmod(name, mode) != 0) {
|
if (lchmod(name, mode) != 0) {
|
||||||
|
Loading…
Reference in New Issue
Block a user