ref: 041d732be72a13b9b7250fdab0ea4c46ad9d8326
parent: 76ee4c3988f4f4e89514c203d8b7781abd29f24a
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Tue May 19 08:39:45 EDT 2015
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'.
--- a/sys/src/cmd/tapefs/tarfs.c
+++ b/sys/src/cmd/tapefs/tarfs.c
@@ -14,6 +14,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
fprint(2, "%s: null name skipped\n", argv0);
else
poppath(f, 1);
- blkno += (f.size + Tblock - 1)/Tblock;
}
+ blkno += (f.size + Tblock - 1)/Tblock;
}
}
--- a/sys/src/cmd/tar.c
+++ b/sys/src/cmd/tar.c
@@ -52,6 +52,7 @@
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 @@
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 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 @@
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 @@
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 @@
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 @@
}
}
+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 @@
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