tar: Allow extracting only a given list of files

tar -xf foo.tar a b c
This commit is contained in:
sin 2015-04-21 15:29:22 +01:00
parent fde9e29d05
commit 258d0793ac

26
tar.c
View File

@ -313,26 +313,34 @@ sanitize(struct header *h)
} }
static void static void
xt(int (*fn)(char *, ssize_t, char[BLKSIZ])) xt(int argc, char *argv[], int (*fn)(char *, ssize_t, char[BLKSIZ]))
{ {
char b[BLKSIZ], fname[256 + 1], *p; char b[BLKSIZ], fname[256 + 1], *p;
struct header *h; struct header *h = (struct header *)b;
long size; long size;
int n; int i, n;
h = (void *)b; while (fread(b, BLKSIZ, 1, tarfile) == 1 && *h->name) {
sanitize(h), n = 0;
while (fread(b, BLKSIZ, 1, tarfile) == 1 && *(h->name)) { /* small dance around non-null terminated fields */
sanitize(h);
n = 0;
if (h->prefix[0]) if (h->prefix[0])
n = snprintf(fname, sizeof(fname), "%.*s/", n = snprintf(fname, sizeof(fname), "%.*s/",
(int)sizeof(h->prefix), h->prefix); (int)sizeof(h->prefix), h->prefix);
snprintf(fname + n, sizeof(fname) - n, "%.*s", snprintf(fname + n, sizeof(fname) - n, "%.*s",
(int)sizeof(h->name), h->name); (int)sizeof(h->name), h->name);
if (argc) {
/* only extract the given files */
for (i = 0; i < argc; i++)
if (!strcmp(argv[i], fname))
break;
if (i == argc)
continue;
}
if ((size = strtol(h->size, &p, 8)) < 0 || *p != '\0') if ((size = strtol(h->size, &p, 8)) < 0 || *p != '\0')
eprintf("strtol %s: invalid number\n", h->size); eprintf("strtol %s: invalid number\n", h->size);
fn(fname, size, b); fn(fname, size, b);
} }
if (ferror(tarfile)) if (ferror(tarfile))
@ -430,7 +438,7 @@ main(int argc, char *argv[])
if (chdir(dir) < 0) if (chdir(dir) < 0)
eprintf("chdir %s:", dir); eprintf("chdir %s:", dir);
xt((mode == 'x') ? unarchive : print); xt(argc, argv, (mode == 'x') ? unarchive : print);
break; break;
} }