From: Russ Cox Date: Thu, 31 Mar 2011 02:19:02 +0000 (-0400) Subject: gopack: add P flag to remove prefix from filename information X-Git-Tag: weekly.2011-04-04~38 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=3d2e57a312f8c7bcbfd98de6ff9aae7453497efc;p=gostls13.git gopack: add P flag to remove prefix from filename information R=r, r2 CC=golang-dev https://golang.org/cl/4307047 --- diff --git a/src/cmd/gopack/ar.c b/src/cmd/gopack/ar.c index 4c241358d4..8f0cfbf804 100644 --- a/src/cmd/gopack/ar.c +++ b/src/cmd/gopack/ar.c @@ -41,6 +41,7 @@ #include #include #include +#include "../../libmach/obj.h" #include #undef select @@ -123,6 +124,7 @@ int gflag; int oflag; int uflag; int vflag; +int Pflag; /* remove leading file prefix */ int Sflag; /* force mark Go package as safe */ int errors; @@ -141,6 +143,7 @@ char poname[ARNAMESIZE+1]; /* name of pivot member */ char *file; /* current file or member being worked on */ Biobuf bout; Biobuf bar; +char *prefix; void arcopy(Biobuf*, Arfile*, Armember*); int arcreate(char*); @@ -149,7 +152,7 @@ void arinsert(Arfile*, Armember*); void *armalloc(int); char *arstrdup(char*); void armove(Biobuf*, Arfile*, Armember*); -void arread(Biobuf*, Armember*, int); +void arread(Biobuf*, Armember*); void arstream(int, Arfile*); int arwrite(int, Armember*); int bamatch(char*, char*); @@ -179,6 +182,7 @@ void trim(char*, char*, int); void usage(void); void wrerr(void); void wrsym(Biobuf*, long, Arsymref*); +int arread_cutprefix(Biobuf*, Armember*); void rcmd(char*, int, char**); /* command processing */ void dcmd(char*, int, char**); @@ -220,6 +224,7 @@ main(int argc, char *argv[]) case 'v': vflag = 1; break; case 'x': setcom(xcmd); break; case 'S': Sflag = 1; break; + case 'P': Pflag = 1; break; default: fprint(2, "gopack: bad option `%c'\n", *cp); exits("error"); @@ -236,6 +241,15 @@ main(int argc, char *argv[]) if(argc < 3) usage(); } + if(Pflag) { + if(argc < 4) { + fprint(2, "gopack: P flag requires prefix argument\n"); + usage(); + } + prefix = argv[2]; + argv++; + argc--; + } if(comfun == 0) { if(uflag == 0) { fprint(2, "gopack: one of [%s] must be specified\n", man); @@ -313,7 +327,16 @@ rcmd(char *arname, int count, char **files) skip(&bar, bp->size); continue; } - if (count && !match(count, files)) { + /* + * the plan 9 ar treats count == 0 as equivalent + * to listing all the archive's files on the command line: + * it will try to open every file name in the archive + * and copy that file into the archive if it exists. + * for go we disable that behavior, because we use + * r with no files to make changes to the archive itself, + * using the S or P flags. + */ + if (!match(count, files)) { scanobj(&bar, ap, bp->size); arcopy(&bar, ap, bp); continue; @@ -972,7 +995,7 @@ phaseerr(int offset) void usage(void) { - fprint(2, "usage: gopack [%s][%s] archive files ...\n", opt, man); + fprint(2, "usage: gopack [%s][%s][P prefix] archive files ...\n", opt, man); exits("error"); } @@ -1012,12 +1035,14 @@ armove(Biobuf *b, Arfile *ap, Armember *bp) { char *cp; Dir *d; + vlong n; d = dirfstat(Bfildes(b)); if (d == nil) { fprint(2, "gopack: cannot stat %s\n", file); return; } + trim(file, bp->hdr.name, sizeof(bp->hdr.name)); for (cp = strchr(bp->hdr.name, 0); /* blank pad on right */ cp < bp->hdr.name+sizeof(bp->hdr.name); cp++) @@ -1029,12 +1054,13 @@ armove(Biobuf *b, Arfile *ap, Armember *bp) sprint(bp->hdr.size, "%-10lld", d->length); strncpy(bp->hdr.fmag, ARFMAG, 2); bp->size = d->length; - arread(b, bp, bp->size); - if (d->length&0x01) - d->length++; + arread(b, bp); + n = bp->size; + if (n&1) + n++; if (ap) { arinsert(ap, bp); - ap->size += d->length+SAR_HDR; + ap->size += n+SAR_HDR; } free(d); } @@ -1047,10 +1073,10 @@ arcopy(Biobuf *b, Arfile *ap, Armember *bp) { long n; + arread(b, bp); n = bp->size; if (n & 01) n++; - arread(b, bp, n); if (ap) { arinsert(ap, bp); ap->size += n+SAR_HDR; @@ -1316,7 +1342,8 @@ longt(Armember *bp) Bprint(&bout, "%7ld", bp->size); date = bp->date; cp = ctime(&date); - Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24); + /* using unix ctime, not plan 9 time, so cp+20 for year, not cp+24 */ + Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+20); } int m1[] = { 1, ROWN, 'r', '-' }; @@ -1378,17 +1405,29 @@ newmember(void) /* allocate a member buffer */ } void -arread(Biobuf *b, Armember *bp, int n) /* read an image into a member buffer */ +arread(Biobuf *b, Armember *bp) /* read an image into a member buffer */ { int i; + vlong off; - bp->member = armalloc(n); - i = Bread(b, bp->member, n); + bp->member = armalloc(bp->size); + + // If P flag is set, let arread_cutprefix try. + // If it succeeds, we're done. If not, fall back + // to a direct copy. + off = Boffset(b); + if(Pflag && arread_cutprefix(b, bp)) + return; + Bseek(b, off, 0); + + i = Bread(b, bp->member, bp->size); if (i < 0) { free(bp->member); bp->member = 0; rderr(); } + if(bp->size&1) + Bgetc(b); } /* @@ -1551,3 +1590,109 @@ arstrdup(char *s) } +/* + * Parts of libmach we're not supposed + * to look at but need for arread_cutprefix. + */ +extern int _read5(Biobuf*, Prog*); +extern int _read6(Biobuf*, Prog*); +extern int _read8(Biobuf*, Prog*); +int (*reader[256])(Biobuf*, Prog*) = { + [ObjArm] = _read5, + [ObjAmd64] = _read6, + [Obj386] = _read8, +}; + +/* + * copy b into bp->member but rewrite object + * during copy to drop prefix from all file names. + * return 1 if b was recognized as an object file + * and copied successfully, 0 otherwise. + */ +int +arread_cutprefix(Biobuf *b, Armember *bp) +{ + vlong offset, o, end; + int n, t; + int (*rd)(Biobuf*, Prog*); + char *w, *inprefix; + Prog p; + + offset = Boffset(b); + end = offset + bp->size; + t = objtype(b, nil); + if(t < 0) + return 0; + if((rd = reader[t]) == nil) + return 0; + + // copy header + w = bp->member; + n = Boffset(b) - offset; + Bseek(b, -n, 1); + if(Bread(b, w, n) != n) + return 0; + offset += n; + w += n; + + // read object file one pseudo-instruction at a time, + // eliding the file name instructions that refer to + // the prefix. + memset(&p, 0, sizeof p); + inprefix = nil; + while(Boffset(b) < end && rd(b, &p)) { + if(p.kind == aName && p.type == UNKNOWN && p.sym == 1 && p.id[0] == '<') { + // part of a file path. + // we'll keep continuing (skipping the copy) + // around the loop until either we get to a + // name piece that should be kept or we see + // the whole prefix. + + if(inprefix == nil && prefix[0] == '/' && p.id[1] == '/' && p.id[2] == '\0') { + // leading / + inprefix = prefix+1; + } else if(inprefix != nil) { + // handle subsequent elements + n = strlen(p.id+1); + if(strncmp(p.id+1, inprefix, n) == 0 && (inprefix[n] == '/' || inprefix[n] == '\0')) { + inprefix += n; + if(inprefix[0] == '/') + inprefix++; + } + } + + if(inprefix && inprefix[0] == '\0') { + // reached end of prefix. + // if we another path element follows, + // nudge the offset to skip over the prefix we saw. + // if not, leave offset alone, to emit the whole name. + // additional name elements will not be skipped + // because inprefix is now nil and we won't see another + // leading / in this name. + inprefix = nil; + o = Boffset(b); + if(o < end && rd(b, &p) && p.kind == aName && p.type == UNKNOWN && p.sym == 1 && p.id[0] == '<') { + print("skip %lld-%lld\n", offset, o); + offset = o; + } + } + } + + // copy instructions + if(!inprefix) { + n = Boffset(b) - offset; + Bseek(b, -n, 1); + if(Bread(b, w, n) != n) + return 0; + offset += n; + w += n; + } + } + bp->size = w - (char*)bp->member; + sprint(bp->hdr.size, "%-10lld", (vlong)bp->size); + strncpy(bp->hdr.fmag, ARFMAG, 2); + Bseek(b, end, 0); + if(Boffset(b)&1) + Bgetc(b); + return 1; +} diff --git a/src/cmd/gopack/doc.go b/src/cmd/gopack/doc.go index 08711e72e1..1551a275fd 100644 --- a/src/cmd/gopack/doc.go +++ b/src/cmd/gopack/doc.go @@ -12,12 +12,15 @@ It adds a special Go-specific section __.PKGDEF that collects all the Go type information from the files in the archive; that section is used by the compiler when importing the package during compilation. -Usage: gopack [uvnbailogS][mrxtdpq] archive files ... +Usage: gopack [uvnbailogS][mrxtdpq][P prefix] archive files ... The new option 'g' causes gopack to maintain the __.PKGDEF section as files are added to the archive. The new option 'S' forces gopack to mark the archive as safe. +The new option 'P' causes gopack to remove the given prefix +from file names in the line number information in object files +that are already stored in or added to the archive. */ package documentation