ar.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197
  1. /*
  2. * ar - portable (ascii) format version
  3. */
  4. #include <lib9.h>
  5. #include <bio.h>
  6. #include <mach.h>
  7. #include <ar.h>
  8. /*
  9. * The algorithm uses up to 3 temp files. The "pivot member" is the
  10. * archive member specified by and a, b, or i option. The temp files are
  11. * astart - contains existing members up to and including the pivot member.
  12. * amiddle - contains new files moved or inserted behind the pivot.
  13. * aend - contains the existing members that follow the pivot member.
  14. * When all members have been processed, function 'install' streams the
  15. * temp files, in order, back into the archive.
  16. */
  17. typedef struct Arsymref
  18. {
  19. char *name;
  20. int type;
  21. int len;
  22. long offset;
  23. struct Arsymref *next;
  24. } Arsymref;
  25. typedef struct Armember /* Temp file entry - one per archive member */
  26. {
  27. struct Armember *next;
  28. struct ar_hdr hdr;
  29. long size;
  30. long date;
  31. void *member;
  32. } Armember;
  33. typedef struct Arfile /* Temp file control block - one per tempfile */
  34. {
  35. int paged; /* set when some data paged to disk */
  36. char *fname; /* paging file name */
  37. int fd; /* paging file descriptor */
  38. long size;
  39. Armember *head; /* head of member chain */
  40. Armember *tail; /* tail of member chain */
  41. Arsymref *sym; /* head of defined symbol chain */
  42. } Arfile;
  43. typedef struct Hashchain
  44. {
  45. char *name;
  46. struct Hashchain *next;
  47. } Hashchain;
  48. #define NHASH 1024
  49. /*
  50. * macro to portably read/write archive header.
  51. * 'cmd' is read/write/Bread/Bwrite, etc.
  52. */
  53. #define HEADER_IO(cmd, f, h) cmd(f, h.name, sizeof(h.name)) != sizeof(h.name)\
  54. || cmd(f, h.date, sizeof(h.date)) != sizeof(h.date)\
  55. || cmd(f, h.uid, sizeof(h.uid)) != sizeof(h.uid)\
  56. || cmd(f, h.gid, sizeof(h.gid)) != sizeof(h.gid)\
  57. || cmd(f, h.mode, sizeof(h.mode)) != sizeof(h.mode)\
  58. || cmd(f, h.size, sizeof(h.size)) != sizeof(h.size)\
  59. || cmd(f, h.fmag, sizeof(h.fmag)) != sizeof(h.fmag)
  60. /* constants and flags */
  61. char *man = "mrxtdpq";
  62. char *opt = "uvnbailo";
  63. char artemp[] = "/tmp/vXXXXX";
  64. char movtemp[] = "/tmp/v1XXXXX";
  65. char tailtemp[] = "/tmp/v2XXXXX";
  66. char symdef[] = "__.SYMDEF";
  67. int aflag; /* command line flags */
  68. int bflag;
  69. int cflag;
  70. int oflag;
  71. int uflag;
  72. int vflag;
  73. Arfile *astart, *amiddle, *aend; /* Temp file control block pointers */
  74. int allobj = 1; /* set when all members are object files of the same type */
  75. int symdefsize; /* size of symdef file */
  76. int dupfound; /* flag for duplicate symbol */
  77. Hashchain *hash[NHASH]; /* hash table of text symbols */
  78. #define ARNAMESIZE sizeof(astart->tail->hdr.name)
  79. char poname[ARNAMESIZE+1]; /* name of pivot member */
  80. char *file; /* current file or member being worked on */
  81. Biobuf bout;
  82. Biobuf bar;
  83. void arcopy(Biobuf*, Arfile*, Armember*);
  84. int arcreate(char*);
  85. void arfree(Arfile*);
  86. void arinsert(Arfile*, Armember*);
  87. char *armalloc(int);
  88. void armove(Biobuf*, Arfile*, Armember*);
  89. void arread(Biobuf*, Armember*, int);
  90. void arstream(int, Arfile*);
  91. int arwrite(int, Armember*);
  92. int bamatch(char*, char*);
  93. int duplicate(char*);
  94. Armember *getdir(Biobuf*);
  95. int getspace(void);
  96. void install(char*, Arfile*, Arfile*, Arfile*, int);
  97. void longt(Armember*);
  98. int match(int, char**);
  99. void mesg(int, char*);
  100. char *myctime(long); /* $TARGMODEL.c */
  101. Arfile *newtempfile(char*);
  102. Armember *newmember(void);
  103. void objsym(Sym*, void*);
  104. int openar(char*, int, int);
  105. int page(Arfile*);
  106. void pmode(long);
  107. void rl(int);
  108. void scanobj(Biobuf*, Arfile*, int);
  109. void ar_select(int*, long);
  110. void setcom(void(*)(char*, int, char**));
  111. void skip(Biobuf*, long);
  112. int symcomp(void*, void*);
  113. void trim(char*, char*, int);
  114. void usage(void);
  115. void wrerr(void);
  116. void wrsym(Biobuf*, int, Arsymref*);
  117. void arcmd(char*, int, char**); /* command processing */
  118. void dcmd(char*, int, char**);
  119. void xcmd(char*, int, char**);
  120. void tcmd(char*, int, char**);
  121. void pcmd(char*, int, char**);
  122. void mcmd(char*, int, char**);
  123. void qcmd(char*, int, char**);
  124. void (*comfun)(char*, int, char**);
  125. void
  126. main(int argc, char *argv[])
  127. {
  128. char *cp;
  129. Binit(&bout, 1, OWRITE);
  130. if(argc < 3)
  131. usage();
  132. for (cp = argv[1]; *cp; cp++) {
  133. switch(*cp) {
  134. case 'a': aflag = 1; break;
  135. case 'b': bflag = 1; break;
  136. case 'c': cflag = 1; break;
  137. case 'd': setcom(dcmd); break;
  138. case 'i': bflag = 1; break;
  139. case 'l':
  140. strcpy(artemp, "vXXXXX");
  141. strcpy(movtemp, "v1XXXXX");
  142. strcpy(tailtemp, "v2XXXXX");
  143. break;
  144. case 'm': setcom(mcmd); break;
  145. case 'o': oflag = 1; break;
  146. case 'p': setcom(pcmd); break;
  147. case 'q': setcom(qcmd); break;
  148. case 'r': setcom(arcmd); break;
  149. case 't': setcom(tcmd); break;
  150. case 'u': uflag = 1; break;
  151. case 'v': vflag = 1; break;
  152. case 'x': setcom(xcmd); break;
  153. default:
  154. fprint(2, "ar: bad option `%c'\n", *cp);
  155. exits("error");
  156. }
  157. }
  158. if (aflag && bflag) {
  159. fprint(2, "ar: only one of 'a' and 'b' can be specified\n");
  160. usage();
  161. }
  162. if(aflag || bflag) {
  163. trim(argv[2], poname, sizeof(poname));
  164. argv++;
  165. argc--;
  166. if(argc < 3)
  167. usage();
  168. }
  169. if(comfun == 0) {
  170. if(uflag == 0) {
  171. fprint(2, "ar: one of [%s] must be specified\n", man);
  172. usage();
  173. }
  174. setcom(arcmd);
  175. }
  176. cp = argv[2];
  177. argc -= 3;
  178. argv += 3;
  179. (*comfun)(cp, argc, argv); /* do the command */
  180. cp = 0;
  181. while (argc--) {
  182. if (*argv) {
  183. fprint(2, "ar: %s not found\n", *argv);
  184. cp = "error";
  185. }
  186. argv++;
  187. }
  188. if(allobj && dupfound)
  189. exits("dup found");
  190. exits(cp);
  191. }
  192. /*
  193. * select a command
  194. */
  195. void
  196. setcom(void (*fun)(char *, int, char**))
  197. {
  198. if(comfun != 0) {
  199. fprint(2, "ar: only one of [%s] allowed\n", man);
  200. usage();
  201. }
  202. comfun = fun;
  203. }
  204. /*
  205. * perform the 'r' and 'u' commands
  206. */
  207. void
  208. arcmd(char *arname, int count, char **files)
  209. {
  210. int fd;
  211. int i;
  212. Arfile *ap;
  213. Armember *bp;
  214. Dir *d;
  215. Biobuf *bfile;
  216. fd = openar(arname, ORDWR, 1);
  217. if (fd >= 0) {
  218. Binit(&bar, fd, OREAD);
  219. Bseek(&bar,seek(fd,0,1), 1);
  220. }
  221. astart = newtempfile(artemp);
  222. ap = astart;
  223. aend = 0;
  224. for(i = 0; fd >= 0; i++) {
  225. bp = getdir(&bar);
  226. if (!bp)
  227. break;
  228. if (bamatch(file, poname)) { /* check for pivot */
  229. aend = newtempfile(tailtemp);
  230. ap = aend;
  231. }
  232. /* pitch symdef file */
  233. if (i == 0 && strcmp(file, symdef) == 0) {
  234. skip(&bar, bp->size);
  235. continue;
  236. }
  237. if (count && !match(count, files)) {
  238. scanobj(&bar, ap, bp->size);
  239. arcopy(&bar, ap, bp);
  240. continue;
  241. }
  242. bfile = Bopen(file, OREAD);
  243. if (!bfile) {
  244. if (count != 0)
  245. fprint(2, "ar: cannot open %s\n", file);
  246. scanobj(&bar, ap, bp->size);
  247. arcopy(&bar, ap, bp);
  248. continue;
  249. }
  250. d = dirfstat(Bfildes(bfile));
  251. if (d == nil)
  252. fprint(2, "ar: cannot stat %s: %r\n", file);
  253. if (uflag && (d == nil || d->mtime <= bp->date)) {
  254. scanobj(&bar, ap, bp->size);
  255. arcopy(&bar, ap, bp);
  256. Bterm(bfile);
  257. free(d);
  258. continue;
  259. }
  260. mesg('r', file);
  261. skip(&bar, bp->size);
  262. scanobj(bfile, ap, d->length);
  263. free(d);
  264. armove(bfile, ap, bp);
  265. Bterm(bfile);
  266. }
  267. if(fd >= 0)
  268. close(fd);
  269. /* copy in remaining files named on command line */
  270. for (i = 0; i < count; i++) {
  271. file = files[i];
  272. if(file == 0)
  273. continue;
  274. files[i] = 0;
  275. bfile = Bopen(file, OREAD);
  276. if (!bfile)
  277. fprint(2, "ar: %s cannot open\n", file);
  278. else {
  279. mesg('a', file);
  280. d = dirfstat(Bfildes(bfile));
  281. if (d == nil)
  282. fprint(2, "ar: can't stat %s: %r\n", file);
  283. else {
  284. scanobj(bfile, astart, d->length);
  285. armove(bfile, astart, newmember());
  286. free(d);
  287. }
  288. Bterm(bfile);
  289. }
  290. }
  291. if(fd < 0 && !cflag)
  292. install(arname, astart, 0, aend, 1); /* issue 'creating' msg */
  293. else
  294. install(arname, astart, 0, aend, 0);
  295. }
  296. void
  297. dcmd(char *arname, int count, char **files)
  298. {
  299. Armember *bp;
  300. int fd, i;
  301. if (!count)
  302. return;
  303. fd = openar(arname, ORDWR, 0);
  304. Binit(&bar, fd, OREAD);
  305. Bseek(&bar,seek(fd,0,1), 1);
  306. astart = newtempfile(artemp);
  307. for (i = 0; bp = getdir(&bar); i++) {
  308. if(match(count, files)) {
  309. mesg('d', file);
  310. skip(&bar, bp->size);
  311. if (strcmp(file, symdef) == 0)
  312. allobj = 0;
  313. } else if (i == 0 && strcmp(file, symdef) == 0)
  314. skip(&bar, bp->size);
  315. else {
  316. scanobj(&bar, astart, bp->size);
  317. arcopy(&bar, astart, bp);
  318. }
  319. }
  320. close(fd);
  321. install(arname, astart, 0, 0, 0);
  322. }
  323. void
  324. xcmd(char *arname, int count, char **files)
  325. {
  326. int fd, f, mode, i;
  327. Armember *bp;
  328. Dir dx;
  329. fd = openar(arname, OREAD, 0);
  330. Binit(&bar, fd, OREAD);
  331. Bseek(&bar,seek(fd,0,1), 1);
  332. i = 0;
  333. while (bp = getdir(&bar)) {
  334. if(count == 0 || match(count, files)) {
  335. mode = strtoul(bp->hdr.mode, 0, 8) & 0777;
  336. f = create(file, OWRITE, mode);
  337. if(f < 0) {
  338. fprint(2, "ar: %s cannot create\n", file);
  339. skip(&bar, bp->size);
  340. } else {
  341. mesg('x', file);
  342. arcopy(&bar, 0, bp);
  343. if (write(f, bp->member, bp->size) < 0)
  344. wrerr();
  345. if(oflag) {
  346. nulldir(&dx);
  347. dx.atime = bp->date;
  348. dx.mtime = bp->date;
  349. if(dirwstat(file, &dx) < 0)
  350. perror(file);
  351. }
  352. free(bp->member);
  353. close(f);
  354. }
  355. free(bp);
  356. if (count && ++i >= count)
  357. break;
  358. } else {
  359. skip(&bar, bp->size);
  360. free(bp);
  361. }
  362. }
  363. close(fd);
  364. }
  365. void
  366. pcmd(char *arname, int count, char **files)
  367. {
  368. int fd;
  369. Armember *bp;
  370. fd = openar(arname, OREAD, 0);
  371. Binit(&bar, fd, OREAD);
  372. Bseek(&bar,seek(fd,0,1), 1);
  373. while(bp = getdir(&bar)) {
  374. if(count == 0 || match(count, files)) {
  375. if(vflag)
  376. print("\n<%s>\n\n", file);
  377. arcopy(&bar, 0, bp);
  378. if (write(1, bp->member, bp->size) < 0)
  379. wrerr();
  380. } else
  381. skip(&bar, bp->size);
  382. free(bp);
  383. }
  384. close(fd);
  385. }
  386. void
  387. mcmd(char *arname, int count, char **files)
  388. {
  389. int fd, i;
  390. Arfile *ap;
  391. Armember *bp;
  392. if (count == 0)
  393. return;
  394. fd = openar(arname, ORDWR, 0);
  395. Binit(&bar, fd, OREAD);
  396. Bseek(&bar,seek(fd,0,1), 1);
  397. astart = newtempfile(artemp);
  398. amiddle = newtempfile(movtemp);
  399. aend = 0;
  400. ap = astart;
  401. for (i = 0; bp = getdir(&bar); i++) {
  402. if (bamatch(file, poname)) {
  403. aend = newtempfile(tailtemp);
  404. ap = aend;
  405. }
  406. if(match(count, files)) {
  407. mesg('m', file);
  408. scanobj(&bar, amiddle, bp->size);
  409. arcopy(&bar, amiddle, bp);
  410. } else
  411. /*
  412. * pitch the symdef file if it is at the beginning
  413. * of the archive and we aren't inserting in front
  414. * of it (ap == astart).
  415. */
  416. if (ap == astart && i == 0 && strcmp(file, symdef) == 0)
  417. skip(&bar, bp->size);
  418. else {
  419. scanobj(&bar, ap, bp->size);
  420. arcopy(&bar, ap, bp);
  421. }
  422. }
  423. close(fd);
  424. if (poname[0] && aend == 0)
  425. fprint(2, "ar: %s not found - files moved to end.\n", poname);
  426. install(arname, astart, amiddle, aend, 0);
  427. }
  428. void
  429. tcmd(char *arname, int count, char **files)
  430. {
  431. int fd;
  432. Armember *bp;
  433. char name[ARNAMESIZE+1];
  434. fd = openar(arname, OREAD, 0);
  435. Binit(&bar, fd, OREAD);
  436. Bseek(&bar,seek(fd,0,1), 1);
  437. while(bp = getdir(&bar)) {
  438. if(count == 0 || match(count, files)) {
  439. if(vflag)
  440. longt(bp);
  441. trim(file, name, ARNAMESIZE);
  442. Bprint(&bout, "%s\n", name);
  443. }
  444. skip(&bar, bp->size);
  445. free(bp);
  446. }
  447. close(fd);
  448. }
  449. void
  450. qcmd(char *arname, int count, char **files)
  451. {
  452. int fd, i;
  453. Armember *bp;
  454. Biobuf *bfile;
  455. if(aflag || bflag) {
  456. fprint(2, "ar: abi not allowed with q\n");
  457. exits("error");
  458. }
  459. fd = openar(arname, ORDWR, 1);
  460. if (fd < 0) {
  461. if(!cflag)
  462. fprint(2, "ar: creating %s\n", arname);
  463. fd = arcreate(arname);
  464. }
  465. Binit(&bar, fd, OREAD);
  466. Bseek(&bar,seek(fd,0,1), 1);
  467. Bseek(&bar, 0, 2);
  468. bp = newmember();
  469. for(i=0; i<count && files[i]; i++) {
  470. file = files[i];
  471. files[i] = 0;
  472. bfile = Bopen(file, OREAD);
  473. if(!bfile)
  474. fprint(2, "ar: %s cannot open\n", file);
  475. else {
  476. mesg('q', file);
  477. armove(bfile, 0, bp);
  478. if (!arwrite(fd, bp))
  479. wrerr();
  480. free(bp->member);
  481. bp->member = 0;
  482. Bterm(bfile);
  483. }
  484. }
  485. free(bp);
  486. close(fd);
  487. }
  488. /*
  489. * extract the symbol references from an object file
  490. */
  491. void
  492. scanobj(Biobuf *b, Arfile *ap, int size)
  493. {
  494. int obj;
  495. long offset;
  496. Dir *d;
  497. static int lastobj = -1;
  498. if (!allobj) /* non-object file encountered */
  499. return;
  500. offset = Boffset(b);
  501. obj = objtype(b, 0);
  502. if (obj < 0) { /* not an object file */
  503. allobj = 0;
  504. d = dirfstat(Bfildes(b));
  505. if (d != nil && d->length == 0)
  506. fprint(2, "ar: zero length file %s\n", file);
  507. free(d);
  508. Bseek(b, offset, 0);
  509. return;
  510. }
  511. if (lastobj >= 0 && obj != lastobj) {
  512. fprint(2, "ar: inconsistent object file %s\n", file);
  513. allobj = 0;
  514. Bseek(b, offset, 0);
  515. return;
  516. }
  517. lastobj = obj;
  518. if (!readar(b, obj, offset+size, 0)) {
  519. fprint(2, "ar: invalid symbol reference in file %s\n", file);
  520. allobj = 0;
  521. Bseek(b, offset, 0);
  522. return;
  523. }
  524. Bseek(b, offset, 0);
  525. objtraverse(objsym, ap);
  526. }
  527. /*
  528. * add text and data symbols to the symbol list
  529. */
  530. void
  531. objsym(Sym *s, void *p)
  532. {
  533. int n;
  534. Arsymref *as;
  535. Arfile *ap;
  536. if (s->type != 'T' && s->type != 'D')
  537. return;
  538. ap = (Arfile*)p;
  539. as = (Arsymref*)armalloc(sizeof(Arsymref));
  540. as->offset = ap->size;
  541. n = strlen(s->name);
  542. as->name = armalloc(n+1);
  543. strcpy(as->name, s->name);
  544. if(s->type == 'T' && duplicate(as->name)) {
  545. dupfound = 1;
  546. fprint(2, "duplicate text symbol: %s\n", as->name);
  547. free(as->name);
  548. free(as);
  549. return;
  550. }
  551. as->type = s->type;
  552. symdefsize += 4+(n+1)+1;
  553. as->len = n;
  554. as->next = ap->sym;
  555. ap->sym = as;
  556. }
  557. /*
  558. * Check the symbol table for duplicate text symbols
  559. */
  560. int
  561. duplicate(char *name)
  562. {
  563. Hashchain *p;
  564. char *cp;
  565. int h;
  566. h = 0;
  567. for(cp = name; *cp; h += *cp++)
  568. h *= 1119;
  569. if(h < 0)
  570. h = ~h;
  571. h %= NHASH;
  572. for(p = hash[h]; p; p = p->next)
  573. if(strcmp(p->name, name) == 0)
  574. return 1;
  575. p = (Hashchain*) armalloc(sizeof(Hashchain));
  576. p->next = hash[h];
  577. p->name = name;
  578. hash[h] = p;
  579. return 0;
  580. }
  581. /*
  582. * open an archive and validate its header
  583. */
  584. int
  585. openar(char *arname, int mode, int errok)
  586. {
  587. int fd;
  588. char mbuf[SARMAG];
  589. fd = open(arname, mode);
  590. if(fd >= 0){
  591. if(read(fd, mbuf, SARMAG) != SARMAG || strncmp(mbuf, ARMAG, SARMAG)) {
  592. fprint(2, "ar: %s not in archive format\n", arname);
  593. exits("error");
  594. }
  595. }else if(!errok){
  596. fprint(2, "ar: cannot open %s: %r\n", arname);
  597. exits("error");
  598. }
  599. return fd;
  600. }
  601. /*
  602. * create an archive and set its header
  603. */
  604. int
  605. arcreate(char *arname)
  606. {
  607. int fd;
  608. fd = create(arname, OWRITE, 0664);
  609. if(fd < 0){
  610. fprint(2, "ar: cannot create %s: %r\n", arname);
  611. exits("error");
  612. }
  613. if(write(fd, ARMAG, SARMAG) != SARMAG)
  614. wrerr();
  615. return fd;
  616. }
  617. /*
  618. * error handling
  619. */
  620. void
  621. wrerr(void)
  622. {
  623. perror("ar: write error");
  624. exits("error");
  625. }
  626. void
  627. rderr(void)
  628. {
  629. perror("ar: read error");
  630. exits("error");
  631. }
  632. void
  633. phaseerr(int offset)
  634. {
  635. fprint(2, "ar: phase error at offset %d\n", offset);
  636. exits("error");
  637. }
  638. void
  639. usage(void)
  640. {
  641. fprint(2, "usage: ar [%s][%s] archive files ...\n", opt, man);
  642. exits("error");
  643. }
  644. /*
  645. * read the header for the next archive member
  646. */
  647. Armember *
  648. getdir(Biobuf *b)
  649. {
  650. Armember *bp;
  651. char *cp;
  652. static char name[ARNAMESIZE+1];
  653. bp = newmember();
  654. if(HEADER_IO(Bread, b, bp->hdr)) {
  655. free(bp);
  656. return 0;
  657. }
  658. if(strncmp(bp->hdr.fmag, ARFMAG, sizeof(bp->hdr.fmag)))
  659. phaseerr(Boffset(b));
  660. strncpy(name, bp->hdr.name, sizeof(bp->hdr.name));
  661. cp = name+sizeof(name)-1;
  662. while(*--cp==' ')
  663. ;
  664. cp[1] = '\0';
  665. file = name;
  666. bp->date = atol(bp->hdr.date);
  667. bp->size = atol(bp->hdr.size);
  668. return bp;
  669. }
  670. /*
  671. * Copy the file referenced by fd to the temp file
  672. */
  673. void
  674. armove(Biobuf *b, Arfile *ap, Armember *bp)
  675. {
  676. char *cp;
  677. Dir *d;
  678. if ((d = dirfstat(Bfildes(b))) == nil) {
  679. fprint(2, "ar: cannot stat %s: %r\n", file);
  680. return;
  681. }
  682. trim(file, bp->hdr.name, sizeof(bp->hdr.name));
  683. for (cp = strchr(bp->hdr.name, 0); /* blank pad on right */
  684. cp < bp->hdr.name+sizeof(bp->hdr.name); cp++)
  685. *cp = ' ';
  686. sprint(bp->hdr.date, "%-12ld", d->mtime);
  687. sprint(bp->hdr.uid, "%-6d", 0);
  688. sprint(bp->hdr.gid, "%-6d", 0);
  689. sprint(bp->hdr.mode, "%-8lo", d->mode);
  690. sprint(bp->hdr.size, "%-10lld", (vlong)d->length);
  691. strncpy(bp->hdr.fmag, ARFMAG, 2);
  692. bp->size = d->length;
  693. bp->date = d->mtime;
  694. arread(b, bp, bp->size);
  695. if (d->length&0x01)
  696. d->length++;
  697. if (ap) {
  698. arinsert(ap, bp);
  699. ap->size += d->length+SAR_HDR;
  700. }
  701. free(d);
  702. }
  703. /*
  704. * Copy the archive member at the current offset into the temp file.
  705. */
  706. void
  707. arcopy(Biobuf *b, Arfile *ap, Armember *bp)
  708. {
  709. int n;
  710. n = bp->size;
  711. if (n & 01)
  712. n++;
  713. arread(b, bp, n);
  714. if (ap) {
  715. arinsert(ap, bp);
  716. ap->size += n+SAR_HDR;
  717. }
  718. }
  719. /*
  720. * Skip an archive member
  721. */
  722. void
  723. skip(Biobuf *bp, long len)
  724. {
  725. if (len & 01)
  726. len++;
  727. Bseek(bp, len, 1);
  728. }
  729. /*
  730. * Stream the three temp files to an archive
  731. */
  732. void
  733. install(char *arname, Arfile *astart, Arfile *amiddle, Arfile *aend, int createflag)
  734. {
  735. int fd;
  736. if(allobj && dupfound) {
  737. fprint(2, "%s not changed\n", arname);
  738. return;
  739. }
  740. if(createflag)
  741. fprint(2, "ar: creating %s\n", arname);
  742. fd = arcreate(arname);
  743. if(allobj)
  744. rl(fd);
  745. if (astart) {
  746. arstream(fd, astart);
  747. arfree(astart);
  748. }
  749. if (amiddle) {
  750. arstream(fd, amiddle);
  751. arfree(amiddle);
  752. }
  753. if (aend) {
  754. arstream(fd, aend);
  755. arfree(aend);
  756. }
  757. close(fd);
  758. }
  759. void
  760. rl(int fd)
  761. {
  762. Biobuf b;
  763. char *cp;
  764. struct ar_hdr a;
  765. long len;
  766. Binit(&b, fd, OWRITE);
  767. Bseek(&b,seek(fd,0,1), 0);
  768. len = symdefsize;
  769. if(len&01)
  770. len++;
  771. sprint(a.date, "%-12ld", time(0));
  772. sprint(a.uid, "%-6d", 0);
  773. sprint(a.gid, "%-6d", 0);
  774. sprint(a.mode, "%-8o", 0644);
  775. sprint(a.size, "%-10ld", len);
  776. strncpy(a.fmag, ARFMAG, 2);
  777. strcpy(a.name, symdef);
  778. for (cp = strchr(a.name, 0); /* blank pad on right */
  779. cp < a.name+sizeof(a.name); cp++)
  780. *cp = ' ';
  781. if(HEADER_IO(Bwrite, &b, a))
  782. wrerr();
  783. len += Boffset(&b);
  784. if (astart) {
  785. wrsym(&b, len, astart->sym);
  786. len += astart->size;
  787. }
  788. if(amiddle) {
  789. wrsym(&b, len, amiddle->sym);
  790. len += amiddle->size;
  791. }
  792. if(aend)
  793. wrsym(&b, len, aend->sym);
  794. if(symdefsize&0x01)
  795. Bputc(&b, 0);
  796. Bterm(&b);
  797. }
  798. /*
  799. * Write the defined symbols to the symdef file
  800. */
  801. void
  802. wrsym(Biobuf *bp, int offset, Arsymref *as)
  803. {
  804. int off;
  805. while(as) {
  806. Bputc(bp, as->type);
  807. off = as->offset+offset;
  808. Bputc(bp, off);
  809. Bputc(bp, off>>8);
  810. Bputc(bp, off>>16);
  811. Bputc(bp, off>>24);
  812. if (Bwrite(bp, as->name, as->len+1) != as->len+1)
  813. wrerr();
  814. as = as->next;
  815. }
  816. }
  817. /*
  818. * Check if the archive member matches an entry on the command line.
  819. */
  820. int
  821. match(int count, char **files)
  822. {
  823. int i;
  824. char name[ARNAMESIZE+1];
  825. for(i=0; i<count; i++) {
  826. if(files[i] == 0)
  827. continue;
  828. trim(files[i], name, ARNAMESIZE);
  829. if(strncmp(name, file, ARNAMESIZE) == 0) {
  830. file = files[i];
  831. files[i] = 0;
  832. return 1;
  833. }
  834. }
  835. return 0;
  836. }
  837. /*
  838. * compare the current member to the name of the pivot member
  839. */
  840. int
  841. bamatch(char *file, char *pivot)
  842. {
  843. static int state = 0;
  844. switch(state)
  845. {
  846. case 0: /* looking for position file */
  847. if (aflag) {
  848. if (strncmp(file, pivot, ARNAMESIZE) == 0)
  849. state = 1;
  850. } else if (bflag) {
  851. if (strncmp(file, pivot, ARNAMESIZE) == 0) {
  852. state = 2; /* found */
  853. return 1;
  854. }
  855. }
  856. break;
  857. case 1: /* found - after previous file */
  858. state = 2;
  859. return 1;
  860. case 2: /* already found position file */
  861. break;
  862. }
  863. return 0;
  864. }
  865. /*
  866. * output a message, if 'v' option was specified
  867. */
  868. void
  869. mesg(int c, char *file)
  870. {
  871. if(vflag)
  872. Bprint(&bout, "%c - %s\n", c, file);
  873. }
  874. /*
  875. * isolate file name by stripping leading directories and trailing slashes
  876. */
  877. void
  878. trim(char *s, char *buf, int n)
  879. {
  880. char *p;
  881. for(;;) {
  882. p = strrchr(s, '/');
  883. if (!p) { /* no slash in name */
  884. strncpy(buf, s, n);
  885. return;
  886. }
  887. if (p[1] != 0) { /* p+1 is first char of file name */
  888. strncpy(buf, p+1, n);
  889. return;
  890. }
  891. *p = 0; /* strip trailing slash */
  892. }
  893. }
  894. /*
  895. * utilities for printing long form of 't' command
  896. */
  897. #define SUID 04000
  898. #define SGID 02000
  899. #define ROWN 0400
  900. #define WOWN 0200
  901. #define XOWN 0100
  902. #define RGRP 040
  903. #define WGRP 020
  904. #define XGRP 010
  905. #define ROTH 04
  906. #define WOTH 02
  907. #define XOTH 01
  908. #define STXT 01000
  909. void
  910. longt(Armember *bp)
  911. {
  912. char *cp;
  913. pmode(strtoul(bp->hdr.mode, 0, 8));
  914. Bprint(&bout, "%3ld/%1ld", atol(bp->hdr.uid), atol(bp->hdr.gid));
  915. Bprint(&bout, "%7ld", bp->size);
  916. cp = myctime(bp->date);
  917. Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24);
  918. }
  919. int m1[] = { 1, ROWN, 'r', '-' };
  920. int m2[] = { 1, WOWN, 'w', '-' };
  921. int m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
  922. int m4[] = { 1, RGRP, 'r', '-' };
  923. int m5[] = { 1, WGRP, 'w', '-' };
  924. int m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
  925. int m7[] = { 1, ROTH, 'r', '-' };
  926. int m8[] = { 1, WOTH, 'w', '-' };
  927. int m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
  928. int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
  929. void
  930. pmode(long mode)
  931. {
  932. int **mp;
  933. for(mp = &m[0]; mp < &m[9];)
  934. ar_select(*mp++, mode);
  935. }
  936. void
  937. ar_select(int *ap, long mode)
  938. {
  939. int n;
  940. n = *ap++;
  941. while(--n>=0 && (mode&*ap++)==0)
  942. ap++;
  943. Bputc(&bout, *ap);
  944. }
  945. /*
  946. * Temp file I/O subsystem. We attempt to cache all three temp files in
  947. * core. When we run out of memory we spill to disk.
  948. * The I/O model assumes that temp files:
  949. * 1) are only written on the end
  950. * 2) are only read from the beginning
  951. * 3) are only read after all writing is complete.
  952. * The architecture uses one control block per temp file. Each control
  953. * block anchors a chain of buffers, each containing an archive member.
  954. */
  955. Arfile *
  956. newtempfile(char *name) /* allocate a file control block */
  957. {
  958. Arfile *ap;
  959. ap = (Arfile *) armalloc(sizeof(Arfile));
  960. ap->fname = name;
  961. return ap;
  962. }
  963. Armember *
  964. newmember(void) /* allocate a member buffer */
  965. {
  966. return (Armember *)armalloc(sizeof(Armember));
  967. }
  968. void
  969. arread(Biobuf *b, Armember *bp, int n) /* read an image into a member buffer */
  970. {
  971. int i;
  972. bp->member = armalloc(n);
  973. i = Bread(b, bp->member, n);
  974. if (i < 0) {
  975. free(bp->member);
  976. bp->member = 0;
  977. rderr();
  978. }
  979. }
  980. /*
  981. * insert a member buffer into the member chain
  982. */
  983. void
  984. arinsert(Arfile *ap, Armember *bp)
  985. {
  986. bp->next = 0;
  987. if (!ap->tail)
  988. ap->head = bp;
  989. else
  990. ap->tail->next = bp;
  991. ap->tail = bp;
  992. }
  993. /*
  994. * stream the members in a temp file to the file referenced by 'fd'.
  995. */
  996. void
  997. arstream(int fd, Arfile *ap)
  998. {
  999. Armember *bp;
  1000. int i;
  1001. char buf[8192];
  1002. if (ap->paged) { /* copy from disk */
  1003. seek(ap->fd, 0, 0);
  1004. for (;;) {
  1005. i = read(ap->fd, buf, sizeof(buf));
  1006. if (i < 0)
  1007. rderr();
  1008. if (i == 0)
  1009. break;
  1010. if (write(fd, buf, i) != i)
  1011. wrerr();
  1012. }
  1013. close(ap->fd);
  1014. ap->paged = 0;
  1015. }
  1016. /* dump the in-core buffers */
  1017. for (bp = ap->head; bp; bp = bp->next) {
  1018. if (!arwrite(fd, bp))
  1019. wrerr();
  1020. }
  1021. }
  1022. /*
  1023. * write a member to 'fd'.
  1024. */
  1025. int
  1026. arwrite(int fd, Armember *bp)
  1027. {
  1028. int len;
  1029. if(HEADER_IO(write, fd, bp->hdr))
  1030. return 0;
  1031. len = bp->size;
  1032. if (len & 01)
  1033. len++;
  1034. if (write(fd, bp->member, len) != len)
  1035. return 0;
  1036. return 1;
  1037. }
  1038. /*
  1039. * Spill a member to a disk copy of a temp file
  1040. */
  1041. int
  1042. page(Arfile *ap)
  1043. {
  1044. Armember *bp;
  1045. bp = ap->head;
  1046. if (!ap->paged) { /* not yet paged - create file */
  1047. ap->fname = mktemp(ap->fname);
  1048. ap->fd = create(ap->fname, ORDWR|ORCLOSE, 0600);
  1049. if (ap->fd < 0) {
  1050. fprint(2,"ar: can't create temp file\n");
  1051. return 0;
  1052. }
  1053. ap->paged = 1;
  1054. }
  1055. if (!arwrite(ap->fd, bp)) /* write member and free buffer block */
  1056. return 0;
  1057. ap->head = bp->next;
  1058. if (ap->tail == bp)
  1059. ap->tail = bp->next;
  1060. free(bp->member);
  1061. free(bp);
  1062. return 1;
  1063. }
  1064. /*
  1065. * try to reclaim space by paging. we try to spill the start, middle,
  1066. * and end files, in that order. there is no particular reason for the
  1067. * ordering.
  1068. */
  1069. int
  1070. getspace(void)
  1071. {
  1072. if (astart && astart->head && page(astart))
  1073. return 1;
  1074. if (amiddle && amiddle->head && page(amiddle))
  1075. return 1;
  1076. if (aend && aend->head && page(aend))
  1077. return 1;
  1078. return 0;
  1079. }
  1080. void
  1081. arfree(Arfile *ap) /* free a member buffer */
  1082. {
  1083. Armember *bp, *next;
  1084. for (bp = ap->head; bp; bp = next) {
  1085. next = bp->next;
  1086. if (bp->member)
  1087. free(bp->member);
  1088. free(bp);
  1089. }
  1090. free(ap);
  1091. }
  1092. /*
  1093. * allocate space for a control block or member buffer. if the malloc
  1094. * fails we try to reclaim space by spilling previously allocated
  1095. * member buffers.
  1096. */
  1097. char *
  1098. armalloc(int n)
  1099. {
  1100. char *cp;
  1101. do {
  1102. cp = malloc(n);
  1103. if (cp) {
  1104. memset(cp, 0, n);
  1105. return cp;
  1106. }
  1107. } while (getspace());
  1108. fprint(2, "ar: out of memory\n");
  1109. exits("malloc");
  1110. return 0;
  1111. }
  1112. /*
  1113. * Nt stub for GetNameFromID() in lib9\dirstat-Nt.c.
  1114. * Other architectures never call it.
  1115. */
  1116. char *
  1117. GetNameFromID(int id)
  1118. {
  1119. USED(id);
  1120. return "unknown";
  1121. }