📄 ar.c
字号:
/* * ar - portable (ascii) format version */#include <u.h>#include <libc.h>#include <bio.h>#include <mach.h>#include <ar.h>/* * The algorithm uses up to 3 temp files. The "pivot member" is the * archive member specified by and a, b, or i option. The temp files are * astart - contains existing members up to and including the pivot member. * amiddle - contains new files moved or inserted behind the pivot. * aend - contains the existing members that follow the pivot member. * When all members have been processed, function 'install' streams the * temp files, in order, back into the archive. */typedef struct Arsymref{ char *name; int type; int len; vlong offset; struct Arsymref *next;} Arsymref;typedef struct Armember /* Temp file entry - one per archive member */{ struct Armember *next; struct ar_hdr hdr; long size; long date; void *member;} Armember;typedef struct Arfile /* Temp file control block - one per tempfile */{ int paged; /* set when some data paged to disk */ char *fname; /* paging file name */ int fd; /* paging file descriptor */ vlong size; Armember *head; /* head of member chain */ Armember *tail; /* tail of member chain */ Arsymref *sym; /* head of defined symbol chain */} Arfile;typedef struct Hashchain{ char *name; struct Hashchain *next;} Hashchain;#define NHASH 1024/* * macro to portably read/write archive header. * 'cmd' is read/write/Bread/Bwrite, etc. */#define HEADER_IO(cmd, f, h) cmd(f, h.name, sizeof(h.name)) != sizeof(h.name)\ || cmd(f, h.date, sizeof(h.date)) != sizeof(h.date)\ || cmd(f, h.uid, sizeof(h.uid)) != sizeof(h.uid)\ || cmd(f, h.gid, sizeof(h.gid)) != sizeof(h.gid)\ || cmd(f, h.mode, sizeof(h.mode)) != sizeof(h.mode)\ || cmd(f, h.size, sizeof(h.size)) != sizeof(h.size)\ || cmd(f, h.fmag, sizeof(h.fmag)) != sizeof(h.fmag) /* constants and flags */char *man = "mrxtdpq";char *opt = "uvnbailo";char artemp[] = "/tmp/vXXXXX";char movtemp[] = "/tmp/v1XXXXX";char tailtemp[] = "/tmp/v2XXXXX";char symdef[] = "__.SYMDEF";int aflag; /* command line flags */int bflag;int cflag;int oflag;int uflag;int vflag;Arfile *astart, *amiddle, *aend; /* Temp file control block pointers */int allobj = 1; /* set when all members are object files of the same type */int symdefsize; /* size of symdef file */int dupfound; /* flag for duplicate symbol */Hashchain *hash[NHASH]; /* hash table of text symbols */ #define ARNAMESIZE sizeof(astart->tail->hdr.name)char poname[ARNAMESIZE+1]; /* name of pivot member */char *file; /* current file or member being worked on */Biobuf bout;Biobuf bar;void arcopy(Biobuf*, Arfile*, Armember*);int arcreate(char*);void arfree(Arfile*);void arinsert(Arfile*, Armember*);char *armalloc(int);void armove(Biobuf*, Arfile*, Armember*);void arread(Biobuf*, Armember*, int);void arstream(int, Arfile*);int arwrite(int, Armember*);int bamatch(char*, char*);int duplicate(char*);Armember *getdir(Biobuf*);int getspace(void);void install(char*, Arfile*, Arfile*, Arfile*, int);void longt(Armember*);int match(int, char**);void mesg(int, char*);Arfile *newtempfile(char*);Armember *newmember(void);void objsym(Sym*, void*);int openar(char*, int, int);int page(Arfile*);void pmode(long);void rl(int);void scanobj(Biobuf*, Arfile*, long);void select(int*, long);void setcom(void(*)(char*, int, char**));void skip(Biobuf*, vlong);int symcomp(void*, void*);void trim(char*, char*, int);void usage(void);void wrerr(void);void wrsym(Biobuf*, long, Arsymref*);void rcmd(char*, int, char**); /* command processing */void dcmd(char*, int, char**);void xcmd(char*, int, char**);void tcmd(char*, int, char**);void pcmd(char*, int, char**);void mcmd(char*, int, char**);void qcmd(char*, int, char**);void (*comfun)(char*, int, char**);voidmain(int argc, char *argv[]){ char *cp; Binit(&bout, 1, OWRITE); if(argc < 3) usage(); for (cp = argv[1]; *cp; cp++) { switch(*cp) { case 'a': aflag = 1; break; case 'b': bflag = 1; break; case 'c': cflag = 1; break; case 'd': setcom(dcmd); break; case 'i': bflag = 1; break; case 'l': strcpy(artemp, "vXXXXX"); strcpy(movtemp, "v1XXXXX"); strcpy(tailtemp, "v2XXXXX"); break; case 'm': setcom(mcmd); break; case 'o': oflag = 1; break; case 'p': setcom(pcmd); break; case 'q': setcom(qcmd); break; case 'r': setcom(rcmd); break; case 't': setcom(tcmd); break; case 'u': uflag = 1; break; case 'v': vflag = 1; break; case 'x': setcom(xcmd); break; default: fprint(2, "ar: bad option `%c'\n", *cp); exits("error"); } } if (aflag && bflag) { fprint(2, "ar: only one of 'a' and 'b' can be specified\n"); usage(); } if(aflag || bflag) { trim(argv[2], poname, sizeof(poname)); argv++; argc--; if(argc < 3) usage(); } if(comfun == 0) { if(uflag == 0) { fprint(2, "ar: one of [%s] must be specified\n", man); usage(); } setcom(rcmd); } cp = argv[2]; argc -= 3; argv += 3; (*comfun)(cp, argc, argv); /* do the command */ cp = 0; while (argc--) { if (*argv) { fprint(2, "ar: %s not found\n", *argv); cp = "error"; } argv++; } exits(cp);}/* * select a command */voidsetcom(void (*fun)(char *, int, char**)){ if(comfun != 0) { fprint(2, "ar: only one of [%s] allowed\n", man); usage(); } comfun = fun;}/* * perform the 'r' and 'u' commands */voidrcmd(char *arname, int count, char **files){ int fd; int i; Arfile *ap; Armember *bp; Dir *d; Biobuf *bfile; fd = openar(arname, ORDWR, 1); if (fd >= 0) { Binit(&bar, fd, OREAD); Bseek(&bar,seek(fd,0,1), 1); } astart = newtempfile(artemp); ap = astart; aend = 0; for(i = 0; fd >= 0; i++) { bp = getdir(&bar); if (!bp) break; if (bamatch(file, poname)) { /* check for pivot */ aend = newtempfile(tailtemp); ap = aend; } /* pitch symdef file */ if (i == 0 && strcmp(file, symdef) == 0) { skip(&bar, bp->size); continue; } if (count && !match(count, files)) { scanobj(&bar, ap, bp->size); arcopy(&bar, ap, bp); continue; } bfile = Bopen(file, OREAD); if (!bfile) { if (count != 0) fprint(2, "ar: cannot open %s\n", file); scanobj(&bar, ap, bp->size); arcopy(&bar, ap, bp); continue; } d = dirfstat(Bfildes(bfile)); if(d == nil) fprint(2, "ar: cannot stat %s: %r\n", file); if (uflag && (d==nil || d->mtime <= bp->date)) { scanobj(&bar, ap, bp->size); arcopy(&bar, ap, bp); Bterm(bfile); free(d); continue; } mesg('r', file); skip(&bar, bp->size); scanobj(bfile, ap, d->length); free(d); armove(bfile, ap, bp); Bterm(bfile); } if(fd >= 0) close(fd); /* copy in remaining files named on command line */ for (i = 0; i < count; i++) { file = files[i]; if(file == 0) continue; files[i] = 0; bfile = Bopen(file, OREAD); if (!bfile) fprint(2, "ar: %s cannot open\n", file); else { mesg('a', file); d = dirfstat(Bfildes(bfile)); if (d == nil) fprint(2, "can't stat %s\n", file); else { scanobj(bfile, astart, d->length); armove(bfile, astart, newmember()); free(d); } Bterm(bfile); } } if(fd < 0 && !cflag) install(arname, astart, 0, aend, 1); /* issue 'creating' msg */ else install(arname, astart, 0, aend, 0);}voiddcmd(char *arname, int count, char **files){ Armember *bp; int fd, i; if (!count) return; fd = openar(arname, ORDWR, 0); Binit(&bar, fd, OREAD); Bseek(&bar,seek(fd,0,1), 1); astart = newtempfile(artemp); for (i = 0; bp = getdir(&bar); i++) { if(match(count, files)) { mesg('d', file); skip(&bar, bp->size); if (strcmp(file, symdef) == 0) allobj = 0; } else if (i == 0 && strcmp(file, symdef) == 0) skip(&bar, bp->size); else { scanobj(&bar, astart, bp->size); arcopy(&bar, astart, bp); } } close(fd); install(arname, astart, 0, 0, 0);}voidxcmd(char *arname, int count, char **files){ int fd, f, mode, i; Armember *bp; Dir dx; fd = openar(arname, OREAD, 0); Binit(&bar, fd, OREAD); Bseek(&bar,seek(fd,0,1), 1); i = 0; while (bp = getdir(&bar)) { if(count == 0 || match(count, files)) { mode = strtoul(bp->hdr.mode, 0, 8) & 0777; f = create(file, OWRITE, mode); if(f < 0) { fprint(2, "ar: %s cannot create\n", file); skip(&bar, bp->size); } else { mesg('x', file); arcopy(&bar, 0, bp); if (write(f, bp->member, bp->size) < 0) wrerr(); if(oflag) { nulldir(&dx); dx.atime = bp->date; dx.mtime = bp->date; if(dirwstat(file, &dx) < 0) perror(file); } free(bp->member); close(f); } free(bp); if (count && ++i >= count) break; } else { skip(&bar, bp->size); free(bp); } } close(fd);}voidpcmd(char *arname, int count, char **files){ int fd; Armember *bp; fd = openar(arname, OREAD, 0); Binit(&bar, fd, OREAD); Bseek(&bar,seek(fd,0,1), 1); while(bp = getdir(&bar)) { if(count == 0 || match(count, files)) { if(vflag) print("\n<%s>\n\n", file); arcopy(&bar, 0, bp); if (write(1, bp->member, bp->size) < 0) wrerr(); } else skip(&bar, bp->size); free(bp); } close(fd);}voidmcmd(char *arname, int count, char **files){ int fd, i; Arfile *ap; Armember *bp; if (count == 0) return; fd = openar(arname, ORDWR, 0); Binit(&bar, fd, OREAD); Bseek(&bar,seek(fd,0,1), 1); astart = newtempfile(artemp); amiddle = newtempfile(movtemp); aend = 0; ap = astart; for (i = 0; bp = getdir(&bar); i++) { if (bamatch(file, poname)) { aend = newtempfile(tailtemp); ap = aend; } if(match(count, files)) { mesg('m', file); scanobj(&bar, amiddle, bp->size); arcopy(&bar, amiddle, bp); } else /* * pitch the symdef file if it is at the beginning * of the archive and we aren't inserting in front * of it (ap == astart). */ if (ap == astart && i == 0 && strcmp(file, symdef) == 0) skip(&bar, bp->size); else { scanobj(&bar, ap, bp->size); arcopy(&bar, ap, bp); } } close(fd); if (poname[0] && aend == 0) fprint(2, "ar: %s not found - files moved to end.\n", poname); install(arname, astart, amiddle, aend, 0);}voidtcmd(char *arname, int count, char **files){ int fd; Armember *bp; char name[ARNAMESIZE+1]; fd = openar(arname, OREAD, 0); Binit(&bar, fd, OREAD); Bseek(&bar,seek(fd,0,1), 1); while(bp = getdir(&bar)) { if(count == 0 || match(count, files)) { if(vflag) longt(bp); trim(file, name, ARNAMESIZE); Bprint(&bout, "%s\n", name); } skip(&bar, bp->size); free(bp); } close(fd);}voidqcmd(char *arname, int count, char **files){ int fd, i; Armember *bp; Biobuf *bfile; if(aflag || bflag) { fprint(2, "ar: abi not allowed with q\n"); exits("error"); } fd = openar(arname, ORDWR, 1); if (fd < 0) { if(!cflag) fprint(2, "ar: creating %s\n", arname); fd = arcreate(arname); } Binit(&bar, fd, OREAD); Bseek(&bar,seek(fd,0,1), 1); /* leave note group behind when writing archive; i.e. sidestep interrupts */ rfork(RFNOTEG); Bseek(&bar, 0, 2); bp = newmember(); for(i=0; i<count && files[i]; i++) { file = files[i]; files[i] = 0; bfile = Bopen(file, OREAD); if(!bfile) fprint(2, "ar: %s cannot open\n", file); else { mesg('q', file); armove(bfile, 0, bp); if (!arwrite(fd, bp)) wrerr(); free(bp->member); bp->member = 0; Bterm(bfile); } } free(bp); close(fd);}/* * extract the symbol references from an object file */voidscanobj(Biobuf *b, Arfile *ap, long size){ int obj; vlong offset; Dir *d; static int lastobj = -1; if (!allobj) /* non-object file encountered */ return; offset = Boffset(b); obj = objtype(b, 0); if (obj < 0) { /* not an object file */ allobj = 0; d = dirfstat(Bfildes(b)); if (d != nil && d->length == 0) fprint(2, "ar: zero length file %s\n", file); free(d); Bseek(b, offset, 0); return; } if (lastobj >= 0 && obj != lastobj) { fprint(2, "ar: inconsistent object file %s\n", file); allobj = 0; Bseek(b, offset, 0); return; } lastobj = obj; if (!readar(b, obj, offset+size, 0)) { fprint(2, "ar: invalid symbol reference in file %s\n", file); allobj = 0; Bseek(b, offset, 0); return; } Bseek(b, offset, 0); objtraverse(objsym, ap);}/* * add text and data symbols to the symbol list */voidobjsym(Sym *s, void *p){ int n; Arsymref *as; Arfile *ap; if (s->type != 'T' && s->type != 'D') return; ap = (Arfile*)p; as = (Arsymref*)armalloc(sizeof(Arsymref)); as->offset = ap->size; n = strlen(s->name); as->name = armalloc(n+1); strcpy(as->name, s->name); if(s->type == 'T' && duplicate(as->name)) { dupfound = 1; fprint(2, "duplicate text symbol: %s\n", as->name); free(as->name); free(as); return; } as->type = s->type; symdefsize += 4+(n+1)+1; as->len = n; as->next = ap->sym; ap->sym = as;}/* * Check the symbol table for duplicate text symbols */intduplicate(char *name){ Hashchain *p; char *cp; int h; h = 0; for(cp = name; *cp; h += *cp++) h *= 1119; if(h < 0) h = ~h; h %= NHASH; for(p = hash[h]; p; p = p->next)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -