From 041d732be72a13b9b7250fdab0ea4c46ad9d8326 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Tue, 19 May 2015 12:39:45 +0200 Subject: [PATCH] tar, tarfs: implement longname support this allows extracting tar archives that use longnames extension, where the real filename is stored in a special entry with linkflag == 'L' before the file entry. also skip longlink entries with linkflag == 'K'. --- sys/src/cmd/tapefs/tarfs.c | 26 ++++++++++++++-- sys/src/cmd/tar.c | 64 +++++++++++++++++++++++++++++++++----- 2 files changed, 79 insertions(+), 11 deletions(-) diff --git a/sys/src/cmd/tapefs/tarfs.c b/sys/src/cmd/tapefs/tarfs.c index c58db4bbb..e694b8781 100644 --- a/sys/src/cmd/tapefs/tarfs.c +++ b/sys/src/cmd/tapefs/tarfs.c @@ -14,6 +14,7 @@ enum { Namsiz = 100, Maxpfx = 155, /* from POSIX */ Maxname = Namsiz + 1 + Maxpfx, + Maxlongname = 65535, Binsize = 0x80, /* flag in size[0], from gnu: positive binary size */ Binnegsz = 0xff, /* flag in size[0]: negative binary size */ }; @@ -30,7 +31,12 @@ enum { LF_DIR = '5', LF_FIFO = '6', LF_CONTIG = '7', + /* 'A' - 'Z' are reserved for custom implementations */ + + LF_LONGNAME = 'L', /* GNU extension */ + LF_LONGLINK = 'K', + }; typedef union { @@ -106,7 +112,9 @@ tarname(Hdr *hp) void populate(char *name) { - long chksum, linkflg; + char longname[Maxlongname+1]; + char *nextname = nil; + long chksum, linkflg, namelen; vlong blkno; char *fname; Fileinf f; @@ -121,7 +129,9 @@ populate(char *name) seek(tapefile, Tblock*blkno, 0); if (readn(tapefile, hp->dummy, sizeof hp->dummy) < sizeof hp->dummy) break; - fname = tarname(hp); + fname = nextname, nextname = nil; + if(fname == nil || fname[0] == '\0') + fname = tarname(hp); if (fname[0] == '\0') break; @@ -162,6 +172,16 @@ populate(char *name) if (linkflg) { /*fprint(2, "link %s->%s skipped\n", fname, hp->linkname);*/ f.size = 0; + } else if (hp->linkflag == LF_LONGLINK) { + ; + } else if (hp->linkflag == LF_LONGNAME) { + namelen = Maxlongname; + if(f.size < namelen) + namelen = f.size; + namelen = readn(tapefile, longname, namelen); + if(namelen < 0) namelen = 0; + longname[namelen] = '\0'; + nextname = longname; } else { /* accept this file */ f.name = fname; @@ -169,8 +189,8 @@ populate(char *name) fprint(2, "%s: null name skipped\n", argv0); else poppath(f, 1); - blkno += (f.size + Tblock - 1)/Tblock; } + blkno += (f.size + Tblock - 1)/Tblock; } } diff --git a/sys/src/cmd/tar.c b/sys/src/cmd/tar.c index 9e891b025..242476024 100644 --- a/sys/src/cmd/tar.c +++ b/sys/src/cmd/tar.c @@ -52,6 +52,7 @@ enum { Namsiz = 100, Maxpfx = 155, /* from POSIX */ Maxname = Namsiz + 1 + Maxpfx, + Maxlongname = 65535, Binsize = 0x80, /* flag in size[0], from gnu: positive binary size */ Binnegsz = 0xff, /* flag in size[0]: negative binary size */ @@ -72,7 +73,11 @@ enum { LF_DIR = '5', LF_FIFO = '6', LF_CONTIG = '7', + /* 'A' - 'Z' are reserved for custom implementations */ + + LF_LONGNAME = 'L', /* GNU extenstion */ + LF_LONGLINK = 'K', }; #define islink(lf) (isreallink(lf) || issymlink(lf)) @@ -145,7 +150,7 @@ static Off nexthdr; static int nblock = Dblock; static int resync; static char *usefile, *arname = "archive"; -static char origdir[Maxname*2]; +static char origdir[Maxlongname+1]; static Hdr *tpblk, *endblk; static Hdr *curblk; @@ -934,12 +939,11 @@ replace(char **argv) static int prefix(char *name, char *pfx) { + char clpfx[Maxlongname+1]; int pfxlen = strlen(pfx); - char clpfx[Maxname+1]; - if (pfxlen > Maxname) - return 0; - strcpy(clpfx, pfx); + clpfx[Maxlongname] = '\0'; + strncpy(clpfx, pfx, Maxlongname); cleanname(clpfx); return strncmp(clpfx, name, pfxlen) == 0 && (name[pfxlen] == '\0' || name[pfxlen] == '/'); @@ -948,12 +952,13 @@ prefix(char *name, char *pfx) static int match(char *name, char **argv) { + char clname[Maxlongname+1]; int i; - char clname[Maxname+1]; if (argv[0] == nil) return 1; - strcpy(clname, name); + clname[Maxlongname] = '\0'; + strncpy(clname, name, Maxlongname); cleanname(clname); for (i = 0; argv[i] != nil; i++) if (prefix(clname, argv[i])) @@ -1045,6 +1050,7 @@ openfname(Hdr *hp, char *fname, int dir, int mode) case LF_LINK: case LF_SYMLINK1: case LF_SYMLINK2: + case LF_LONGLINK: fprint(2, "%s: can't make (sym)link %s\n", argv0, fname); break; @@ -1201,6 +1207,46 @@ skip(int ar, Hdr *hp, char *fname) } } +static char* +getname(int ar, Hdr *hp) +{ + static char namebuf[Maxlongname+1], *nextname = nil; + ulong blksleft, blksread; + char *fname, *p; + int n; + + if(nextname != nil && nextname[0] != '\0'){ + fname = nextname, nextname = nil; + return fname; + } + fname = name(hp); + if(hp->linkflag == LF_LONGNAME){ + p = namebuf; + for (blksleft = BYTES2TBLKS(arsize(hp)); blksleft > 0; + blksleft -= blksread) { + hp = getblkrd(ar, Alldata); + if (hp == nil) + sysfatal("unexpected EOF on archive reading %s from %s", + fname, arname); + blksread = gothowmany(blksleft); + n = &namebuf[Maxlongname] - p; + if(Tblock*blksread < n) + n = Tblock*blksread; + memmove(p, hp->data, n); + p += n; + putreadblks(ar, blksread); + } + *p = '\0'; + fname = nil; + nextname = namebuf; + } else { + namebuf[Maxlongname] = '\0'; + strncpy(namebuf, fname, Maxlongname); + fname = namebuf; + } + return fname; +} + static char * extract(char **argv) { @@ -1221,7 +1267,9 @@ extract(char **argv) sysfatal("can't open archive %s: %r", usefile); while ((hp = readhdr(ar)) != nil) { - longname = name(hp); + longname = getname(ar, hp); + if(longname == nil) + continue; if (match(longname, argv)) extract1(ar, hp, longname); else