13e12c5d1SDavid du Colombier /* 23e12c5d1SDavid du Colombier * ar - portable (ascii) format version 33e12c5d1SDavid du Colombier */ 43e12c5d1SDavid du Colombier #include <u.h> 53e12c5d1SDavid du Colombier #include <libc.h> 63e12c5d1SDavid du Colombier #include <bio.h> 7*219b2ee8SDavid du Colombier #include <mach.h> 83e12c5d1SDavid du Colombier #include <ar.h> 93e12c5d1SDavid du Colombier 10bd389b36SDavid du Colombier /* 11bd389b36SDavid du Colombier * The algorithm uses up to 3 temp files. The "pivot member" is the 12*219b2ee8SDavid du Colombier * archive member specified by and a, b, or i option. The temp files are 13*219b2ee8SDavid du Colombier * astart - contains existing members up to and including the pivot member. 14*219b2ee8SDavid du Colombier * amiddle - contains new files moved or inserted behind the pivot. 15*219b2ee8SDavid du Colombier * aend - contains the existing members that follow the pivot member. 16*219b2ee8SDavid du Colombier * When all members have been processed, function 'install' streams the 17*219b2ee8SDavid du Colombier * temp files, in order, back into the archive. 18bd389b36SDavid du Colombier */ 19bd389b36SDavid du Colombier 20*219b2ee8SDavid du Colombier typedef struct Arsymref 21*219b2ee8SDavid du Colombier { 22*219b2ee8SDavid du Colombier char *name; 23*219b2ee8SDavid du Colombier int type; 24*219b2ee8SDavid du Colombier int len; 25*219b2ee8SDavid du Colombier long offset; 26*219b2ee8SDavid du Colombier struct Arsymref *next; 27*219b2ee8SDavid du Colombier } Arsymref; 28*219b2ee8SDavid du Colombier 29bd389b36SDavid du Colombier typedef struct Armember /* Temp file entry - one per archive member */ 303e12c5d1SDavid du Colombier { 31bd389b36SDavid du Colombier struct Armember *next; 32bd389b36SDavid du Colombier struct ar_hdr hdr; 33bd389b36SDavid du Colombier long size; 34bd389b36SDavid du Colombier long date; 35bd389b36SDavid du Colombier void *member; 36bd389b36SDavid du Colombier } Armember; 373e12c5d1SDavid du Colombier 38bd389b36SDavid du Colombier typedef struct Arfile /* Temp file control block - one per tempfile */ 39bd389b36SDavid du Colombier { 40bd389b36SDavid du Colombier int paged; /* set when some data paged to disk */ 41bd389b36SDavid du Colombier char *fname; /* paging file name */ 42bd389b36SDavid du Colombier int fd; /* paging file descriptor */ 43*219b2ee8SDavid du Colombier long size; 44bd389b36SDavid du Colombier Armember *head; /* head of member chain */ 45bd389b36SDavid du Colombier Armember *tail; /* tail of member chain */ 46*219b2ee8SDavid du Colombier Arsymref *sym; /* head of defined symbol chain */ 47bd389b36SDavid du Colombier } Arfile; 48*219b2ee8SDavid du Colombier 49*219b2ee8SDavid du Colombier /* 50*219b2ee8SDavid du Colombier * macro to portably read/write archive header. 51*219b2ee8SDavid du Colombier * 'cmd' is read/write/Bread/Bwrite, etc. 52*219b2ee8SDavid du Colombier */ 53*219b2ee8SDavid du Colombier #define HEADER_IO(cmd, f, h) cmd(f, h.name, sizeof(h.name)) != sizeof(h.name)\ 54*219b2ee8SDavid du Colombier || cmd(f, h.date, sizeof(h.date)) != sizeof(h.date)\ 55*219b2ee8SDavid du Colombier || cmd(f, h.uid, sizeof(h.uid)) != sizeof(h.uid)\ 56*219b2ee8SDavid du Colombier || cmd(f, h.gid, sizeof(h.gid)) != sizeof(h.gid)\ 57*219b2ee8SDavid du Colombier || cmd(f, h.mode, sizeof(h.mode)) != sizeof(h.mode)\ 58*219b2ee8SDavid du Colombier || cmd(f, h.size, sizeof(h.size)) != sizeof(h.size)\ 59*219b2ee8SDavid du Colombier || cmd(f, h.fmag, sizeof(h.fmag)) != sizeof(h.fmag) 60*219b2ee8SDavid du Colombier 61bd389b36SDavid du Colombier /* constants and flags */ 62bd389b36SDavid du Colombier char *man = "mrxtdpq"; 63bd389b36SDavid du Colombier char *opt = "uvnbailo"; 64bd389b36SDavid du Colombier char artemp[] = "/tmp/vXXXXX"; 65bd389b36SDavid du Colombier char movtemp[] = "/tmp/v1XXXXX"; 66bd389b36SDavid du Colombier char tailtemp[] = "/tmp/v2XXXXX"; 67*219b2ee8SDavid du Colombier char symdef[] = "__.SYMDEF"; 683e12c5d1SDavid du Colombier 69bd389b36SDavid du Colombier int aflag; /* command line flags */ 70bd389b36SDavid du Colombier int bflag; 71bd389b36SDavid du Colombier int cflag; 72bd389b36SDavid du Colombier int oflag; 73bd389b36SDavid du Colombier int uflag; 74bd389b36SDavid du Colombier int vflag; 753e12c5d1SDavid du Colombier 76bd389b36SDavid du Colombier Arfile *astart, *amiddle, *aend; /* Temp file control block pointers */ 77*219b2ee8SDavid du Colombier int allobj = 1; /* set when all members are object files of the same type */ 78*219b2ee8SDavid du Colombier int symdefsize; /* size of symdef file */ 79bd389b36SDavid du Colombier 80bd389b36SDavid du Colombier #define ARNAMESIZE sizeof(astart->tail->hdr.name) 81bd389b36SDavid du Colombier 82bd389b36SDavid du Colombier char poname[ARNAMESIZE+1]; /* name of pivot member */ 83bd389b36SDavid du Colombier char *file; /* current file or member being worked on */ 843e12c5d1SDavid du Colombier Biobuf bout; 85*219b2ee8SDavid du Colombier Biobuf bar; 863e12c5d1SDavid du Colombier 87*219b2ee8SDavid du Colombier void arcopy(Biobuf*, Arfile*, Armember*); 88bd389b36SDavid du Colombier int arcreate(char*); 89bd389b36SDavid du Colombier void arfree(Arfile*); 90bd389b36SDavid du Colombier void arinsert(Arfile*, Armember*); 91bd389b36SDavid du Colombier char *armalloc(int); 92*219b2ee8SDavid du Colombier void armove(Biobuf*, Arfile*, Armember*); 93*219b2ee8SDavid du Colombier void arread(Biobuf*, Armember*, int); 94bd389b36SDavid du Colombier void arstream(int, Arfile*); 95bd389b36SDavid du Colombier int arwrite(int, Armember*); 96bd389b36SDavid du Colombier int bamatch(char*, char*); 97*219b2ee8SDavid du Colombier Armember *getdir(Biobuf*); 98bd389b36SDavid du Colombier int getspace(void); 99bd389b36SDavid du Colombier void install(char*, Arfile*, Arfile*, Arfile*); 100bd389b36SDavid du Colombier void longt(Armember*); 101bd389b36SDavid du Colombier int match(int, char**); 102bd389b36SDavid du Colombier void mesg(int, char*); 103bd389b36SDavid du Colombier Arfile *newtempfile(char*); 104bd389b36SDavid du Colombier Armember *newmember(void); 105*219b2ee8SDavid du Colombier void objsym(Sym*, void*); 106bd389b36SDavid du Colombier int openar(char*, int, int); 107bd389b36SDavid du Colombier int page(Arfile*); 108bd389b36SDavid du Colombier void pmode(long); 109*219b2ee8SDavid du Colombier void rl(int); 110*219b2ee8SDavid du Colombier void scanobj(Biobuf*, Arfile*, int); 111bd389b36SDavid du Colombier void select(int*, long); 112bd389b36SDavid du Colombier void setcom(void(*)(char*, int, char**)); 113*219b2ee8SDavid du Colombier void skip(Biobuf*, long); 114bd389b36SDavid du Colombier void trim(char*, char*, int); 1153e12c5d1SDavid du Colombier void usage(void); 1163e12c5d1SDavid du Colombier void wrerr(void); 117*219b2ee8SDavid du Colombier void wrsym(Biobuf*, int, Arsymref*); 1183e12c5d1SDavid du Colombier 119bd389b36SDavid du Colombier void rcmd(char*, int, char**); /* command processing */ 120bd389b36SDavid du Colombier void dcmd(char*, int, char**); 121bd389b36SDavid du Colombier void xcmd(char*, int, char**); 122bd389b36SDavid du Colombier void tcmd(char*, int, char**); 123bd389b36SDavid du Colombier void pcmd(char*, int, char**); 124bd389b36SDavid du Colombier void mcmd(char*, int, char**); 125bd389b36SDavid du Colombier void qcmd(char*, int, char**); 126bd389b36SDavid du Colombier void (*comfun)(char*, int, char**); 127bd389b36SDavid du Colombier 1283e12c5d1SDavid du Colombier void 1293e12c5d1SDavid du Colombier main(int argc, char *argv[]) 1303e12c5d1SDavid du Colombier { 1313e12c5d1SDavid du Colombier char *cp; 1323e12c5d1SDavid du Colombier 133*219b2ee8SDavid du Colombier 1343e12c5d1SDavid du Colombier Binit(&bout, 1, OWRITE); 1353e12c5d1SDavid du Colombier if(argc < 3) 1363e12c5d1SDavid du Colombier usage(); 137bd389b36SDavid du Colombier for (cp = argv[1]; *cp; cp++) { 1383e12c5d1SDavid du Colombier switch(*cp) { 139bd389b36SDavid du Colombier case 'a': aflag = 1; break; 140bd389b36SDavid du Colombier case 'b': bflag = 1; break; 141bd389b36SDavid du Colombier case 'c': cflag = 1; break; 142bd389b36SDavid du Colombier case 'd': setcom(dcmd); break; 143bd389b36SDavid du Colombier case 'i': bflag = 1; break; 1443e12c5d1SDavid du Colombier case 'l': 145bd389b36SDavid du Colombier strcpy(artemp, "vXXXXX"); 146bd389b36SDavid du Colombier strcpy(movtemp, "v1XXXXX"); 147bd389b36SDavid du Colombier strcpy(tailtemp, "v2XXXXX"); 148bd389b36SDavid du Colombier break; 149bd389b36SDavid du Colombier case 'm': setcom(mcmd); break; 150bd389b36SDavid du Colombier case 'o': oflag = 1; break; 151bd389b36SDavid du Colombier case 'p': setcom(pcmd); break; 152bd389b36SDavid du Colombier case 'q': setcom(qcmd); break; 153bd389b36SDavid du Colombier case 'r': setcom(rcmd); break; 154bd389b36SDavid du Colombier case 't': setcom(tcmd); break; 155bd389b36SDavid du Colombier case 'u': uflag = 1; break; 156bd389b36SDavid du Colombier case 'v': vflag = 1; break; 157bd389b36SDavid du Colombier case 'x': setcom(xcmd); break; 1583e12c5d1SDavid du Colombier default: 1593e12c5d1SDavid du Colombier fprint(2, "ar: bad option `%c'\n", *cp); 160bd389b36SDavid du Colombier exits("error"); 1613e12c5d1SDavid du Colombier } 1623e12c5d1SDavid du Colombier } 163bd389b36SDavid du Colombier if (aflag && bflag) { 164bd389b36SDavid du Colombier fprint(2, "ar: only one of 'a' and 'b' can be specified\n"); 165bd389b36SDavid du Colombier usage(); 166bd389b36SDavid du Colombier } 167bd389b36SDavid du Colombier if(aflag || bflag) { 168bd389b36SDavid du Colombier trim(argv[2], poname, sizeof(poname)); 1693e12c5d1SDavid du Colombier argv++; 1703e12c5d1SDavid du Colombier argc--; 1713e12c5d1SDavid du Colombier if(argc < 3) 1723e12c5d1SDavid du Colombier usage(); 1733e12c5d1SDavid du Colombier } 1743e12c5d1SDavid du Colombier if(comfun == 0) { 175bd389b36SDavid du Colombier if(uflag == 0) { 1763e12c5d1SDavid du Colombier fprint(2, "ar: one of [%s] must be specified\n", man); 177bd389b36SDavid du Colombier usage(); 1783e12c5d1SDavid du Colombier } 1793e12c5d1SDavid du Colombier setcom(rcmd); 1803e12c5d1SDavid du Colombier } 181bd389b36SDavid du Colombier cp = argv[2]; 182bd389b36SDavid du Colombier argc -= 3; 183bd389b36SDavid du Colombier argv += 3; 184bd389b36SDavid du Colombier (*comfun)(cp, argc, argv); /* do the command */ 185bd389b36SDavid du Colombier cp = 0; 186bd389b36SDavid du Colombier while (argc--) { 187bd389b36SDavid du Colombier if (*argv) { 188bd389b36SDavid du Colombier fprint(2, "ar: %s not found\n", *argv); 189bd389b36SDavid du Colombier cp = "error"; 1903e12c5d1SDavid du Colombier } 191bd389b36SDavid du Colombier argv++; 192bd389b36SDavid du Colombier } 193bd389b36SDavid du Colombier exits(cp); 194bd389b36SDavid du Colombier } 195bd389b36SDavid du Colombier /* 196bd389b36SDavid du Colombier * select a command 197bd389b36SDavid du Colombier */ 1983e12c5d1SDavid du Colombier void 199bd389b36SDavid du Colombier setcom(void (*fun)(char *, int, char**)) 2003e12c5d1SDavid du Colombier { 2013e12c5d1SDavid du Colombier 2023e12c5d1SDavid du Colombier if(comfun != 0) { 2033e12c5d1SDavid du Colombier fprint(2, "ar: only one of [%s] allowed\n", man); 204bd389b36SDavid du Colombier usage(); 2053e12c5d1SDavid du Colombier } 2063e12c5d1SDavid du Colombier comfun = fun; 2073e12c5d1SDavid du Colombier } 208bd389b36SDavid du Colombier /* 209bd389b36SDavid du Colombier * perform the 'r' and 'u' commands 210bd389b36SDavid du Colombier */ 2113e12c5d1SDavid du Colombier void 212bd389b36SDavid du Colombier rcmd(char *arname, int count, char **files) 2133e12c5d1SDavid du Colombier { 214*219b2ee8SDavid du Colombier int fd; 215*219b2ee8SDavid du Colombier int i, ret; 216bd389b36SDavid du Colombier Arfile *ap; 217bd389b36SDavid du Colombier Armember *bp; 218bd389b36SDavid du Colombier Dir d; 219*219b2ee8SDavid du Colombier Biobuf *bfile; 2203e12c5d1SDavid du Colombier 221bd389b36SDavid du Colombier fd = openar(arname, ORDWR, 1); 222*219b2ee8SDavid du Colombier if (fd >= 0) { 223*219b2ee8SDavid du Colombier Binit(&bar, fd, OREAD); 224*219b2ee8SDavid du Colombier Bseek(&bar,seek(fd,0,1), 1); 225*219b2ee8SDavid du Colombier } 226bd389b36SDavid du Colombier astart = newtempfile(artemp); 227bd389b36SDavid du Colombier ap = astart; 228bd389b36SDavid du Colombier aend = 0; 229*219b2ee8SDavid du Colombier for(i = 0; fd >= 0; i++) { 230*219b2ee8SDavid du Colombier bp = getdir(&bar); 231bd389b36SDavid du Colombier if (!bp) 232bd389b36SDavid du Colombier break; 233bd389b36SDavid du Colombier if (bamatch(file, poname)) { /* check for pivot */ 234bd389b36SDavid du Colombier aend = newtempfile(tailtemp); 235bd389b36SDavid du Colombier ap = aend; 236bd389b36SDavid du Colombier } 237*219b2ee8SDavid du Colombier /* pitch symdef file */ 238*219b2ee8SDavid du Colombier if (i == 0 && strcmp(file, symdef) == 0) { 239*219b2ee8SDavid du Colombier skip(&bar, bp->size); 240*219b2ee8SDavid du Colombier continue; 241*219b2ee8SDavid du Colombier } 242*219b2ee8SDavid du Colombier if (count && !match(count, files)) { 243*219b2ee8SDavid du Colombier scanobj(&bar, ap, bp->size); 244*219b2ee8SDavid du Colombier arcopy(&bar, ap, bp); 245*219b2ee8SDavid du Colombier continue; 246*219b2ee8SDavid du Colombier } 247*219b2ee8SDavid du Colombier bfile = Bopen(file, OREAD); 248*219b2ee8SDavid du Colombier if (!bfile) { 249bd389b36SDavid du Colombier if (count != 0) 2503e12c5d1SDavid du Colombier fprint(2, "ar: cannot open %s\n", file); 251*219b2ee8SDavid du Colombier scanobj(&bar, ap, bp->size); 252*219b2ee8SDavid du Colombier arcopy(&bar, ap, bp); 253*219b2ee8SDavid du Colombier continue; 254*219b2ee8SDavid du Colombier } 255*219b2ee8SDavid du Colombier ret = dirfstat(Bfildes(bfile), &d); 256*219b2ee8SDavid du Colombier if (ret < 0) 257bd389b36SDavid du Colombier fprint(2, "ar: cannot stat %s\n", file); 258*219b2ee8SDavid du Colombier if (uflag && (ret < 0 || d.mtime <= bp->date)) { 259*219b2ee8SDavid du Colombier scanobj(&bar, ap, bp->size); 260*219b2ee8SDavid du Colombier arcopy(&bar, ap, bp); 261*219b2ee8SDavid du Colombier Bterm(bfile); 262*219b2ee8SDavid du Colombier continue; 2633e12c5d1SDavid du Colombier } 264bd389b36SDavid du Colombier mesg('r', file); 265*219b2ee8SDavid du Colombier skip(&bar, bp->size); 266*219b2ee8SDavid du Colombier scanobj(bfile, ap, d.length); 267*219b2ee8SDavid du Colombier armove(bfile, ap, bp); 268*219b2ee8SDavid du Colombier Bterm(bfile); 2693e12c5d1SDavid du Colombier } 270bd389b36SDavid du Colombier if(fd < 0) { 271bd389b36SDavid du Colombier if(!cflag) 272bd389b36SDavid du Colombier fprint(2, "ar: creating %s\n", arname); 273bd389b36SDavid du Colombier } else 274bd389b36SDavid du Colombier close(fd); 275bd389b36SDavid du Colombier /* copy in remaining files named on command line */ 276bd389b36SDavid du Colombier for (i = 0; i < count; i++) { 277bd389b36SDavid du Colombier file = files[i]; 2783e12c5d1SDavid du Colombier if(file == 0) 2793e12c5d1SDavid du Colombier continue; 280bd389b36SDavid du Colombier files[i] = 0; 281*219b2ee8SDavid du Colombier bfile = Bopen(file, OREAD); 282*219b2ee8SDavid du Colombier if (!bfile) 2833e12c5d1SDavid du Colombier fprint(2, "ar: %s cannot open\n", file); 284bd389b36SDavid du Colombier else { 285bd389b36SDavid du Colombier mesg('a', file); 286*219b2ee8SDavid du Colombier i = dirfstat(Bfildes(bfile), &d); 287*219b2ee8SDavid du Colombier if (i < 0) 288*219b2ee8SDavid du Colombier fprint(2, "can't stat %s\n", file); 289*219b2ee8SDavid du Colombier else { 290*219b2ee8SDavid du Colombier scanobj(bfile, astart, d.length); 291*219b2ee8SDavid du Colombier armove(bfile, astart, newmember()); 292*219b2ee8SDavid du Colombier } 293*219b2ee8SDavid du Colombier Bterm(bfile); 2943e12c5d1SDavid du Colombier } 2953e12c5d1SDavid du Colombier } 296bd389b36SDavid du Colombier install(arname, astart, 0, aend); 297bd389b36SDavid du Colombier } 298*219b2ee8SDavid du Colombier 299bd389b36SDavid du Colombier void 300bd389b36SDavid du Colombier dcmd(char *arname, int count, char **files) 301bd389b36SDavid du Colombier { 302bd389b36SDavid du Colombier Armember *bp; 303*219b2ee8SDavid du Colombier int fd, i; 304bd389b36SDavid du Colombier 305bd389b36SDavid du Colombier 306bd389b36SDavid du Colombier if (!count) 307bd389b36SDavid du Colombier return; 308bd389b36SDavid du Colombier fd = openar(arname, ORDWR, 0); 309*219b2ee8SDavid du Colombier Binit(&bar, fd, OREAD); 310*219b2ee8SDavid du Colombier Bseek(&bar,seek(fd,0,1), 1); 311bd389b36SDavid du Colombier astart = newtempfile(artemp); 312*219b2ee8SDavid du Colombier for (i = 0; bp = getdir(&bar); i++) { 313bd389b36SDavid du Colombier if(match(count, files)) { 314bd389b36SDavid du Colombier mesg('d', file); 315*219b2ee8SDavid du Colombier skip(&bar, bp->size); 316*219b2ee8SDavid du Colombier if (strcmp(file, symdef) == 0) 317*219b2ee8SDavid du Colombier allobj = 0; 318*219b2ee8SDavid du Colombier } else if (i == 0 && strcmp(file, symdef) == 0) 319*219b2ee8SDavid du Colombier skip(&bar, bp->size); 320*219b2ee8SDavid du Colombier else { 321*219b2ee8SDavid du Colombier scanobj(&bar, astart, bp->size); 322*219b2ee8SDavid du Colombier arcopy(&bar, astart, bp); 323bd389b36SDavid du Colombier } 324*219b2ee8SDavid du Colombier } 325*219b2ee8SDavid du Colombier close(fd); 326bd389b36SDavid du Colombier install(arname, astart, 0, 0); 3273e12c5d1SDavid du Colombier } 3283e12c5d1SDavid du Colombier 3293e12c5d1SDavid du Colombier void 330bd389b36SDavid du Colombier xcmd(char *arname, int count, char **files) 3313e12c5d1SDavid du Colombier { 332bd389b36SDavid du Colombier int fd, f, mode, i; 333bd389b36SDavid du Colombier Armember *bp; 334*219b2ee8SDavid du Colombier Dir dx; 3353e12c5d1SDavid du Colombier 336bd389b36SDavid du Colombier fd = openar(arname, OREAD, 0); 337*219b2ee8SDavid du Colombier Binit(&bar, fd, OREAD); 338*219b2ee8SDavid du Colombier Bseek(&bar,seek(fd,0,1), 1); 339bd389b36SDavid du Colombier i = 0; 340*219b2ee8SDavid du Colombier while (bp = getdir(&bar)) { 341bd389b36SDavid du Colombier if(count == 0 || match(count, files)) { 342bd389b36SDavid du Colombier mode = strtoul(bp->hdr.mode, 0, 8) & 0777; 343bd389b36SDavid du Colombier f = create(file, OWRITE, mode); 344bd389b36SDavid du Colombier if(f < 0) { 345bd389b36SDavid du Colombier fprint(2, "ar: %s cannot create\n", file); 346*219b2ee8SDavid du Colombier skip(&bar, bp->size); 347bd389b36SDavid du Colombier } else { 348bd389b36SDavid du Colombier mesg('x', file); 349*219b2ee8SDavid du Colombier arcopy(&bar, 0, bp); 350bd389b36SDavid du Colombier if (write(f, bp->member, bp->size) < 0) 3513e12c5d1SDavid du Colombier wrerr(); 352bd389b36SDavid du Colombier if(oflag) { 353*219b2ee8SDavid du Colombier if(dirfstat(f, &dx) < 0) 354bd389b36SDavid du Colombier perror(file); 355bd389b36SDavid du Colombier else { 356*219b2ee8SDavid du Colombier dx.atime = bp->date; 357*219b2ee8SDavid du Colombier dx.mtime = bp->date; 358*219b2ee8SDavid du Colombier if(dirwstat(file, &dx) < 0) 359bd389b36SDavid du Colombier perror(file); 3603e12c5d1SDavid du Colombier } 361bd389b36SDavid du Colombier } 362bd389b36SDavid du Colombier free(bp->member); 363bd389b36SDavid du Colombier close(f); 364bd389b36SDavid du Colombier } 365bd389b36SDavid du Colombier free(bp); 366bd389b36SDavid du Colombier if (count && ++i >= count) 367bd389b36SDavid du Colombier break; 368bd389b36SDavid du Colombier } else { 369*219b2ee8SDavid du Colombier skip(&bar, bp->size); 370bd389b36SDavid du Colombier free(bp); 371bd389b36SDavid du Colombier } 372bd389b36SDavid du Colombier } 373bd389b36SDavid du Colombier close(fd); 374bd389b36SDavid du Colombier } 375bd389b36SDavid du Colombier void 376bd389b36SDavid du Colombier pcmd(char *arname, int count, char **files) 377bd389b36SDavid du Colombier { 378bd389b36SDavid du Colombier int fd; 379bd389b36SDavid du Colombier Armember *bp; 3803e12c5d1SDavid du Colombier 381bd389b36SDavid du Colombier fd = openar(arname, OREAD, 0); 382*219b2ee8SDavid du Colombier Binit(&bar, fd, OREAD); 383*219b2ee8SDavid du Colombier Bseek(&bar,seek(fd,0,1), 1); 384*219b2ee8SDavid du Colombier while(bp = getdir(&bar)) { 385bd389b36SDavid du Colombier if(count == 0 || match(count, files)) { 386bd389b36SDavid du Colombier if(vflag) 387bd389b36SDavid du Colombier print("\n<%s>\n\n", file); 388*219b2ee8SDavid du Colombier arcopy(&bar, 0, bp); 389bd389b36SDavid du Colombier if (write(1, bp->member, bp->size) < 0) 390bd389b36SDavid du Colombier wrerr(); 391bd389b36SDavid du Colombier } else 392*219b2ee8SDavid du Colombier skip(&bar, bp->size); 393bd389b36SDavid du Colombier free(bp); 394bd389b36SDavid du Colombier } 395bd389b36SDavid du Colombier close(fd); 396bd389b36SDavid du Colombier } 397bd389b36SDavid du Colombier void 398bd389b36SDavid du Colombier mcmd(char *arname, int count, char **files) 399bd389b36SDavid du Colombier { 400*219b2ee8SDavid du Colombier int fd, i; 401bd389b36SDavid du Colombier Arfile *ap; 402bd389b36SDavid du Colombier Armember *bp; 403bd389b36SDavid du Colombier 404bd389b36SDavid du Colombier if (count == 0) 405bd389b36SDavid du Colombier return; 406bd389b36SDavid du Colombier fd = openar(arname, ORDWR, 0); 407*219b2ee8SDavid du Colombier Binit(&bar, fd, OREAD); 408*219b2ee8SDavid du Colombier Bseek(&bar,seek(fd,0,1), 1); 409bd389b36SDavid du Colombier astart = newtempfile(artemp); 410bd389b36SDavid du Colombier amiddle = newtempfile(movtemp); 411bd389b36SDavid du Colombier aend = 0; 412bd389b36SDavid du Colombier ap = astart; 413*219b2ee8SDavid du Colombier for (i = 0; bp = getdir(&bar); i++) { 414bd389b36SDavid du Colombier if (bamatch(file, poname)) { 415bd389b36SDavid du Colombier aend = newtempfile(tailtemp); 416bd389b36SDavid du Colombier ap = aend; 417bd389b36SDavid du Colombier } 418bd389b36SDavid du Colombier if(match(count, files)) { 419bd389b36SDavid du Colombier mesg('m', file); 420*219b2ee8SDavid du Colombier scanobj(&bar, amiddle, bp->size); 421*219b2ee8SDavid du Colombier arcopy(&bar, amiddle, bp); 422bd389b36SDavid du Colombier } else 423*219b2ee8SDavid du Colombier /* 424*219b2ee8SDavid du Colombier * pitch the symdef file if it is at the beginning 425*219b2ee8SDavid du Colombier * of the archive and we aren't inserting in front 426*219b2ee8SDavid du Colombier * of it (ap == astart). 427*219b2ee8SDavid du Colombier */ 428*219b2ee8SDavid du Colombier if (ap == astart && i == 0 && strcmp(file, symdef) == 0) 429*219b2ee8SDavid du Colombier skip(&bar, bp->size); 430*219b2ee8SDavid du Colombier else { 431*219b2ee8SDavid du Colombier scanobj(&bar, ap, bp->size); 432*219b2ee8SDavid du Colombier arcopy(&bar, ap, bp); 433*219b2ee8SDavid du Colombier } 434bd389b36SDavid du Colombier } 435bd389b36SDavid du Colombier close(fd); 436bd389b36SDavid du Colombier if (poname[0] && aend == 0) 437bd389b36SDavid du Colombier fprint(2, "ar: %s not found - files moved to end.\n", poname); 438bd389b36SDavid du Colombier install(arname, astart, amiddle, aend); 439bd389b36SDavid du Colombier } 440bd389b36SDavid du Colombier void 441bd389b36SDavid du Colombier tcmd(char *arname, int count, char **files) 442bd389b36SDavid du Colombier { 443bd389b36SDavid du Colombier int fd; 444bd389b36SDavid du Colombier Armember *bp; 445bd389b36SDavid du Colombier char name[ARNAMESIZE+1]; 446bd389b36SDavid du Colombier 447bd389b36SDavid du Colombier fd = openar(arname, OREAD, 0); 448*219b2ee8SDavid du Colombier Binit(&bar, fd, OREAD); 449*219b2ee8SDavid du Colombier Bseek(&bar,seek(fd,0,1), 1); 450*219b2ee8SDavid du Colombier while(bp = getdir(&bar)) { 451bd389b36SDavid du Colombier if(count == 0 || match(count, files)) { 452bd389b36SDavid du Colombier if(vflag) 453bd389b36SDavid du Colombier longt(bp); 454*219b2ee8SDavid du Colombier trim(file, name, ARNAMESIZE); 455bd389b36SDavid du Colombier Bprint(&bout, "%s\n", name); 456bd389b36SDavid du Colombier } 457*219b2ee8SDavid du Colombier skip(&bar, bp->size); 458bd389b36SDavid du Colombier free(bp); 459bd389b36SDavid du Colombier } 460bd389b36SDavid du Colombier close(fd); 461bd389b36SDavid du Colombier } 462bd389b36SDavid du Colombier void 463bd389b36SDavid du Colombier qcmd(char *arname, int count, char **files) 464bd389b36SDavid du Colombier { 465*219b2ee8SDavid du Colombier int fd, i; 466bd389b36SDavid du Colombier Armember *bp; 467*219b2ee8SDavid du Colombier Biobuf *bfile; 468bd389b36SDavid du Colombier 469bd389b36SDavid du Colombier if(aflag || bflag) { 470bd389b36SDavid du Colombier fprint(2, "ar: abi not allowed with q\n"); 471bd389b36SDavid du Colombier exits("error"); 472bd389b36SDavid du Colombier } 473bd389b36SDavid du Colombier fd = openar(arname, ORDWR, 1); 474bd389b36SDavid du Colombier if (fd < 0) { 475bd389b36SDavid du Colombier if(!cflag) 476bd389b36SDavid du Colombier fprint(2, "ar: creating %s\n", arname); 477bd389b36SDavid du Colombier fd = arcreate(arname); 478bd389b36SDavid du Colombier } 479*219b2ee8SDavid du Colombier Binit(&bar, fd, OREAD); 480*219b2ee8SDavid du Colombier Bseek(&bar,seek(fd,0,1), 1); 481bd389b36SDavid du Colombier /* leave note group behind when writing archive; i.e. sidestep interrupts */ 482bd389b36SDavid du Colombier rfork(RFNOTEG); 483*219b2ee8SDavid du Colombier Bseek(&bar, 0, 2); 484bd389b36SDavid du Colombier bp = newmember(); 485bd389b36SDavid du Colombier for(i=0; i<count && files[i]; i++) { 486bd389b36SDavid du Colombier file = files[i]; 487bd389b36SDavid du Colombier files[i] = 0; 488*219b2ee8SDavid du Colombier bfile = Bopen(file, OREAD); 489*219b2ee8SDavid du Colombier if(!bfile) 490bd389b36SDavid du Colombier fprint(2, "ar: %s cannot open\n", file); 491bd389b36SDavid du Colombier else { 492bd389b36SDavid du Colombier mesg('q', file); 493*219b2ee8SDavid du Colombier armove(bfile, 0, bp); 494bd389b36SDavid du Colombier if (!arwrite(fd, bp)) 495bd389b36SDavid du Colombier wrerr(); 496bd389b36SDavid du Colombier free(bp->member); 497bd389b36SDavid du Colombier bp->member = 0; 498*219b2ee8SDavid du Colombier Bterm(bfile); 499bd389b36SDavid du Colombier } 500bd389b36SDavid du Colombier } 501bd389b36SDavid du Colombier free(bp); 502bd389b36SDavid du Colombier close(fd); 503bd389b36SDavid du Colombier } 504*219b2ee8SDavid du Colombier 505*219b2ee8SDavid du Colombier /* 506*219b2ee8SDavid du Colombier * extract the symbol references from an object file 507*219b2ee8SDavid du Colombier */ 508*219b2ee8SDavid du Colombier 509*219b2ee8SDavid du Colombier void 510*219b2ee8SDavid du Colombier scanobj(Biobuf *b, Arfile *ap, int size) 511*219b2ee8SDavid du Colombier { 512*219b2ee8SDavid du Colombier int obj; 513*219b2ee8SDavid du Colombier long offset; 514*219b2ee8SDavid du Colombier static int lastobj = -1; 515*219b2ee8SDavid du Colombier 516*219b2ee8SDavid du Colombier if (!allobj) /* non-object file encountered */ 517*219b2ee8SDavid du Colombier return; 518*219b2ee8SDavid du Colombier offset = BOFFSET(b); 519*219b2ee8SDavid du Colombier obj = objtype(b, 0); 520*219b2ee8SDavid du Colombier if (obj < 0) { /* not an object file */ 521*219b2ee8SDavid du Colombier allobj = 0; 522*219b2ee8SDavid du Colombier Bseek(b, offset, 0); 523*219b2ee8SDavid du Colombier return; 524*219b2ee8SDavid du Colombier } 525*219b2ee8SDavid du Colombier if (lastobj >= 0 && obj != lastobj) { 526*219b2ee8SDavid du Colombier fprint(2, "ar: inconsistent object file %s\n", file); 527*219b2ee8SDavid du Colombier allobj = 0; 528*219b2ee8SDavid du Colombier Bseek(b, offset, 0); 529*219b2ee8SDavid du Colombier return; 530*219b2ee8SDavid du Colombier } 531*219b2ee8SDavid du Colombier lastobj = obj; 532*219b2ee8SDavid du Colombier if (!readar(b, obj, offset+size, 0)) { 533*219b2ee8SDavid du Colombier fprint(2, "ar: invalid symbol reference in file %s\n", file); 534*219b2ee8SDavid du Colombier allobj = 0; 535*219b2ee8SDavid du Colombier Bseek(b, offset, 0); 536*219b2ee8SDavid du Colombier return; 537*219b2ee8SDavid du Colombier } 538*219b2ee8SDavid du Colombier Bseek(b, offset, 0); 539*219b2ee8SDavid du Colombier objtraverse(objsym, ap); 540*219b2ee8SDavid du Colombier } 541*219b2ee8SDavid du Colombier 542*219b2ee8SDavid du Colombier /* 543*219b2ee8SDavid du Colombier * add text and data symbols to the symbol list 544*219b2ee8SDavid du Colombier */ 545*219b2ee8SDavid du Colombier void 546*219b2ee8SDavid du Colombier objsym(Sym *s, void *p) 547*219b2ee8SDavid du Colombier { 548*219b2ee8SDavid du Colombier int n; 549*219b2ee8SDavid du Colombier Arsymref *as; 550*219b2ee8SDavid du Colombier Arfile *ap; 551*219b2ee8SDavid du Colombier 552*219b2ee8SDavid du Colombier if (s->type != 'T' && s->type != 'D') 553*219b2ee8SDavid du Colombier return; 554*219b2ee8SDavid du Colombier ap = (Arfile*)p; 555*219b2ee8SDavid du Colombier as = (Arsymref*)armalloc(sizeof(Arsymref)); 556*219b2ee8SDavid du Colombier as->offset = ap->size; 557*219b2ee8SDavid du Colombier n = strlen(s->name); 558*219b2ee8SDavid du Colombier as->name = armalloc(n+1); 559*219b2ee8SDavid du Colombier strcpy(as->name, s->name); 560*219b2ee8SDavid du Colombier as->type = s->type; 561*219b2ee8SDavid du Colombier symdefsize += 4+(n+1)+1; 562*219b2ee8SDavid du Colombier as->len = n; 563*219b2ee8SDavid du Colombier as->next = ap->sym; 564*219b2ee8SDavid du Colombier ap->sym = as; 565*219b2ee8SDavid du Colombier } 566*219b2ee8SDavid du Colombier 567bd389b36SDavid du Colombier /* 568bd389b36SDavid du Colombier * open an archive and validate its header 569bd389b36SDavid du Colombier */ 5703e12c5d1SDavid du Colombier int 571bd389b36SDavid du Colombier openar(char *arname, int mode, int errok) 5723e12c5d1SDavid du Colombier { 573bd389b36SDavid du Colombier int fd; 5743e12c5d1SDavid du Colombier char mbuf[SARMAG]; 5753e12c5d1SDavid du Colombier 576bd389b36SDavid du Colombier fd = open(arname, mode); 577bd389b36SDavid du Colombier if(fd >= 0){ 578bd389b36SDavid du Colombier if(read(fd, mbuf, SARMAG) != SARMAG || strncmp(mbuf, ARMAG, SARMAG)) { 579bd389b36SDavid du Colombier fprint(2, "ar: %s not in archive format\n", arname); 580bd389b36SDavid du Colombier exits("error"); 5813e12c5d1SDavid du Colombier } 582bd389b36SDavid du Colombier }else if(!errok){ 583bd389b36SDavid du Colombier fprint(2, "ar: cannot open %s: %r\n", arname); 584bd389b36SDavid du Colombier exits("error"); 585bd389b36SDavid du Colombier } 586bd389b36SDavid du Colombier return fd; 587bd389b36SDavid du Colombier } 588bd389b36SDavid du Colombier /* 589bd389b36SDavid du Colombier * create an archive and set its header 590bd389b36SDavid du Colombier */ 591bd389b36SDavid du Colombier int 592bd389b36SDavid du Colombier arcreate(char *arname) 593bd389b36SDavid du Colombier { 594bd389b36SDavid du Colombier int fd; 595bd389b36SDavid du Colombier 596bd389b36SDavid du Colombier fd = create(arname, OWRITE, 0664); 597bd389b36SDavid du Colombier if(fd < 0){ 598bd389b36SDavid du Colombier fprint(2, "ar: cannot create %s: %r\n", arname); 599bd389b36SDavid du Colombier exits("error"); 600bd389b36SDavid du Colombier } 601bd389b36SDavid du Colombier if(write(fd, ARMAG, SARMAG) != SARMAG) 602bd389b36SDavid du Colombier wrerr(); 603bd389b36SDavid du Colombier return fd; 604bd389b36SDavid du Colombier } 605bd389b36SDavid du Colombier /* 606bd389b36SDavid du Colombier * error handling 607bd389b36SDavid du Colombier */ 608bd389b36SDavid du Colombier void 609bd389b36SDavid du Colombier wrerr(void) 610bd389b36SDavid du Colombier { 611bd389b36SDavid du Colombier perror("ar: write error"); 612bd389b36SDavid du Colombier exits("error"); 6133e12c5d1SDavid du Colombier } 6143e12c5d1SDavid du Colombier 6153e12c5d1SDavid du Colombier void 616bd389b36SDavid du Colombier rderr(void) 6173e12c5d1SDavid du Colombier { 618bd389b36SDavid du Colombier perror("ar: read error"); 619bd389b36SDavid du Colombier exits("error"); 620bd389b36SDavid du Colombier } 6213e12c5d1SDavid du Colombier 622bd389b36SDavid du Colombier void 623bd389b36SDavid du Colombier phaseerr(int offset) 624bd389b36SDavid du Colombier { 625bd389b36SDavid du Colombier fprint(2, "ar: phase error at offset %d\n", offset); 626bd389b36SDavid du Colombier exits("error"); 6273e12c5d1SDavid du Colombier } 6283e12c5d1SDavid du Colombier 6293e12c5d1SDavid du Colombier void 6303e12c5d1SDavid du Colombier usage(void) 6313e12c5d1SDavid du Colombier { 632bd389b36SDavid du Colombier fprint(2, "usage: ar [%s][%s] archive files ...\n", opt, man); 633bd389b36SDavid du Colombier exits("error"); 6343e12c5d1SDavid du Colombier } 6353e12c5d1SDavid du Colombier /* 636bd389b36SDavid du Colombier * read the header for the next archive member 6373e12c5d1SDavid du Colombier */ 638bd389b36SDavid du Colombier Armember * 639*219b2ee8SDavid du Colombier getdir(Biobuf *b) 6403e12c5d1SDavid du Colombier { 641bd389b36SDavid du Colombier Armember *bp; 6423e12c5d1SDavid du Colombier char *cp; 643bd389b36SDavid du Colombier static char name[ARNAMESIZE+1]; 6443e12c5d1SDavid du Colombier 645bd389b36SDavid du Colombier bp = newmember(); 646*219b2ee8SDavid du Colombier if(HEADER_IO(Bread, b, bp->hdr)) { 647bd389b36SDavid du Colombier free(bp); 648bd389b36SDavid du Colombier return 0; 6493e12c5d1SDavid du Colombier } 650bd389b36SDavid du Colombier if(strncmp(bp->hdr.fmag, ARFMAG, sizeof(bp->hdr.fmag))) 651*219b2ee8SDavid du Colombier phaseerr(BOFFSET(b)); 652bd389b36SDavid du Colombier strncpy(name, bp->hdr.name, sizeof(bp->hdr.name)); 653bd389b36SDavid du Colombier cp = name+sizeof(name)-1; 6543e12c5d1SDavid du Colombier while(*--cp==' ') 6553e12c5d1SDavid du Colombier ; 6563e12c5d1SDavid du Colombier cp[1] = '\0'; 6573e12c5d1SDavid du Colombier file = name; 658bd389b36SDavid du Colombier bp->date = atol(bp->hdr.date); 659bd389b36SDavid du Colombier bp->size = atol(bp->hdr.size); 660bd389b36SDavid du Colombier return bp; 6613e12c5d1SDavid du Colombier } 662bd389b36SDavid du Colombier /* 663bd389b36SDavid du Colombier * Copy the file referenced by fd to the temp file 664bd389b36SDavid du Colombier */ 665bd389b36SDavid du Colombier void 666*219b2ee8SDavid du Colombier armove(Biobuf *b, Arfile *ap, Armember *bp) 667bd389b36SDavid du Colombier { 668bd389b36SDavid du Colombier char *cp; 669bd389b36SDavid du Colombier Dir d; 6703e12c5d1SDavid du Colombier 671*219b2ee8SDavid du Colombier if (dirfstat(Bfildes(b), &d) < 0) { 672bd389b36SDavid du Colombier fprint(2, "ar: cannot stat %s\n", file); 673bd389b36SDavid du Colombier return; 674bd389b36SDavid du Colombier } 675bd389b36SDavid du Colombier trim(file, bp->hdr.name, sizeof(bp->hdr.name)); 676bd389b36SDavid du Colombier for (cp = strchr(bp->hdr.name, 0); /* blank pad on right */ 677bd389b36SDavid du Colombier cp < bp->hdr.name+sizeof(bp->hdr.name); cp++) 678bd389b36SDavid du Colombier *cp = ' '; 679bd389b36SDavid du Colombier sprint(bp->hdr.date, "%-12ld", d.mtime); 680bd389b36SDavid du Colombier sprint(bp->hdr.uid, "%-6d", 0); 681bd389b36SDavid du Colombier sprint(bp->hdr.gid, "%-6d", 0); 682bd389b36SDavid du Colombier sprint(bp->hdr.mode, "%-8lo", d.mode); 683bd389b36SDavid du Colombier sprint(bp->hdr.size, "%-10ld", d.length); 684bd389b36SDavid du Colombier strncpy(bp->hdr.fmag, ARFMAG, 2); 685bd389b36SDavid du Colombier bp->size = d.length; 686bd389b36SDavid du Colombier bp->date = d.mtime; 687*219b2ee8SDavid du Colombier arread(b, bp, bp->size); 688*219b2ee8SDavid du Colombier if (d.length&0x01) 689*219b2ee8SDavid du Colombier d.length++; 690*219b2ee8SDavid du Colombier if (ap) { 691bd389b36SDavid du Colombier arinsert(ap, bp); 692*219b2ee8SDavid du Colombier ap->size += d.length+SAR_HDR; 693*219b2ee8SDavid du Colombier } 694bd389b36SDavid du Colombier } 695bd389b36SDavid du Colombier /* 696bd389b36SDavid du Colombier * Copy the archive member at the current offset into the temp file. 697bd389b36SDavid du Colombier */ 698bd389b36SDavid du Colombier void 699*219b2ee8SDavid du Colombier arcopy(Biobuf *b, Arfile *ap, Armember *bp) 700bd389b36SDavid du Colombier { 701bd389b36SDavid du Colombier int n; 7023e12c5d1SDavid du Colombier 703bd389b36SDavid du Colombier n = bp->size; 704bd389b36SDavid du Colombier if (n & 01) 705bd389b36SDavid du Colombier n++; 706*219b2ee8SDavid du Colombier arread(b, bp, n); 707*219b2ee8SDavid du Colombier if (ap) { 708bd389b36SDavid du Colombier arinsert(ap, bp); 709*219b2ee8SDavid du Colombier ap->size += n+SAR_HDR; 710*219b2ee8SDavid du Colombier } 711bd389b36SDavid du Colombier } 712bd389b36SDavid du Colombier /* 713bd389b36SDavid du Colombier * Skip an archive member 714bd389b36SDavid du Colombier */ 715bd389b36SDavid du Colombier void 716*219b2ee8SDavid du Colombier skip(Biobuf *bp, long len) 717bd389b36SDavid du Colombier { 718bd389b36SDavid du Colombier if (len & 01) 719bd389b36SDavid du Colombier len++; 720*219b2ee8SDavid du Colombier Bseek(bp, len, 1); 721bd389b36SDavid du Colombier } 722bd389b36SDavid du Colombier /* 723bd389b36SDavid du Colombier * Stream the three temp files to an archive 724bd389b36SDavid du Colombier */ 725bd389b36SDavid du Colombier void 726bd389b36SDavid du Colombier install(char *arname, Arfile *astart, Arfile *amiddle, Arfile *aend) 727bd389b36SDavid du Colombier { 728bd389b36SDavid du Colombier int fd; 729bd389b36SDavid du Colombier 730bd389b36SDavid du Colombier /* leave note group behind when copying back; i.e. sidestep interrupts */ 731bd389b36SDavid du Colombier rfork(RFNOTEG); 732bd389b36SDavid du Colombier fd = arcreate(arname); 733*219b2ee8SDavid du Colombier rl(fd); 734bd389b36SDavid du Colombier if (astart) { 735bd389b36SDavid du Colombier arstream(fd, astart); 736bd389b36SDavid du Colombier arfree(astart); 737bd389b36SDavid du Colombier } 738bd389b36SDavid du Colombier if (amiddle) { 739bd389b36SDavid du Colombier arstream(fd, amiddle); 740bd389b36SDavid du Colombier arfree(amiddle); 741bd389b36SDavid du Colombier } 742bd389b36SDavid du Colombier if (aend) { 743bd389b36SDavid du Colombier arstream(fd, aend); 744bd389b36SDavid du Colombier arfree(aend); 745bd389b36SDavid du Colombier } 746bd389b36SDavid du Colombier close(fd); 747bd389b36SDavid du Colombier } 748*219b2ee8SDavid du Colombier void 749*219b2ee8SDavid du Colombier rl(int fd) 750*219b2ee8SDavid du Colombier { 751*219b2ee8SDavid du Colombier 752*219b2ee8SDavid du Colombier Biobuf b; 753*219b2ee8SDavid du Colombier char *cp; 754*219b2ee8SDavid du Colombier struct ar_hdr a; 755*219b2ee8SDavid du Colombier long len; 756*219b2ee8SDavid du Colombier 757*219b2ee8SDavid du Colombier if (!allobj) 758*219b2ee8SDavid du Colombier return; 759*219b2ee8SDavid du Colombier 760*219b2ee8SDavid du Colombier Binit(&b, fd, OWRITE); 761*219b2ee8SDavid du Colombier Bseek(&b,seek(fd,0,1), 0); 762*219b2ee8SDavid du Colombier 763*219b2ee8SDavid du Colombier len = symdefsize; 764*219b2ee8SDavid du Colombier if(len&01) 765*219b2ee8SDavid du Colombier len++; 766*219b2ee8SDavid du Colombier sprint(a.date, "%-12ld", time(0)); 767*219b2ee8SDavid du Colombier sprint(a.uid, "%-6d", 0); 768*219b2ee8SDavid du Colombier sprint(a.gid, "%-6d", 0); 769*219b2ee8SDavid du Colombier sprint(a.mode, "%-8lo", 0644); 770*219b2ee8SDavid du Colombier sprint(a.size, "%-10ld", len); 771*219b2ee8SDavid du Colombier strncpy(a.fmag, ARFMAG, 2); 772*219b2ee8SDavid du Colombier strcpy(a.name, symdef); 773*219b2ee8SDavid du Colombier for (cp = strchr(a.name, 0); /* blank pad on right */ 774*219b2ee8SDavid du Colombier cp < a.name+sizeof(a.name); cp++) 775*219b2ee8SDavid du Colombier *cp = ' '; 776*219b2ee8SDavid du Colombier if(HEADER_IO(Bwrite, &b, a)) 777*219b2ee8SDavid du Colombier wrerr(); 778*219b2ee8SDavid du Colombier 779*219b2ee8SDavid du Colombier len += BOFFSET(&b); 780*219b2ee8SDavid du Colombier if (astart) { 781*219b2ee8SDavid du Colombier wrsym(&b, len, astart->sym); 782*219b2ee8SDavid du Colombier len += astart->size; 783*219b2ee8SDavid du Colombier } 784*219b2ee8SDavid du Colombier if(amiddle) { 785*219b2ee8SDavid du Colombier wrsym(&b, len, amiddle->sym); 786*219b2ee8SDavid du Colombier len += amiddle->size; 787*219b2ee8SDavid du Colombier } 788*219b2ee8SDavid du Colombier if(aend) 789*219b2ee8SDavid du Colombier wrsym(&b, len, aend->sym); 790*219b2ee8SDavid du Colombier 791*219b2ee8SDavid du Colombier if(symdefsize&0x01) 792*219b2ee8SDavid du Colombier Bputc(&b, 0); 793*219b2ee8SDavid du Colombier Bterm(&b); 794*219b2ee8SDavid du Colombier } 795*219b2ee8SDavid du Colombier /* 796*219b2ee8SDavid du Colombier * Write the defined symbols to the symdef file 797*219b2ee8SDavid du Colombier */ 798*219b2ee8SDavid du Colombier void 799*219b2ee8SDavid du Colombier wrsym(Biobuf *bp, int offset, Arsymref *as) 800*219b2ee8SDavid du Colombier { 801*219b2ee8SDavid du Colombier int off; 802*219b2ee8SDavid du Colombier 803*219b2ee8SDavid du Colombier while(as) { 804*219b2ee8SDavid du Colombier Bputc(bp, as->type); 805*219b2ee8SDavid du Colombier off = as->offset+offset; 806*219b2ee8SDavid du Colombier Bputc(bp, off); 807*219b2ee8SDavid du Colombier Bputc(bp, off>>8); 808*219b2ee8SDavid du Colombier Bputc(bp, off>>16); 809*219b2ee8SDavid du Colombier Bputc(bp, off>>24); 810*219b2ee8SDavid du Colombier if (Bwrite(bp, as->name, as->len+1) != as->len+1) 811*219b2ee8SDavid du Colombier wrerr(); 812*219b2ee8SDavid du Colombier as = as->next; 813*219b2ee8SDavid du Colombier } 814*219b2ee8SDavid du Colombier } 815bd389b36SDavid du Colombier /* 816bd389b36SDavid du Colombier * Check if the archive member matches an entry on the command line. 817bd389b36SDavid du Colombier */ 8183e12c5d1SDavid du Colombier int 819bd389b36SDavid du Colombier match(int count, char **files) 8203e12c5d1SDavid du Colombier { 8213e12c5d1SDavid du Colombier int i; 822bd389b36SDavid du Colombier char name[ARNAMESIZE+1]; 8233e12c5d1SDavid du Colombier 824bd389b36SDavid du Colombier for(i=0; i<count; i++) { 825bd389b36SDavid du Colombier if(files[i] == 0) 8263e12c5d1SDavid du Colombier continue; 827*219b2ee8SDavid du Colombier trim(files[i], name, ARNAMESIZE); 828*219b2ee8SDavid du Colombier if(strncmp(name, file, ARNAMESIZE) == 0) { 829bd389b36SDavid du Colombier file = files[i]; 830bd389b36SDavid du Colombier files[i] = 0; 8313e12c5d1SDavid du Colombier return 1; 8323e12c5d1SDavid du Colombier } 8333e12c5d1SDavid du Colombier } 8343e12c5d1SDavid du Colombier return 0; 8353e12c5d1SDavid du Colombier } 836bd389b36SDavid du Colombier /* 837bd389b36SDavid du Colombier * compare the current member to the name of the pivot member 838bd389b36SDavid du Colombier */ 839bd389b36SDavid du Colombier int 840bd389b36SDavid du Colombier bamatch(char *file, char *pivot) 8413e12c5d1SDavid du Colombier { 842bd389b36SDavid du Colombier static int state = 0; 8433e12c5d1SDavid du Colombier 844bd389b36SDavid du Colombier switch(state) 845bd389b36SDavid du Colombier { 846bd389b36SDavid du Colombier case 0: /* looking for position file */ 847bd389b36SDavid du Colombier if (aflag) { 848*219b2ee8SDavid du Colombier if (strncmp(file, pivot, ARNAMESIZE) == 0) 849bd389b36SDavid du Colombier state = 1; 850bd389b36SDavid du Colombier } else if (bflag) { 851*219b2ee8SDavid du Colombier if (strncmp(file, pivot, ARNAMESIZE) == 0) { 852bd389b36SDavid du Colombier state = 2; /* found */ 853bd389b36SDavid du Colombier return 1; 8543e12c5d1SDavid du Colombier } 8553e12c5d1SDavid du Colombier } 856bd389b36SDavid du Colombier break; 857bd389b36SDavid du Colombier case 1: /* found - after previous file */ 858bd389b36SDavid du Colombier state = 2; 859bd389b36SDavid du Colombier return 1; 860bd389b36SDavid du Colombier case 2: /* already found position file */ 861bd389b36SDavid du Colombier break; 862bd389b36SDavid du Colombier } 863bd389b36SDavid du Colombier return 0; 864bd389b36SDavid du Colombier } 865bd389b36SDavid du Colombier /* 866bd389b36SDavid du Colombier * output a message, if 'v' option was specified 867bd389b36SDavid du Colombier */ 8683e12c5d1SDavid du Colombier void 869bd389b36SDavid du Colombier mesg(int c, char *file) 8703e12c5d1SDavid du Colombier { 8713e12c5d1SDavid du Colombier 872bd389b36SDavid du Colombier if(vflag) 8733e12c5d1SDavid du Colombier Bprint(&bout, "%c - %s\n", c, file); 8743e12c5d1SDavid du Colombier } 875bd389b36SDavid du Colombier /* 876bd389b36SDavid du Colombier * isolate file name by stripping leading directories and trailing slashes 877bd389b36SDavid du Colombier */ 878bd389b36SDavid du Colombier void 879bd389b36SDavid du Colombier trim(char *s, char *buf, int n) 8803e12c5d1SDavid du Colombier { 881bd389b36SDavid du Colombier char *p; 8823e12c5d1SDavid du Colombier 883bd389b36SDavid du Colombier for(;;) { 884bd389b36SDavid du Colombier p = strrchr(s, '/'); 885bd389b36SDavid du Colombier if (!p) { /* no slash in name */ 886bd389b36SDavid du Colombier strncpy(buf, s, n); 887bd389b36SDavid du Colombier return; 8883e12c5d1SDavid du Colombier } 889bd389b36SDavid du Colombier if (p[1] != 0) { /* p+1 is first char of file name */ 890bd389b36SDavid du Colombier strncpy(buf, p+1, n); 891bd389b36SDavid du Colombier return; 8923e12c5d1SDavid du Colombier } 893bd389b36SDavid du Colombier *p = 0; /* strip trailing slash */ 894bd389b36SDavid du Colombier } 895bd389b36SDavid du Colombier } 896bd389b36SDavid du Colombier /* 897bd389b36SDavid du Colombier * utilities for printing long form of 't' command 898bd389b36SDavid du Colombier */ 8993e12c5d1SDavid du Colombier #define SUID 04000 9003e12c5d1SDavid du Colombier #define SGID 02000 9013e12c5d1SDavid du Colombier #define ROWN 0400 9023e12c5d1SDavid du Colombier #define WOWN 0200 9033e12c5d1SDavid du Colombier #define XOWN 0100 9043e12c5d1SDavid du Colombier #define RGRP 040 9053e12c5d1SDavid du Colombier #define WGRP 020 9063e12c5d1SDavid du Colombier #define XGRP 010 9073e12c5d1SDavid du Colombier #define ROTH 04 9083e12c5d1SDavid du Colombier #define WOTH 02 9093e12c5d1SDavid du Colombier #define XOTH 01 9103e12c5d1SDavid du Colombier #define STXT 01000 9113e12c5d1SDavid du Colombier 9123e12c5d1SDavid du Colombier void 913bd389b36SDavid du Colombier longt(Armember *bp) 9143e12c5d1SDavid du Colombier { 9153e12c5d1SDavid du Colombier char *cp; 9163e12c5d1SDavid du Colombier 917bd389b36SDavid du Colombier pmode(strtoul(bp->hdr.mode, 0, 8)); 918bd389b36SDavid du Colombier Bprint(&bout, "%3d/%1d", atol(bp->hdr.uid), atol(bp->hdr.gid)); 919bd389b36SDavid du Colombier Bprint(&bout, "%7ld", bp->size); 920bd389b36SDavid du Colombier cp = ctime(bp->date); 9213e12c5d1SDavid du Colombier Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24); 9223e12c5d1SDavid du Colombier } 9233e12c5d1SDavid du Colombier 9243e12c5d1SDavid du Colombier int m1[] = { 1, ROWN, 'r', '-' }; 9253e12c5d1SDavid du Colombier int m2[] = { 1, WOWN, 'w', '-' }; 9263e12c5d1SDavid du Colombier int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; 9273e12c5d1SDavid du Colombier int m4[] = { 1, RGRP, 'r', '-' }; 9283e12c5d1SDavid du Colombier int m5[] = { 1, WGRP, 'w', '-' }; 9293e12c5d1SDavid du Colombier int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; 9303e12c5d1SDavid du Colombier int m7[] = { 1, ROTH, 'r', '-' }; 9313e12c5d1SDavid du Colombier int m8[] = { 1, WOTH, 'w', '-' }; 9323e12c5d1SDavid du Colombier int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; 9333e12c5d1SDavid du Colombier 9343e12c5d1SDavid du Colombier int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 9353e12c5d1SDavid du Colombier 9363e12c5d1SDavid du Colombier void 937bd389b36SDavid du Colombier pmode(long mode) 9383e12c5d1SDavid du Colombier { 9393e12c5d1SDavid du Colombier int **mp; 9403e12c5d1SDavid du Colombier 9413e12c5d1SDavid du Colombier for(mp = &m[0]; mp < &m[9];) 942bd389b36SDavid du Colombier select(*mp++, mode); 9433e12c5d1SDavid du Colombier } 9443e12c5d1SDavid du Colombier 9453e12c5d1SDavid du Colombier void 946bd389b36SDavid du Colombier select(int *ap, long mode) 9473e12c5d1SDavid du Colombier { 948bd389b36SDavid du Colombier int n; 9493e12c5d1SDavid du Colombier 9503e12c5d1SDavid du Colombier n = *ap++; 951bd389b36SDavid du Colombier while(--n>=0 && (mode&*ap++)==0) 9523e12c5d1SDavid du Colombier ap++; 9533e12c5d1SDavid du Colombier Bputc(&bout, *ap); 9543e12c5d1SDavid du Colombier } 955bd389b36SDavid du Colombier /* 956bd389b36SDavid du Colombier * Temp file I/O subsystem. We attempt to cache all three temp files in 957bd389b36SDavid du Colombier * core. When we run out of memory we spill to disk. 958bd389b36SDavid du Colombier * The I/O model assumes that temp files: 959bd389b36SDavid du Colombier * 1) are only written on the end 960bd389b36SDavid du Colombier * 2) are only read from the beginning 961bd389b36SDavid du Colombier * 3) are only read after all writing is complete. 962bd389b36SDavid du Colombier * The architecture uses one control block per temp file. Each control 963bd389b36SDavid du Colombier * block anchors a chain of buffers, each containing an archive member. 964bd389b36SDavid du Colombier */ 965bd389b36SDavid du Colombier Arfile * 966bd389b36SDavid du Colombier newtempfile(char *name) /* allocate a file control block */ 967bd389b36SDavid du Colombier { 968bd389b36SDavid du Colombier Arfile *ap; 969bd389b36SDavid du Colombier 970bd389b36SDavid du Colombier ap = (Arfile *) armalloc(sizeof(Arfile)); 971bd389b36SDavid du Colombier ap->fname = name; 972bd389b36SDavid du Colombier return ap; 973bd389b36SDavid du Colombier } 974bd389b36SDavid du Colombier 975bd389b36SDavid du Colombier Armember * 976bd389b36SDavid du Colombier newmember(void) /* allocate a member buffer */ 977bd389b36SDavid du Colombier { 978bd389b36SDavid du Colombier return (Armember *)armalloc(sizeof(Armember)); 979bd389b36SDavid du Colombier } 9803e12c5d1SDavid du Colombier 9813e12c5d1SDavid du Colombier void 982*219b2ee8SDavid du Colombier arread(Biobuf *b, Armember *bp, int n) /* read an image into a member buffer */ 9833e12c5d1SDavid du Colombier { 984bd389b36SDavid du Colombier int i; 985bd389b36SDavid du Colombier 986bd389b36SDavid du Colombier bp->member = armalloc(n); 987*219b2ee8SDavid du Colombier i = Bread(b, bp->member, n); 988bd389b36SDavid du Colombier if (i < 0) { 989bd389b36SDavid du Colombier free(bp->member); 990bd389b36SDavid du Colombier bp->member = 0; 991bd389b36SDavid du Colombier rderr(); 992bd389b36SDavid du Colombier } 993bd389b36SDavid du Colombier } 994bd389b36SDavid du Colombier /* 995bd389b36SDavid du Colombier * insert a member buffer into the member chain 996bd389b36SDavid du Colombier */ 997bd389b36SDavid du Colombier void 998bd389b36SDavid du Colombier arinsert(Arfile *ap, Armember *bp) 999bd389b36SDavid du Colombier { 1000bd389b36SDavid du Colombier bp->next = 0; 1001bd389b36SDavid du Colombier if (!ap->tail) 1002bd389b36SDavid du Colombier ap->head = bp; 1003bd389b36SDavid du Colombier else 1004bd389b36SDavid du Colombier ap->tail->next = bp; 1005bd389b36SDavid du Colombier ap->tail = bp; 1006bd389b36SDavid du Colombier } 1007bd389b36SDavid du Colombier /* 1008bd389b36SDavid du Colombier * stream the members in a temp file to the file referenced by 'fd'. 1009bd389b36SDavid du Colombier */ 1010bd389b36SDavid du Colombier void 1011bd389b36SDavid du Colombier arstream(int fd, Arfile *ap) 1012bd389b36SDavid du Colombier { 1013bd389b36SDavid du Colombier Armember *bp; 1014bd389b36SDavid du Colombier int i; 1015bd389b36SDavid du Colombier char buf[8192]; 1016bd389b36SDavid du Colombier 1017bd389b36SDavid du Colombier if (ap->paged) { /* copy from disk */ 1018bd389b36SDavid du Colombier seek(ap->fd, 0, 0); 1019bd389b36SDavid du Colombier for (;;) { 1020bd389b36SDavid du Colombier i = read(ap->fd, buf, sizeof(buf)); 1021bd389b36SDavid du Colombier if (i < 0) 1022bd389b36SDavid du Colombier rderr(); 1023bd389b36SDavid du Colombier if (i == 0) 1024bd389b36SDavid du Colombier break; 1025bd389b36SDavid du Colombier if (write(fd, buf, i) != i) 1026bd389b36SDavid du Colombier wrerr(); 1027bd389b36SDavid du Colombier } 1028bd389b36SDavid du Colombier close(ap->fd); 1029bd389b36SDavid du Colombier ap->paged = 0; 1030bd389b36SDavid du Colombier } 1031bd389b36SDavid du Colombier /* dump the in-core buffers */ 1032bd389b36SDavid du Colombier for (bp = ap->head; bp; bp = bp->next) { 1033bd389b36SDavid du Colombier if (!arwrite(fd, bp)) 1034bd389b36SDavid du Colombier wrerr(); 1035bd389b36SDavid du Colombier } 1036bd389b36SDavid du Colombier } 1037bd389b36SDavid du Colombier /* 1038bd389b36SDavid du Colombier * write a member to 'fd'. 1039bd389b36SDavid du Colombier */ 1040bd389b36SDavid du Colombier int 1041bd389b36SDavid du Colombier arwrite(int fd, Armember *bp) 1042bd389b36SDavid du Colombier { 1043bd389b36SDavid du Colombier int len; 1044bd389b36SDavid du Colombier 1045*219b2ee8SDavid du Colombier if(HEADER_IO(write, fd, bp->hdr)) 1046bd389b36SDavid du Colombier return 0; 1047bd389b36SDavid du Colombier len = bp->size; 1048bd389b36SDavid du Colombier if (len & 01) 1049bd389b36SDavid du Colombier len++; 1050bd389b36SDavid du Colombier if (write(fd, bp->member, len) != len) 1051bd389b36SDavid du Colombier return 0; 1052bd389b36SDavid du Colombier return 1; 1053bd389b36SDavid du Colombier } 1054bd389b36SDavid du Colombier /* 1055bd389b36SDavid du Colombier * Spill a member to a disk copy of a temp file 1056bd389b36SDavid du Colombier */ 1057bd389b36SDavid du Colombier int 1058bd389b36SDavid du Colombier page(Arfile *ap) 1059bd389b36SDavid du Colombier { 1060bd389b36SDavid du Colombier Armember *bp; 1061bd389b36SDavid du Colombier 1062bd389b36SDavid du Colombier bp = ap->head; 1063bd389b36SDavid du Colombier if (!ap->paged) { /* not yet paged - create file */ 1064bd389b36SDavid du Colombier ap->fname = mktemp(ap->fname); 1065bd389b36SDavid du Colombier ap->fd = create(ap->fname, ORDWR|ORCLOSE, 0600); 1066bd389b36SDavid du Colombier if (ap->fd < 0) { 1067bd389b36SDavid du Colombier fprint(2,"ar: can't create temp file\n"); 1068bd389b36SDavid du Colombier return 0; 1069bd389b36SDavid du Colombier } 1070bd389b36SDavid du Colombier ap->paged = 1; 1071bd389b36SDavid du Colombier } 1072bd389b36SDavid du Colombier if (!arwrite(ap->fd, bp)) /* write member and free buffer block */ 1073bd389b36SDavid du Colombier return 0; 1074bd389b36SDavid du Colombier ap->head = bp->next; 1075bd389b36SDavid du Colombier if (ap->tail == bp) 1076bd389b36SDavid du Colombier ap->tail = bp->next; 1077bd389b36SDavid du Colombier free(bp->member); 1078bd389b36SDavid du Colombier free(bp); 1079bd389b36SDavid du Colombier return 1; 1080bd389b36SDavid du Colombier } 1081bd389b36SDavid du Colombier /* 1082bd389b36SDavid du Colombier * try to reclaim space by paging. we try to spill the start, middle, 1083bd389b36SDavid du Colombier * and end files, in that order. there is no particular reason for the 1084bd389b36SDavid du Colombier * ordering. 1085bd389b36SDavid du Colombier */ 1086bd389b36SDavid du Colombier int 1087bd389b36SDavid du Colombier getspace(void) 1088bd389b36SDavid du Colombier { 1089bd389b36SDavid du Colombier if (astart && astart->head && page(astart)) 1090bd389b36SDavid du Colombier return 1; 1091bd389b36SDavid du Colombier if (amiddle && amiddle->head && page(amiddle)) 1092bd389b36SDavid du Colombier return 1; 1093bd389b36SDavid du Colombier if (aend && aend->head && page(aend)) 1094bd389b36SDavid du Colombier return 1; 1095bd389b36SDavid du Colombier return 0; 1096bd389b36SDavid du Colombier } 1097bd389b36SDavid du Colombier 1098bd389b36SDavid du Colombier void 1099bd389b36SDavid du Colombier arfree(Arfile *ap) /* free a member buffer */ 1100bd389b36SDavid du Colombier { 1101bd389b36SDavid du Colombier Armember *bp, *next; 1102bd389b36SDavid du Colombier 1103bd389b36SDavid du Colombier for (bp = ap->head; bp; bp = next) { 1104bd389b36SDavid du Colombier next = bp->next; 1105bd389b36SDavid du Colombier if (bp->member) 1106bd389b36SDavid du Colombier free(bp->member); 1107bd389b36SDavid du Colombier free(bp); 1108bd389b36SDavid du Colombier } 1109bd389b36SDavid du Colombier free(ap); 1110bd389b36SDavid du Colombier } 1111bd389b36SDavid du Colombier /* 1112bd389b36SDavid du Colombier * allocate space for a control block or member buffer. if the malloc 1113bd389b36SDavid du Colombier * fails we try to reclaim space by spilling previously allocated 1114bd389b36SDavid du Colombier * member buffers. 1115bd389b36SDavid du Colombier */ 1116bd389b36SDavid du Colombier char * 1117bd389b36SDavid du Colombier armalloc(int n) 1118bd389b36SDavid du Colombier { 1119bd389b36SDavid du Colombier char *cp; 1120bd389b36SDavid du Colombier 1121bd389b36SDavid du Colombier do { 1122bd389b36SDavid du Colombier cp = malloc(n); 1123bd389b36SDavid du Colombier if (cp) { 1124bd389b36SDavid du Colombier memset(cp, 0, n); 1125bd389b36SDavid du Colombier return cp; 1126bd389b36SDavid du Colombier } 1127bd389b36SDavid du Colombier } while (getspace()); 1128bd389b36SDavid du Colombier fprint(2, "ar: out of memory\n"); 1129bd389b36SDavid du Colombier exits("malloc"); 1130bd389b36SDavid du Colombier return 0; 11313e12c5d1SDavid du Colombier } 1132