Fix tar(1) handling of archives with improper internal order

Not all archives are packed in such way to be generated without
having to recursively generate the output path.

For now, reuse the function from mkdir.c and later move it to
libutil.
This commit is contained in:
sin 2015-04-20 16:31:51 +01:00
parent 3ef6d4e4c9
commit 97905f6991

30
tar.c
View File

@ -4,6 +4,7 @@
#include <errno.h> #include <errno.h>
#include <grp.h> #include <grp.h>
#include <libgen.h>
#include <pwd.h> #include <pwd.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -172,6 +173,29 @@ archive(const char *path)
return 0; return 0;
} }
static int
mkdirp(char *path)
{
char *p;
for (p = path; *p; p++) {
if (*p != '/')
continue;
*p = '\0';
if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) < 0 && errno != EEXIST) {
weprintf("mkdir %s:", path);
*p = '/';
return -1;
}
*p = '/';
}
if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) < 0 && errno != EEXIST) {
weprintf("mkdir %s:", path);
return -1;
}
return 0;
}
static int static int
unarchive(char *fname, ssize_t l, char b[BLKSIZ]) unarchive(char *fname, ssize_t l, char b[BLKSIZ])
{ {
@ -179,13 +203,17 @@ unarchive(char *fname, ssize_t l, char b[BLKSIZ])
struct timeval times[2]; struct timeval times[2];
struct header *h = (void *)b; struct header *h = (void *)b;
long mode, major, minor, type, mtime, uid, gid; long mode, major, minor, type, mtime, uid, gid;
char lname[101], *p; char lname[101], *tmp, *p;
if (!mflag && ((mtime = strtoul(h->mtime, &p, 8)) < 0 || *p != '\0')) if (!mflag && ((mtime = strtoul(h->mtime, &p, 8)) < 0 || *p != '\0'))
eprintf("strtoul %s: invalid number\n", h->mtime); eprintf("strtoul %s: invalid number\n", h->mtime);
if (unlink(fname) < 0 && errno != ENOENT && errno != EISDIR) if (unlink(fname) < 0 && errno != ENOENT && errno != EISDIR)
eprintf("unlink %s:", fname); eprintf("unlink %s:", fname);
tmp = strdup(fname);
mkdirp(dirname(tmp));
free(tmp);
switch (h->type) { switch (h->type) {
case REG: case REG:
case AREG: case AREG: