LF_LONGNAME = 'L', /* GNU extenstion */
LF_LONGLINK = 'K',
+ LF_PAXHDR = 'x', /* PAX header */
+ LF_PAXGLOBL = 'g',
};
#define islink(lf) (isreallink(lf) || issymlink(lf))
char devminor[8];
char prefix[Maxpfx]; /* if non-null, path= prefix "/" name */
};
+} Blk;
+
+typedef struct {
+ char *name;
+ char *uid;
+ char *gid;
+ ulong mode;
+ vlong size;
+ vlong mtime;
+ vlong atime;
} Hdr;
typedef struct {
#define OTHER(rdwr) ((rdwr) == Rd? Wr: Rd)
-static int debug;
static int fixednblock;
static int verb;
static int posix = 1;
static int resync;
static char *usefile, *arname = "archive";
static char origdir[Maxlongname+1];
-static Hdr *tpblk, *endblk;
-static Hdr *curblk;
+static Blk *tpblk, *endblk;
+static Blk *curblk;
+static Hdr globlhdr;
static void
usage(void)
static Compress *
compmethod(char *name)
{
- int i, nmlen = strlen(name), sfxlen;
- Compress *cp;
-
- for (cp = comps; cp < comps + nelem(comps); cp++)
- for (i = 0; i < nelem(cp->sfx) && cp->sfx[i]; i++) {
- sfxlen = strlen(cp->sfx[i]);
- if (nmlen > sfxlen &&
- strcmp(cp->sfx[i], name + nmlen - sfxlen) == 0)
- return cp;
+ if (name) {
+ int i, nmlen, sfxlen;
+ Compress *cp;
+
+ nmlen = strlen(name);
+ for (cp = comps; cp < comps + nelem(comps); cp++) {
+ for (i = 0; i < nelem(cp->sfx) && cp->sfx[i]; i++) {
+ sfxlen = strlen(cp->sfx[i]);
+ if (nmlen > sfxlen &&
+ strcmp(cp->sfx[i], name + nmlen - sfxlen) == 0)
+ return cp;
+ }
}
+ }
return docompress? comps: nil;
}
if (i != nblock) {
nblock = i;
fprint(2, "%s: blocking = %d\n", argv0, nblock);
- endblk = (Hdr *)bufs + nblock;
+ endblk = (Blk *)bufs + nblock;
bytes = n;
}
} else if (justhdr && seekable && nexthdr - blkoff >= bytes) {
return bufs;
}
-static Hdr *
+static Blk *
getblk(int ar, Refill rfp, int justhdr)
{
if (curblk == nil || curblk >= endblk) { /* input block exhausted? */
return curblk++;
}
-static Hdr *
+static Blk *
getblkrd(int ar, int justhdr)
{
return getblk(ar, refill, justhdr);
}
-static Hdr *
+static Blk *
getblke(int ar)
{
return getblk(ar, nil, Alldata);
}
-static Hdr *
+static Blk *
getblkz(int ar)
{
- Hdr *hp = getblke(ar);
+ Blk *bp = getblke(ar);
- if (hp != nil)
- memset(hp->data, 0, Tblock);
- return hp;
+ if (bp != nil)
+ memset(bp->data, 0, Tblock);
+ return bp;
}
/*
* old archive when updating with `tar rf archive'
*/
static long
-chksum(Hdr *hp)
+chksum(Blk *bp)
{
int n = Tblock;
long i = 0;
- uchar *cp = hp->data;
- char oldsum[sizeof hp->chksum];
+ uchar *cp = bp->data;
+ char oldsum[sizeof bp->chksum];
- memmove(oldsum, hp->chksum, sizeof oldsum);
- memset(hp->chksum, ' ', sizeof hp->chksum);
+ memmove(oldsum, bp->chksum, sizeof oldsum);
+ memset(bp->chksum, ' ', sizeof bp->chksum);
while (n-- > 0)
i += *cp++;
- memmove(hp->chksum, oldsum, sizeof oldsum);
+ memmove(bp->chksum, oldsum, sizeof oldsum);
return i;
}
static int
-isustar(Hdr *hp)
+isustar(Blk *bp)
{
- return strcmp(hp->magic, "ustar") == 0;
+ return strcmp(bp->magic, "ustar") == 0;
}
/*
/* set fullname from header */
static char *
-name(Hdr *hp)
+parsename(Blk *bp, char *buf, int nbuf)
{
int pfxlen, namlen;
- char *fullname;
- static char fullnamebuf[2+Maxname+1]; /* 2+ for ./ on relative names */
-
- fullname = fullnamebuf+2;
- namlen = strnlen(hp->name, sizeof hp->name);
- if (hp->prefix[0] == '\0' || !isustar(hp)) { /* old-style name? */
- memmove(fullname, hp->name, namlen);
- fullname[namlen] = '\0';
- return fullname;
+
+ namlen = strnlen(bp->name, sizeof bp->name);
+ if (bp->prefix[0] == '\0' || !isustar(bp)) { /* old-style name? */
+ assert(nbuf > namlen);
+ memmove(buf, bp->name, namlen);
+ buf[namlen] = '\0';
+ return buf;
}
/* name is in two pieces */
- pfxlen = strnlen(hp->prefix, sizeof hp->prefix);
- memmove(fullname, hp->prefix, pfxlen);
- fullname[pfxlen] = '/';
- memmove(fullname + pfxlen + 1, hp->name, namlen);
- fullname[pfxlen + 1 + namlen] = '\0';
- return fullname;
+ pfxlen = strnlen(bp->prefix, sizeof bp->prefix);
+ assert(nbuf > pfxlen + 1 + namlen);
+ memmove(buf, bp->prefix, pfxlen);
+ buf[pfxlen] = '/';
+ memmove(buf + pfxlen + 1, bp->name, namlen);
+ buf[pfxlen + 1 + namlen] = '\0';
+ return buf;
}
static int
-isdir(Hdr *hp)
+isdir(Blk *bp, char *name)
{
/* the mode test is ugly but sometimes necessary */
- return hp->linkflag == LF_DIR ||
- strrchr(name(hp), '\0')[-1] == '/' ||
- (strtoul(hp->mode, nil, 8)&0170000) == 040000;
+ return bp->linkflag == LF_DIR ||
+ strrchr(name, '\0')[-1] == '/' ||
+ (strtoul(bp->mode, nil, 8)&0170000) == 040000;
}
static int
-eotar(Hdr *hp)
+eotar(Blk *bp)
{
- return name(hp)[0] == '\0';
+ char buf[Maxname + 1];
+ return parsename(bp, buf, sizeof(buf))[0] == '\0';
}
/*
* 2^64-1 (actually 2^80-1 but our file sizes are vlongs) rather than 2^33-1.
*/
static Off
-hdrsize(Hdr *hp)
+hdrsize(Blk *bp)
{
uchar *p;
+ char buf[Maxname + 1];
- if((uchar)hp->size[0] == Binnegsz) {
+ if((uchar)bp->size[0] == Binnegsz) {
fprint(2, "%s: %s: negative length, which is insane\n",
- argv0, name(hp));
+ argv0, parsename(bp, buf, sizeof(buf)));
return 0;
- } else if((uchar)hp->size[0] == Binsize) {
- p = (uchar *)hp->size + sizeof hp->size - 1 -
+ } else if((uchar)bp->size[0] == Binsize) {
+ p = (uchar *)bp->size + sizeof bp->size - 1 -
sizeof(vlong); /* -1 for terminating space */
return G8BEBYTE(p);
}
- return hdrotoull(hp->size, hp->size + sizeof hp->size, 0,
- name(hp), "size");
+ return hdrotoull(bp->size, bp->size + sizeof bp->size, 0,
+ parsename(bp, buf, sizeof(buf)), "size");
}
/*
* return the number of bytes recorded in the archive.
*/
static Off
-arsize(Hdr *hp)
+arsize(Blk *bp, char *fname)
{
- if(isdir(hp) || islink(hp->linkflag))
+ if(isdir(bp, fname) || islink(bp->linkflag))
return 0;
- return hdrsize(hp);
+ return hdrsize(bp);
}
static long
parsecksum(char *cksum, char *name)
{
- Hdr *hp;
+ Blk *bp;
- return hdrotoull(cksum, cksum + sizeof hp->chksum, (uvlong)-1LL,
+ return hdrotoull(cksum, cksum + sizeof bp->chksum, (uvlong)-1LL,
name, "checksum");
}
-static Hdr *
-readhdr(int ar)
+static Blk *
+readhdrblk(int ar)
{
+ char buf[Maxname + 1];
long hdrcksum;
- Hdr *hp;
+ Blk *bp;
- hp = getblkrd(ar, Alldata);
- if (hp == nil)
+ bp = getblkrd(ar, Alldata);
+ if (bp == nil)
sysfatal("unexpected EOF instead of archive header in %s",
arname);
- if (eotar(hp)) /* end-of-archive block? */
+ if (eotar(bp)) /* end-of-archive block? */
return nil;
- hdrcksum = parsecksum(hp->chksum, name(hp));
- if (hdrcksum == -1 || chksum(hp) != hdrcksum) {
+ hdrcksum = parsecksum(bp->chksum, parsename(bp, buf, sizeof(buf)));
+ if (hdrcksum == -1 || chksum(bp) != hdrcksum) {
if (!resync)
sysfatal("bad archive header checksum in %s: "
"name %.100s...; expected %#luo got %#luo",
- arname, hp->name, hdrcksum, chksum(hp));
+ arname, bp->name, hdrcksum, chksum(bp));
fprint(2, "%s: skipping past archive header with bad checksum in %s...",
argv0, arname);
do {
- hp = getblkrd(ar, Alldata);
- if (hp == nil)
+ bp = getblkrd(ar, Alldata);
+ if (bp == nil)
sysfatal("unexpected EOF looking for archive header in %s",
arname);
- hdrcksum = parsecksum(hp->chksum, name(hp));
- } while (hdrcksum == -1 || chksum(hp) != hdrcksum);
- fprint(2, "found %s\n", name(hp));
+ hdrcksum = parsecksum(bp->chksum, parsename(bp, buf, sizeof(buf)));
+ } while (hdrcksum == -1 || chksum(bp) != hdrcksum);
+ fprint(2, "found %s\n", parsename(bp, buf, sizeof(buf)));
}
- nexthdr += Tblock*(1 + BYTES2TBLKS(arsize(hp)));
- return hp;
+ nexthdr += Tblock*(1 + BYTES2TBLKS(hdrsize(bp)));
+
+ return bp;
}
-/*
- * tar r[c]
- */
+static int
+getname(int ar, Blk *bp, Hdr *hdr)
+{
+ char buf[Maxlongname+1];
+ ulong blksleft, blksread;
+ char *p;
+ int n;
+
+ if (bp->linkflag != LF_LONGNAME){
+ /* PAX attributes take precedence */
+ if(hdr->name == nil)
+ hdr->name = strdup(parsename(bp, buf, sizeof(buf)));
+ return 0;
+ }
+
+ p = buf;
+ for (blksleft = BYTES2TBLKS(hdrsize(bp)); blksleft > 0; blksleft -= blksread) {
+ bp = getblkrd(ar, Alldata);
+ if (bp == nil)
+ sysfatal("unexpected EOF on archive reading from %s", arname);
+ blksread = gothowmany(blksleft);
+ n = &buf[Maxlongname] - p;
+ if(Tblock*blksread < n)
+ n = Tblock*blksread;
+ memmove(p, bp->data, n);
+ p += n;
+ }
+ *p = '\0';
+ hdr->name = strdup(buf);
+ return 1;
+}
+
+static char *
+matchattr(char *kvp, char *k)
+{
+ if (strncmp(kvp, k, strlen(k)) == 0)
+ return kvp + strlen(k);
+ return nil;
+}
+
+static int
+parsepax(int ar, Blk *bp, Hdr *hdr, int paxtype)
+{
+ char *p, *lp, *le, *e, *kvp, *val, lenbuf[16];
+ ulong blksleft;
+ int n, off, len;
+ Blk *b;
+
+ if (!isustar(bp) || bp->linkflag != paxtype)
+ return 0;
+ off = 0;
+ len = -1;
+ kvp = nil;
+ lp = lenbuf;
+ le = lenbuf + sizeof(lenbuf);
+ for (blksleft = BYTES2TBLKS(hdrsize(bp)); blksleft > 0; ) {
+ b = getblkrd(ar, Alldata);
+ if (b == nil)
+ sysfatal("unexpected EOF on archive reading attr for %s from %s", bp->name, arname);
+ p = (char *)b->data;
+ e = (char *)b->data + sizeof(b->data);
+ while(p != e) {
+ if(*p == '\0')
+ break;
+ /*
+ * Copy out the length prefix. This may span a block boundary, so be
+ * careful about when we get the next block. The length prefix includes
+ * both its own length and the trailing newline. We want to trim the
+ * length prefix, since we already consumed it.
+ */
+ if(len == -1){
+ while(p != e && *p >= '0' && *p <= '9'){
+ if(lp + 1 == le)
+ sysfatal("oversize length prefix in pax header");
+ *lp++ = *p++;
+ }
+ if (p == e && blksleft > 0)
+ goto nextblk;
+ if (*p++ != ' ')
+ sysfatal("invalid delimiter in pax header: %c (%s)\n", *p, p);
+ *lp++ = '\0';
+ len = atoi(lenbuf) - strlen(lenbuf) - 1;
+ }
+
+ if (kvp == nil && (kvp = malloc(len)) == nil)
+ sysfatal("out of memory: %r");
+ n = (len - off > e - p) ? e - p : len - off;
+ memcpy(kvp + off, p, n);
+ kvp[len - 1] = '\0';
+ off += n;
+ p += n;
+ assert(e >= p);
+ if (len == off) {
+ if ((val = matchattr(kvp, "path=")) != nil) {
+ free(hdr->name);
+ hdr->name = strdup(val);
+ } else if ((val = matchattr(kvp, "linkpath=")) != nil) {
+ /* Mostly for better error messages. */
+ free(hdr->name);
+ hdr->name = strdup(val);
+ } else if ((val = matchattr(kvp, "uname=")) != nil) {
+ free(hdr->uid);
+ hdr->uid = strdup(val);
+ } else if ((val = matchattr(kvp, "gname=")) != nil) {
+ free(hdr->gid);
+ hdr->gid = strdup(val);
+ } else if ((val = matchattr(kvp, "atime=")) != nil)
+ hdr->atime = strtoll(val, nil, 0);
+ else if ((val = matchattr(kvp, "mtime=")) != nil)
+ hdr->mtime = strtoll(val, nil, 0);
+ else if ((val = matchattr(kvp, "size=")) != nil)
+ hdr->size = strtoll(val, nil, 0);
+ else
+ if (matchattr(kvp, "comment=") == nil && matchattr(kvp, "ctime=") == nil)
+ fprint(2, "warning: pax attribute not supported: %s\n", kvp);
+ free(kvp);
+ kvp = nil;
+ lp = lenbuf;
+ off = 0;
+ len = -1;
+ }
+ }
+nextblk:
+ blksleft--;
+ }
+ return 1;
+}
+
+static int
+parsehdr(Hdr *hdr, Blk *bp)
+{
+ int ustar;
+
+ ustar = isustar(bp);
+ if(hdr->mode == -1)
+ hdr->mode = (strtoul(bp->mode, nil, 8) & 0777);
+ if(hdr->mode == -1)
+ hdr->mode = globlhdr.mode;
+ if (isdir(bp, hdr->name))
+ hdr->mode |= DMDIR;
+ if (hdr->atime == -1)
+ hdr->atime = -1;
+ if (hdr->atime == -1)
+ hdr->atime = globlhdr.atime;
+ if (hdr->mtime == -1)
+ hdr->mtime = strtol(bp->mtime, nil, 8);
+ if (hdr->mtime == -1)
+ hdr->mtime = globlhdr.mtime;
+ if (hdr->size == -1)
+ hdr->size = arsize(bp, hdr->name);
+ if (ustar && hdr->uid == nil)
+ hdr->uid = strdup(bp->uname);
+ if (hdr->uid == nil)
+ hdr->uid = (globlhdr.uid != nil) ? strdup(globlhdr.uid) : nil;
+ if (ustar && hdr->gid == nil)
+ hdr->gid = strdup(bp->uname);
+ if (hdr->gid == nil)
+ hdr->gid = (globlhdr.gid != nil) ? strdup(globlhdr.gid) : nil;
+ return 0;
+}
+
+static void
+nullhdr(Hdr *hdr)
+{
+ hdr->name = nil;
+ hdr->uid = nil;
+ hdr->gid = nil;
+ hdr->mode = -1;
+ hdr->mtime = -1;
+ hdr->atime = -1;
+ hdr->size = -1;
+}
+
+static Blk *
+readhdr(int ar, Hdr *hdr)
+{
+ Blk *bp;
+
+ nullhdr(hdr);
+again:
+ if ((bp = readhdrblk(ar)) == nil)
+ return nil;
+ if (parsepax(ar, bp, hdr, LF_PAXHDR))
+ goto again;
+ if (parsepax(ar, bp, &globlhdr, LF_PAXGLOBL))
+ goto again;
+ if (getname(ar, bp, hdr))
+ goto again;
+ if (parsehdr(hdr, bp) == -1)
+ sysfatal("could not parse header: %r");
+
+ return bp;
+}
+
+void
+freehdr(Hdr *hdr)
+{
+ free(hdr->name);
+ free(hdr->uid);
+ free(hdr->gid);
+}
/*
* if name is longer than Namsiz bytes, try to split it at a slash and fit the
- * pieces into hp->prefix and hp->name.
+ * pieces into bp->prefix and bp->name.
*/
static int
-putfullname(Hdr *hp, char *name)
+putfullname(Blk *bp, char *name)
{
int namlen, pfxlen;
char *sl, *osl;
String *slname = nil;
- if (isdir(hp)) {
+ if (isdir(bp, name)) {
slname = s_new();
s_append(slname, name);
s_append(slname, "/"); /* posix requires this */
namlen = strlen(name);
if (namlen <= Namsiz) {
- strncpy(hp->name, name, Namsiz);
- hp->prefix[0] = '\0'; /* ustar paranoia */
+ strncpy(bp->name, name, Namsiz);
+ bp->prefix[0] = '\0'; /* ustar paranoia */
return 0;
}
* try various splits until one results in pieces that fit into the
* appropriate fields of the header. look for slashes from right
* to left, in the hopes of putting the largest part of the name into
- * hp->prefix, which is larger than hp->name.
+ * bp->prefix, which is larger than bp->name.
*/
sl = strrchr(name, '/');
while (sl != nil) {
pfxlen = sl - name;
- if (pfxlen <= sizeof hp->prefix && namlen-1 - pfxlen <= Namsiz)
+ if (pfxlen <= sizeof bp->prefix && namlen-1 - pfxlen <= Namsiz)
break;
osl = sl;
*osl = '\0';
return -1;
}
*sl = '\0';
- strncpy(hp->prefix, name, sizeof hp->prefix);
+ strncpy(bp->prefix, name, sizeof bp->prefix);
*sl++ = '/';
- strncpy(hp->name, sl, sizeof hp->name);
+ strncpy(bp->name, sl, sizeof bp->name);
if (slname)
s_free(slname);
return 0;
}
static int
-mkhdr(Hdr *hp, Dir *dir, char *file)
+mkhdr(Blk *bp, Dir *dir, char *file)
{
int r;
* some of these fields run together, so we format them left-to-right
* and don't use snprint.
*/
- sprint(hp->mode, "%6lo ", dir->mode & 0777);
- sprint(hp->uid, "%6o ", aruid);
- sprint(hp->gid, "%6o ", argid);
+ sprint(bp->mode, "%6lo ", dir->mode & 0777);
+ sprint(bp->uid, "%6o ", aruid);
+ sprint(bp->gid, "%6o ", argid);
if (dir->length >= (Off)1<<32) {
static int printed;
printed = 1;
fprint(2, "%s: storing large sizes in \"base 256\"\n", argv0);
}
- hp->size[0] = Binsize;
+ bp->size[0] = Binsize;
/* emit so-called `base 256' representation of size */
- putbe((uchar *)hp->size+1, dir->length, sizeof hp->size - 2);
- hp->size[sizeof hp->size - 1] = ' ';
+ putbe((uchar *)bp->size+1, dir->length, sizeof bp->size - 2);
+ bp->size[sizeof bp->size - 1] = ' ';
} else
- sprint(hp->size, "%11lluo ", dir->length);
- sprint(hp->mtime, "%11luo ", dir->mtime);
- hp->linkflag = (dir->mode&DMDIR? LF_DIR: LF_PLAIN1);
- r = putfullname(hp, file);
+ sprint(bp->size, "%11lluo ", dir->length);
+ sprint(bp->mtime, "%11luo ", dir->mtime);
+ bp->linkflag = (dir->mode&DMDIR? LF_DIR: LF_PLAIN1);
+ r = putfullname(bp, file);
if (posix) {
- strncpy(hp->magic, "ustar", sizeof hp->magic);
- strncpy(hp->version, "00", sizeof hp->version);
- strncpy(hp->uname, dir->uid, sizeof hp->uname);
- strncpy(hp->gname, dir->gid, sizeof hp->gname);
+ strncpy(bp->magic, "ustar", sizeof bp->magic);
+ strncpy(bp->version, "00", sizeof bp->version);
+ strncpy(bp->uname, dir->uid, sizeof bp->uname);
+ strncpy(bp->gname, dir->gid, sizeof bp->gname);
}
- sprint(hp->chksum, "%6luo", chksum(hp));
+ sprint(bp->chksum, "%6luo", chksum(bp));
return r;
}
int n, fd, isdir;
long bytes, blksread;
ulong blksleft;
- Hdr *hbp;
+ Blk *hbp;
Dir *dir;
String *name = nil;
int i, ar;
ulong blksleft, blksread;
Off bytes;
- Hdr *hp;
+ Blk *bp;
Compress *comp = nil;
Pushstate ps;
- if (usefile && docreate) {
+ if (usefile && docreate)
ar = create(usefile, OWRITE, 0666);
- if (docompress)
- comp = compmethod(usefile);
- } else if (usefile)
+ else if (usefile)
ar = open(usefile, ORDWR);
else
ar = Stdout;
- if (comp)
- ar = push(ar, comp->comp, Output, &ps);
+ if (docreate && docompress) {
+ comp = compmethod(usefile);
+ if (comp)
+ ar = push(ar, comp->comp, Output, &ps);
+ }
if (ar < 0)
sysfatal("can't open archive %s: %r", usefile);
if (usefile && !docreate) {
/* skip quickly to the end */
- while ((hp = readhdr(ar)) != nil) {
- bytes = arsize(hp);
+ while ((bp = readhdrblk(ar)) != nil) {
+ bytes = hdrsize(bp);
for (blksleft = BYTES2TBLKS(bytes);
blksleft > 0 && getblkrd(ar, Justnxthdr) != nil;
blksleft -= blksread) {
}
static int
-openfname(Hdr *hp, char *fname, int dir, int mode)
+openfname(Blk *bp, char *fname, int mode)
{
- int fd;
+ int fd, dir;
fd = -1;
+ dir = mode & DMDIR;
cleanname(fname);
- switch (hp->linkflag) {
+ switch (bp->linkflag) {
case LF_LINK:
case LF_SYMLINK1:
case LF_SYMLINK2:
break;
default:
if (!keepexisting || access(fname, AEXIST) < 0) {
- int rw = (dir? OREAD: OWRITE);
+ int rw = (dir ? OREAD: OWRITE);
fd = create(fname, rw, mode);
if (fd < 0) {
{
int wrbytes;
ulong blksread;
- Hdr *hbp;
+ Blk *hbp;
if (blksleft == 0 || bytes < 0)
bytes = 0;
}
static void
-wrmeta(int fd, Hdr *hp, long mtime, int mode) /* update metadata */
+wrmeta(int fd, Hdr *hdr) /* update metadata */
{
Dir nd;
nulldir(&nd);
- nd.mtime = mtime;
- nd.mode = mode;
+ nd.mtime = hdr->mtime;
+ nd.mode = hdr->mode;
dirfwstat(fd, &nd);
- if (isustar(hp)) {
+ if (hdr->gid) {
nulldir(&nd);
- nd.gid = hp->gname;
+ nd.gid = hdr->gid;
dirfwstat(fd, &nd);
+ }
+ if (hdr->uid){
nulldir(&nd);
- nd.uid = hp->uname;
+ nd.uid = hdr->uid;
dirfwstat(fd, &nd);
}
}
/*
* copy a file from the archive into the filesystem.
- * fname is result of name(), so has two extra bytes at beginning.
+ * fname is result of getname(), so has two extra bytes at beginning.
*/
static void
-extract1(int ar, Hdr *hp, char *fname)
+extract1(int ar, Blk *bp, Hdr *hdr)
{
- int fd = -1, dir = 0;
- long mtime = strtol(hp->mtime, nil, 8);
- ulong mode = strtoul(hp->mode, nil, 8) & 0777;
- Off bytes = hdrsize(hp); /* for printing */
- ulong blksleft = BYTES2TBLKS(arsize(hp));
+ int fd = -1;
+ Off bytes = hdr->size; /* for printing */
+ uvlong blksleft = BYTES2TBLKS(bytes);
+ char *path;
/* fiddle name, figure out mode and blocks */
- if (isdir(hp)) {
- mode |= DMDIR|0700;
- dir = 1;
- }
- switch (hp->linkflag) {
+ switch (bp->linkflag) {
case LF_LINK:
case LF_SYMLINK1:
case LF_SYMLINK2:
blksleft = 0;
break;
}
- if (relative)
- if(fname[0] == '/')
- *--fname = '.';
- else if(fname[0] == '#'){
- *--fname = '/';
- *--fname = '.';
- }
+ if((path = malloc(strlen(hdr->name) + 3)) == nil)
+ sysfatal("malloc: %r");
+ if (relative && hdr->name[0] == '/')
+ strcpy(path, ".");
+ else if(relative && hdr->name[0] == '#')
+ strcpy(path, "./");
+ else
+ path[0] = '\0';
+ strcat(path, hdr->name);
if (verb == Xtract)
- fd = openfname(hp, fname, dir, mode);
+ fd = openfname(bp, path, hdr->mode);
else if (verbose) {
- char *cp = ctime(mtime);
+ char *cp = ctime(hdr->mtime);
- print("%M %8lld %-12.12s %-4.4s %s\n",
- mode, bytes, cp+4, cp+24, fname);
+ print("%M %8lld %-12.12s %-4.4s %s\n",
+ hdr->mode, bytes, cp+4, cp+24, path);
} else
- print("%s\n", fname);
+ print("%s\n", path);
- copyfromar(ar, fd, fname, blksleft, bytes);
+ copyfromar(ar, fd, path, blksleft, hdr->size);
/* touch up meta data and close */
if (fd >= 0) {
* creating files in them, but we don't do that.
*/
if (settime)
- wrmeta(fd, hp, mtime, mode);
+ wrmeta(fd, hdr);
close(fd);
}
+ free(path);
}
static void
-skip(int ar, Hdr *hp, char *fname)
+skip(int ar, Blk *bp, Hdr *hdr)
{
ulong blksleft, blksread;
- Hdr *hbp;
+ Blk *hbp;
- for (blksleft = BYTES2TBLKS(arsize(hp)); blksleft > 0;
+ for (blksleft = BYTES2TBLKS(arsize(bp, hdr->name)); blksleft > 0;
blksleft -= blksread) {
hbp = getblkrd(ar, Justnxthdr);
if (hbp == nil)
sysfatal("unexpected EOF on archive extracting %s from %s",
- fname, arname);
+ hdr->name, arname);
blksread = gothowmany(blksleft);
putreadblks(ar, blksread);
}
}
-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)
{
int ar;
- char *longname;
- Hdr *hp;
- Compress *comp = nil;
+ Blk *bp;
+ Hdr hdr;
+ Compress *comp;
Pushstate ps;
- if (usefile) {
+ if (usefile)
ar = open(usefile, OREAD);
- comp = compmethod(usefile);
- } else
+ else
ar = Stdin;
+ comp = compmethod(usefile);
if (comp)
ar = push(ar, comp->decomp, Input, &ps);
if (ar < 0)
sysfatal("can't open archive %s: %r", usefile);
- while ((hp = readhdr(ar)) != nil) {
- longname = getname(ar, hp);
- if(longname == nil)
- continue;
- if (match(longname, argv))
- extract1(ar, hp, longname);
+ while ((bp = readhdr(ar, &hdr)) != nil) {
+ if (match(hdr.name, argv))
+ extract1(ar, bp, &hdr);
else
- skip(ar, hp, longname);
+ skip(ar, bp, &hdr);
+ freehdr(&hdr);
}
if (comp)
usage();
initblks();
+ nullhdr(&globlhdr);
switch (verb) {
case Toc:
case Xtract: