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'.
This commit is contained in:
parent
76ee4c3988
commit
041d732be7
2 changed files with 79 additions and 11 deletions
|
@ -14,6 +14,7 @@ enum {
|
||||||
Namsiz = 100,
|
Namsiz = 100,
|
||||||
Maxpfx = 155, /* from POSIX */
|
Maxpfx = 155, /* from POSIX */
|
||||||
Maxname = Namsiz + 1 + Maxpfx,
|
Maxname = Namsiz + 1 + Maxpfx,
|
||||||
|
Maxlongname = 65535,
|
||||||
Binsize = 0x80, /* flag in size[0], from gnu: positive binary size */
|
Binsize = 0x80, /* flag in size[0], from gnu: positive binary size */
|
||||||
Binnegsz = 0xff, /* flag in size[0]: negative binary size */
|
Binnegsz = 0xff, /* flag in size[0]: negative binary size */
|
||||||
};
|
};
|
||||||
|
@ -30,7 +31,12 @@ enum {
|
||||||
LF_DIR = '5',
|
LF_DIR = '5',
|
||||||
LF_FIFO = '6',
|
LF_FIFO = '6',
|
||||||
LF_CONTIG = '7',
|
LF_CONTIG = '7',
|
||||||
|
|
||||||
/* 'A' - 'Z' are reserved for custom implementations */
|
/* 'A' - 'Z' are reserved for custom implementations */
|
||||||
|
|
||||||
|
LF_LONGNAME = 'L', /* GNU extension */
|
||||||
|
LF_LONGLINK = 'K',
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
|
@ -106,7 +112,9 @@ tarname(Hdr *hp)
|
||||||
void
|
void
|
||||||
populate(char *name)
|
populate(char *name)
|
||||||
{
|
{
|
||||||
long chksum, linkflg;
|
char longname[Maxlongname+1];
|
||||||
|
char *nextname = nil;
|
||||||
|
long chksum, linkflg, namelen;
|
||||||
vlong blkno;
|
vlong blkno;
|
||||||
char *fname;
|
char *fname;
|
||||||
Fileinf f;
|
Fileinf f;
|
||||||
|
@ -121,7 +129,9 @@ populate(char *name)
|
||||||
seek(tapefile, Tblock*blkno, 0);
|
seek(tapefile, Tblock*blkno, 0);
|
||||||
if (readn(tapefile, hp->dummy, sizeof hp->dummy) < sizeof hp->dummy)
|
if (readn(tapefile, hp->dummy, sizeof hp->dummy) < sizeof hp->dummy)
|
||||||
break;
|
break;
|
||||||
fname = tarname(hp);
|
fname = nextname, nextname = nil;
|
||||||
|
if(fname == nil || fname[0] == '\0')
|
||||||
|
fname = tarname(hp);
|
||||||
if (fname[0] == '\0')
|
if (fname[0] == '\0')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -162,6 +172,16 @@ populate(char *name)
|
||||||
if (linkflg) {
|
if (linkflg) {
|
||||||
/*fprint(2, "link %s->%s skipped\n", fname, hp->linkname);*/
|
/*fprint(2, "link %s->%s skipped\n", fname, hp->linkname);*/
|
||||||
f.size = 0;
|
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 {
|
} else {
|
||||||
/* accept this file */
|
/* accept this file */
|
||||||
f.name = fname;
|
f.name = fname;
|
||||||
|
@ -169,8 +189,8 @@ populate(char *name)
|
||||||
fprint(2, "%s: null name skipped\n", argv0);
|
fprint(2, "%s: null name skipped\n", argv0);
|
||||||
else
|
else
|
||||||
poppath(f, 1);
|
poppath(f, 1);
|
||||||
blkno += (f.size + Tblock - 1)/Tblock;
|
|
||||||
}
|
}
|
||||||
|
blkno += (f.size + Tblock - 1)/Tblock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ enum {
|
||||||
Namsiz = 100,
|
Namsiz = 100,
|
||||||
Maxpfx = 155, /* from POSIX */
|
Maxpfx = 155, /* from POSIX */
|
||||||
Maxname = Namsiz + 1 + Maxpfx,
|
Maxname = Namsiz + 1 + Maxpfx,
|
||||||
|
Maxlongname = 65535,
|
||||||
Binsize = 0x80, /* flag in size[0], from gnu: positive binary size */
|
Binsize = 0x80, /* flag in size[0], from gnu: positive binary size */
|
||||||
Binnegsz = 0xff, /* flag in size[0]: negative binary size */
|
Binnegsz = 0xff, /* flag in size[0]: negative binary size */
|
||||||
|
|
||||||
|
@ -72,7 +73,11 @@ enum {
|
||||||
LF_DIR = '5',
|
LF_DIR = '5',
|
||||||
LF_FIFO = '6',
|
LF_FIFO = '6',
|
||||||
LF_CONTIG = '7',
|
LF_CONTIG = '7',
|
||||||
|
|
||||||
/* 'A' - 'Z' are reserved for custom implementations */
|
/* 'A' - 'Z' are reserved for custom implementations */
|
||||||
|
|
||||||
|
LF_LONGNAME = 'L', /* GNU extenstion */
|
||||||
|
LF_LONGLINK = 'K',
|
||||||
};
|
};
|
||||||
|
|
||||||
#define islink(lf) (isreallink(lf) || issymlink(lf))
|
#define islink(lf) (isreallink(lf) || issymlink(lf))
|
||||||
|
@ -145,7 +150,7 @@ static Off nexthdr;
|
||||||
static int nblock = Dblock;
|
static int nblock = Dblock;
|
||||||
static int resync;
|
static int resync;
|
||||||
static char *usefile, *arname = "archive";
|
static char *usefile, *arname = "archive";
|
||||||
static char origdir[Maxname*2];
|
static char origdir[Maxlongname+1];
|
||||||
static Hdr *tpblk, *endblk;
|
static Hdr *tpblk, *endblk;
|
||||||
static Hdr *curblk;
|
static Hdr *curblk;
|
||||||
|
|
||||||
|
@ -934,12 +939,11 @@ replace(char **argv)
|
||||||
static int
|
static int
|
||||||
prefix(char *name, char *pfx)
|
prefix(char *name, char *pfx)
|
||||||
{
|
{
|
||||||
|
char clpfx[Maxlongname+1];
|
||||||
int pfxlen = strlen(pfx);
|
int pfxlen = strlen(pfx);
|
||||||
char clpfx[Maxname+1];
|
|
||||||
|
|
||||||
if (pfxlen > Maxname)
|
clpfx[Maxlongname] = '\0';
|
||||||
return 0;
|
strncpy(clpfx, pfx, Maxlongname);
|
||||||
strcpy(clpfx, pfx);
|
|
||||||
cleanname(clpfx);
|
cleanname(clpfx);
|
||||||
return strncmp(clpfx, name, pfxlen) == 0 &&
|
return strncmp(clpfx, name, pfxlen) == 0 &&
|
||||||
(name[pfxlen] == '\0' || name[pfxlen] == '/');
|
(name[pfxlen] == '\0' || name[pfxlen] == '/');
|
||||||
|
@ -948,12 +952,13 @@ prefix(char *name, char *pfx)
|
||||||
static int
|
static int
|
||||||
match(char *name, char **argv)
|
match(char *name, char **argv)
|
||||||
{
|
{
|
||||||
|
char clname[Maxlongname+1];
|
||||||
int i;
|
int i;
|
||||||
char clname[Maxname+1];
|
|
||||||
|
|
||||||
if (argv[0] == nil)
|
if (argv[0] == nil)
|
||||||
return 1;
|
return 1;
|
||||||
strcpy(clname, name);
|
clname[Maxlongname] = '\0';
|
||||||
|
strncpy(clname, name, Maxlongname);
|
||||||
cleanname(clname);
|
cleanname(clname);
|
||||||
for (i = 0; argv[i] != nil; i++)
|
for (i = 0; argv[i] != nil; i++)
|
||||||
if (prefix(clname, argv[i]))
|
if (prefix(clname, argv[i]))
|
||||||
|
@ -1045,6 +1050,7 @@ openfname(Hdr *hp, char *fname, int dir, int mode)
|
||||||
case LF_LINK:
|
case LF_LINK:
|
||||||
case LF_SYMLINK1:
|
case LF_SYMLINK1:
|
||||||
case LF_SYMLINK2:
|
case LF_SYMLINK2:
|
||||||
|
case LF_LONGLINK:
|
||||||
fprint(2, "%s: can't make (sym)link %s\n",
|
fprint(2, "%s: can't make (sym)link %s\n",
|
||||||
argv0, fname);
|
argv0, fname);
|
||||||
break;
|
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 *
|
static char *
|
||||||
extract(char **argv)
|
extract(char **argv)
|
||||||
{
|
{
|
||||||
|
@ -1221,7 +1267,9 @@ extract(char **argv)
|
||||||
sysfatal("can't open archive %s: %r", usefile);
|
sysfatal("can't open archive %s: %r", usefile);
|
||||||
|
|
||||||
while ((hp = readhdr(ar)) != nil) {
|
while ((hp = readhdr(ar)) != nil) {
|
||||||
longname = name(hp);
|
longname = getname(ar, hp);
|
||||||
|
if(longname == nil)
|
||||||
|
continue;
|
||||||
if (match(longname, argv))
|
if (match(longname, argv))
|
||||||
extract1(ar, hp, longname);
|
extract1(ar, hp, longname);
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in a new issue