sbase

suckless unix tools
git clone git://git.suckless.org/sbase
Log | Files | Refs | README | LICENSE

commit 258d0793ac830d247f8c7b54c7749f04f583faa4
parent fde9e29d05d754aeb133af0d58802494b591bc1c
Author: sin <sin@2f30.org>
Date:   Tue, 21 Apr 2015 15:29:22 +0100

tar: Allow extracting only a given list of files

tar -xf foo.tar a b c

Diffstat:
Mtar.c | 26+++++++++++++++++---------
1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/tar.c b/tar.c @@ -313,26 +313,34 @@ sanitize(struct header *h) } 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; - struct header *h; + struct header *h = (struct header *)b; 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)) { - sanitize(h); - n = 0; + /* small dance around non-null terminated fields */ if (h->prefix[0]) n = snprintf(fname, sizeof(fname), "%.*s/", (int)sizeof(h->prefix), h->prefix); snprintf(fname + n, sizeof(fname) - n, "%.*s", (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') eprintf("strtol %s: invalid number\n", h->size); - fn(fname, size, b); } if (ferror(tarfile)) @@ -430,7 +438,7 @@ main(int argc, char *argv[]) if (chdir(dir) < 0) eprintf("chdir %s:", dir); - xt((mode == 'x') ? unarchive : print); + xt(argc, argv, (mode == 'x') ? unarchive : print); break; }