--- tar.c | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/tar.c b/tar.c index 934b9c6..ee75e6c 100644 --- a/tar.c +++ b/tar.c _AT_@ -30,7 +30,8 @@ enum Type { BLOCKDEV = '4', DIRECTORY = '5', FIFO = '6', - RESERVED = '7' + RESERVED = '7', + LONGNAME = 'L', }; struct header { _AT_@ -449,15 +450,15 @@ xt(int argc, char *argv[], int mode) struct timespec times[2]; struct header *h = (struct header *)b; struct dirtime *dirtime; - long size; - int i, n; + long n, size; + int i; int (*fn)(char *, ssize_t, char[BLKSIZ]) = (mode == 'x') ? unarchive : print; long fnmax = 256 + 1; char *fname = ecalloc(1, fnmax); while (eread(tarfd, b, BLKSIZ) > 0 && h->name[0]) { chktar(h); - sanitize(h), n = 0; + sanitize(h); if ((size = strtol(h->size, &p, 8)) < 0 || *p != '\0') eprintf("strtol %s: invalid number\n", h->size); _AT_@ -468,14 +469,35 @@ xt(int argc, char *argv[], int mode) case 'x': skipblk(size); continue; + + /* GNU tar long filename */ + case LONGNAME: + if (size > fnmax) { + fnmax = size; + free(fname); + fname = ecalloc(1, fnmax); + } + for (n = 0; n < size; n += BLKSIZ) { + if (!(eread(tarfd, b, BLKSIZ) > 0)) + eprintf("corrupt long filename\n"); + memcpy(fname + n, b, MIN(size - n, BLKSIZ)); + } + /* the filename must already be NUL-terminated in the archive */ + if (!size || fname[size-1]) + eprintf("corrupt long filename\n"); + continue; } - /* small dance around non-null terminated fields */ - if (h->prefix[0]) - n = snprintf(fname, fnmax, "%.*s/", - (int)sizeof(h->prefix), h->prefix); - snprintf(fname + n, fnmax - n, "%.*s", - (int)sizeof(h->name), h->name); + /* only read filename if we don't already have a long name queued up */ + if (!fname[0]) { + /* small dance around non-null terminated fields */ + n = 0; + if (h->prefix[0]) + n = snprintf(fname, fnmax, "%.*s/", + (int)sizeof(h->prefix), h->prefix); + snprintf(fname + n, fnmax - n, "%.*s", + (int)sizeof(h->name), h->name); + } if (argc) { /* only extract the given files */ _AT_@ -491,6 +513,8 @@ xt(int argc, char *argv[], int mode) fn(fname, size, b); if (vflag && mode != 't') puts(fname); + + fname[0] = 0; } free(fname); -- 2.28.0Received on Thu Nov 26 2020 - 14:53:46 CET
This archive was generated by hypermail 2.3.0 : Thu Nov 26 2020 - 15:00:37 CET