ar.c 23 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189
  1. /*
  2. * ar - portable (ascii) format version
  3. */
  4. #include <u.h>
  5. #include <libc.h>
  6. #include <bio.h>
  7. #include <mach.h>
  8. #include <ar.h>
  9. /*
  10. * The algorithm uses up to 3 temp files. The "pivot member" is the
  11. * archive member specified by and a, b, or i option. The temp files are
  12. * astart - contains existing members up to and including the pivot member.
  13. * amiddle - contains new files moved or inserted behind the pivot.
  14. * aend - contains the existing members that follow the pivot member.
  15. * When all members have been processed, function 'install' streams the
  16. * temp files, in order, back into the archive.
  17. */
  18. typedef struct Arsymref
  19. {
  20. char *name;
  21. int type;
  22. int len;
  23. long offset;
  24. struct Arsymref *next;
  25. } Arsymref;
  26. typedef struct Armember /* Temp file entry - one per archive member */
  27. {
  28. struct Armember *next;
  29. struct ar_hdr hdr;
  30. long size;
  31. long date;
  32. void *member;
  33. } Armember;
  34. typedef struct Arfile /* Temp file control block - one per tempfile */
  35. {
  36. int paged; /* set when some data paged to disk */
  37. char *fname; /* paging file name */
  38. int fd; /* paging file descriptor */
  39. long size;
  40. Armember *head; /* head of member chain */
  41. Armember *tail; /* tail of member chain */
  42. Arsymref *sym; /* head of defined symbol chain */
  43. } Arfile;
  44. typedef struct Hashchain
  45. {
  46. char *name;
  47. struct Hashchain *next;
  48. } Hashchain;
  49. #define NHASH 1024
  50. /*
  51. * macro to portably read/write archive header.
  52. * 'cmd' is read/write/Bread/Bwrite, etc.
  53. */
  54. #define HEADER_IO(cmd, f, h) cmd(f, h.name, sizeof(h.name)) != sizeof(h.name)\
  55. || cmd(f, h.date, sizeof(h.date)) != sizeof(h.date)\
  56. || cmd(f, h.uid, sizeof(h.uid)) != sizeof(h.uid)\
  57. || cmd(f, h.gid, sizeof(h.gid)) != sizeof(h.gid)\
  58. || cmd(f, h.mode, sizeof(h.mode)) != sizeof(h.mode)\
  59. || cmd(f, h.size, sizeof(h.size)) != sizeof(h.size)\
  60. || cmd(f, h.fmag, sizeof(h.fmag)) != sizeof(h.fmag)
  61. /* constants and flags */
  62. char *man = "mrxtdpq";
  63. char *opt = "uvnbailo";
  64. char artemp[] = "/tmp/vXXXXX";
  65. char movtemp[] = "/tmp/v1XXXXX";
  66. char tailtemp[] = "/tmp/v2XXXXX";
  67. char symdef[] = "__.SYMDEF";
  68. int aflag; /* command line flags */
  69. int bflag;
  70. int cflag;
  71. int oflag;
  72. int uflag;
  73. int vflag;
  74. Arfile *astart, *amiddle, *aend; /* Temp file control block pointers */
  75. int allobj = 1; /* set when all members are object files of the same type */
  76. int symdefsize; /* size of symdef file */
  77. int dupfound; /* flag for duplicate symbol */
  78. Hashchain *hash[NHASH]; /* hash table of text symbols */
  79. #define ARNAMESIZE sizeof(astart->tail->hdr.name)
  80. char poname[ARNAMESIZE+1]; /* name of pivot member */
  81. char *file; /* current file or member being worked on */
  82. Biobuf bout;
  83. Biobuf bar;
  84. void arcopy(Biobuf*, Arfile*, Armember*);
  85. int arcreate(char*);
  86. void arfree(Arfile*);
  87. void arinsert(Arfile*, Armember*);
  88. char *armalloc(int);
  89. void armove(Biobuf*, Arfile*, Armember*);
  90. void arread(Biobuf*, Armember*, int);
  91. void arstream(int, Arfile*);
  92. int arwrite(int, Armember*);
  93. int bamatch(char*, char*);
  94. int duplicate(char*);
  95. Armember *getdir(Biobuf*);
  96. int getspace(void);
  97. void install(char*, Arfile*, Arfile*, Arfile*, int);
  98. void longt(Armember*);
  99. int match(int, char**);
  100. void mesg(int, char*);
  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 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 rcmd(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(rcmd); 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(rcmd);
  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. exits(cp);
  189. }
  190. /*
  191. * select a command
  192. */
  193. void
  194. setcom(void (*fun)(char *, int, char**))
  195. {
  196. if(comfun != 0) {
  197. fprint(2, "ar: only one of [%s] allowed\n", man);
  198. usage();
  199. }
  200. comfun = fun;
  201. }
  202. /*
  203. * perform the 'r' and 'u' commands
  204. */
  205. void
  206. rcmd(char *arname, int count, char **files)
  207. {
  208. int fd;
  209. int i;
  210. Arfile *ap;
  211. Armember *bp;
  212. Dir *d;
  213. Biobuf *bfile;
  214. fd = openar(arname, ORDWR, 1);
  215. if (fd >= 0) {
  216. Binit(&bar, fd, OREAD);
  217. Bseek(&bar,seek(fd,0,1), 1);
  218. }
  219. astart = newtempfile(artemp);
  220. ap = astart;
  221. aend = 0;
  222. for(i = 0; fd >= 0; i++) {
  223. bp = getdir(&bar);
  224. if (!bp)
  225. break;
  226. if (bamatch(file, poname)) { /* check for pivot */
  227. aend = newtempfile(tailtemp);
  228. ap = aend;
  229. }
  230. /* pitch symdef file */
  231. if (i == 0 && strcmp(file, symdef) == 0) {
  232. skip(&bar, bp->size);
  233. continue;
  234. }
  235. if (count && !match(count, files)) {
  236. scanobj(&bar, ap, bp->size);
  237. arcopy(&bar, ap, bp);
  238. continue;
  239. }
  240. bfile = Bopen(file, OREAD);
  241. if (!bfile) {
  242. if (count != 0)
  243. fprint(2, "ar: cannot open %s\n", file);
  244. scanobj(&bar, ap, bp->size);
  245. arcopy(&bar, ap, bp);
  246. continue;
  247. }
  248. d = dirfstat(Bfildes(bfile));
  249. if(d == nil)
  250. fprint(2, "ar: cannot stat %s: %r\n", file);
  251. if (uflag && (d==nil || d->mtime <= bp->date)) {
  252. scanobj(&bar, ap, bp->size);
  253. arcopy(&bar, ap, bp);
  254. Bterm(bfile);
  255. free(d);
  256. continue;
  257. }
  258. mesg('r', file);
  259. skip(&bar, bp->size);
  260. scanobj(bfile, ap, d->length);
  261. free(d);
  262. armove(bfile, ap, bp);
  263. Bterm(bfile);
  264. }
  265. if(fd >= 0)
  266. close(fd);
  267. /* copy in remaining files named on command line */
  268. for (i = 0; i < count; i++) {
  269. file = files[i];
  270. if(file == 0)
  271. continue;
  272. files[i] = 0;
  273. bfile = Bopen(file, OREAD);
  274. if (!bfile)
  275. fprint(2, "ar: %s cannot open\n", file);
  276. else {
  277. mesg('a', file);
  278. d = dirfstat(Bfildes(bfile));
  279. if (d == nil)
  280. fprint(2, "can't stat %s\n", file);
  281. else {
  282. scanobj(bfile, astart, d->length);
  283. armove(bfile, astart, newmember());
  284. free(d);
  285. }
  286. Bterm(bfile);
  287. }
  288. }
  289. if(fd < 0 && !cflag)
  290. install(arname, astart, 0, aend, 1); /* issue 'creating' msg */
  291. else
  292. install(arname, astart, 0, aend, 0);
  293. }
  294. void
  295. dcmd(char *arname, int count, char **files)
  296. {
  297. Armember *bp;
  298. int fd, i;
  299. if (!count)
  300. return;
  301. fd = openar(arname, ORDWR, 0);
  302. Binit(&bar, fd, OREAD);
  303. Bseek(&bar,seek(fd,0,1), 1);
  304. astart = newtempfile(artemp);
  305. for (i = 0; bp = getdir(&bar); i++) {
  306. if(match(count, files)) {
  307. mesg('d', file);
  308. skip(&bar, bp->size);
  309. if (strcmp(file, symdef) == 0)
  310. allobj = 0;
  311. } else if (i == 0 && strcmp(file, symdef) == 0)
  312. skip(&bar, bp->size);
  313. else {
  314. scanobj(&bar, astart, bp->size);
  315. arcopy(&bar, astart, bp);
  316. }
  317. }
  318. close(fd);
  319. install(arname, astart, 0, 0, 0);
  320. }
  321. void
  322. xcmd(char *arname, int count, char **files)
  323. {
  324. int fd, f, mode, i;
  325. Armember *bp;
  326. Dir dx;
  327. fd = openar(arname, OREAD, 0);
  328. Binit(&bar, fd, OREAD);
  329. Bseek(&bar,seek(fd,0,1), 1);
  330. i = 0;
  331. while (bp = getdir(&bar)) {
  332. if(count == 0 || match(count, files)) {
  333. mode = strtoul(bp->hdr.mode, 0, 8) & 0777;
  334. f = create(file, OWRITE, mode);
  335. if(f < 0) {
  336. fprint(2, "ar: %s cannot create\n", file);
  337. skip(&bar, bp->size);
  338. } else {
  339. mesg('x', file);
  340. arcopy(&bar, 0, bp);
  341. if (write(f, bp->member, bp->size) < 0)
  342. wrerr();
  343. if(oflag) {
  344. nulldir(&dx);
  345. dx.atime = bp->date;
  346. dx.mtime = bp->date;
  347. if(dirwstat(file, &dx) < 0)
  348. perror(file);
  349. }
  350. free(bp->member);
  351. close(f);
  352. }
  353. free(bp);
  354. if (count && ++i >= count)
  355. break;
  356. } else {
  357. skip(&bar, bp->size);
  358. free(bp);
  359. }
  360. }
  361. close(fd);
  362. }
  363. void
  364. pcmd(char *arname, int count, char **files)
  365. {
  366. int fd;
  367. Armember *bp;
  368. fd = openar(arname, OREAD, 0);
  369. Binit(&bar, fd, OREAD);
  370. Bseek(&bar,seek(fd,0,1), 1);
  371. while(bp = getdir(&bar)) {
  372. if(count == 0 || match(count, files)) {
  373. if(vflag)
  374. print("\n<%s>\n\n", file);
  375. arcopy(&bar, 0, bp);
  376. if (write(1, bp->member, bp->size) < 0)
  377. wrerr();
  378. } else
  379. skip(&bar, bp->size);
  380. free(bp);
  381. }
  382. close(fd);
  383. }
  384. void
  385. mcmd(char *arname, int count, char **files)
  386. {
  387. int fd, i;
  388. Arfile *ap;
  389. Armember *bp;
  390. if (count == 0)
  391. return;
  392. fd = openar(arname, ORDWR, 0);
  393. Binit(&bar, fd, OREAD);
  394. Bseek(&bar,seek(fd,0,1), 1);
  395. astart = newtempfile(artemp);
  396. amiddle = newtempfile(movtemp);
  397. aend = 0;
  398. ap = astart;
  399. for (i = 0; bp = getdir(&bar); i++) {
  400. if (bamatch(file, poname)) {
  401. aend = newtempfile(tailtemp);
  402. ap = aend;
  403. }
  404. if(match(count, files)) {
  405. mesg('m', file);
  406. scanobj(&bar, amiddle, bp->size);
  407. arcopy(&bar, amiddle, bp);
  408. } else
  409. /*
  410. * pitch the symdef file if it is at the beginning
  411. * of the archive and we aren't inserting in front
  412. * of it (ap == astart).
  413. */
  414. if (ap == astart && i == 0 && strcmp(file, symdef) == 0)
  415. skip(&bar, bp->size);
  416. else {
  417. scanobj(&bar, ap, bp->size);
  418. arcopy(&bar, ap, bp);
  419. }
  420. }
  421. close(fd);
  422. if (poname[0] && aend == 0)
  423. fprint(2, "ar: %s not found - files moved to end.\n", poname);
  424. install(arname, astart, amiddle, aend, 0);
  425. }
  426. void
  427. tcmd(char *arname, int count, char **files)
  428. {
  429. int fd;
  430. Armember *bp;
  431. char name[ARNAMESIZE+1];
  432. fd = openar(arname, OREAD, 0);
  433. Binit(&bar, fd, OREAD);
  434. Bseek(&bar,seek(fd,0,1), 1);
  435. while(bp = getdir(&bar)) {
  436. if(count == 0 || match(count, files)) {
  437. if(vflag)
  438. longt(bp);
  439. trim(file, name, ARNAMESIZE);
  440. Bprint(&bout, "%s\n", name);
  441. }
  442. skip(&bar, bp->size);
  443. free(bp);
  444. }
  445. close(fd);
  446. }
  447. void
  448. qcmd(char *arname, int count, char **files)
  449. {
  450. int fd, i;
  451. Armember *bp;
  452. Biobuf *bfile;
  453. if(aflag || bflag) {
  454. fprint(2, "ar: abi not allowed with q\n");
  455. exits("error");
  456. }
  457. fd = openar(arname, ORDWR, 1);
  458. if (fd < 0) {
  459. if(!cflag)
  460. fprint(2, "ar: creating %s\n", arname);
  461. fd = arcreate(arname);
  462. }
  463. Binit(&bar, fd, OREAD);
  464. Bseek(&bar,seek(fd,0,1), 1);
  465. /* leave note group behind when writing archive; i.e. sidestep interrupts */
  466. rfork(RFNOTEG);
  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. d = dirfstat(Bfildes(b));
  679. if (d == nil) {
  680. fprint(2, "ar: cannot stat %s\n", file);
  681. return;
  682. }
  683. trim(file, bp->hdr.name, sizeof(bp->hdr.name));
  684. for (cp = strchr(bp->hdr.name, 0); /* blank pad on right */
  685. cp < bp->hdr.name+sizeof(bp->hdr.name); cp++)
  686. *cp = ' ';
  687. sprint(bp->hdr.date, "%-12ld", d->mtime);
  688. sprint(bp->hdr.uid, "%-6d", 0);
  689. sprint(bp->hdr.gid, "%-6d", 0);
  690. sprint(bp->hdr.mode, "%-8lo", d->mode);
  691. sprint(bp->hdr.size, "%-10lld", d->length);
  692. strncpy(bp->hdr.fmag, ARFMAG, 2);
  693. bp->size = d->length;
  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. /* leave note group behind when copying back; i.e. sidestep interrupts */
  741. rfork(RFNOTEG);
  742. if(createflag)
  743. fprint(2, "ar: creating %s\n", arname);
  744. fd = arcreate(arname);
  745. if(allobj)
  746. rl(fd);
  747. if (astart) {
  748. arstream(fd, astart);
  749. arfree(astart);
  750. }
  751. if (amiddle) {
  752. arstream(fd, amiddle);
  753. arfree(amiddle);
  754. }
  755. if (aend) {
  756. arstream(fd, aend);
  757. arfree(aend);
  758. }
  759. close(fd);
  760. }
  761. void
  762. rl(int fd)
  763. {
  764. Biobuf b;
  765. char *cp;
  766. struct ar_hdr a;
  767. long len;
  768. Binit(&b, fd, OWRITE);
  769. Bseek(&b,seek(fd,0,1), 0);
  770. len = symdefsize;
  771. if(len&01)
  772. len++;
  773. sprint(a.date, "%-12ld", time(0));
  774. sprint(a.uid, "%-6d", 0);
  775. sprint(a.gid, "%-6d", 0);
  776. sprint(a.mode, "%-8lo", 0644L);
  777. sprint(a.size, "%-10ld", len);
  778. strncpy(a.fmag, ARFMAG, 2);
  779. strcpy(a.name, symdef);
  780. for (cp = strchr(a.name, 0); /* blank pad on right */
  781. cp < a.name+sizeof(a.name); cp++)
  782. *cp = ' ';
  783. if(HEADER_IO(Bwrite, &b, a))
  784. wrerr();
  785. len += Boffset(&b);
  786. if (astart) {
  787. wrsym(&b, len, astart->sym);
  788. len += astart->size;
  789. }
  790. if(amiddle) {
  791. wrsym(&b, len, amiddle->sym);
  792. len += amiddle->size;
  793. }
  794. if(aend)
  795. wrsym(&b, len, aend->sym);
  796. if(symdefsize&0x01)
  797. Bputc(&b, 0);
  798. Bterm(&b);
  799. }
  800. /*
  801. * Write the defined symbols to the symdef file
  802. */
  803. void
  804. wrsym(Biobuf *bp, int offset, Arsymref *as)
  805. {
  806. int off;
  807. while(as) {
  808. Bputc(bp, as->type);
  809. off = as->offset+offset;
  810. Bputc(bp, off);
  811. Bputc(bp, off>>8);
  812. Bputc(bp, off>>16);
  813. Bputc(bp, off>>24);
  814. if (Bwrite(bp, as->name, as->len+1) != as->len+1)
  815. wrerr();
  816. as = as->next;
  817. }
  818. }
  819. /*
  820. * Check if the archive member matches an entry on the command line.
  821. */
  822. int
  823. match(int count, char **files)
  824. {
  825. int i;
  826. char name[ARNAMESIZE+1];
  827. for(i=0; i<count; i++) {
  828. if(files[i] == 0)
  829. continue;
  830. trim(files[i], name, ARNAMESIZE);
  831. if(strncmp(name, file, ARNAMESIZE) == 0) {
  832. file = files[i];
  833. files[i] = 0;
  834. return 1;
  835. }
  836. }
  837. return 0;
  838. }
  839. /*
  840. * compare the current member to the name of the pivot member
  841. */
  842. int
  843. bamatch(char *file, char *pivot)
  844. {
  845. static int state = 0;
  846. switch(state)
  847. {
  848. case 0: /* looking for position file */
  849. if (aflag) {
  850. if (strncmp(file, pivot, ARNAMESIZE) == 0)
  851. state = 1;
  852. } else if (bflag) {
  853. if (strncmp(file, pivot, ARNAMESIZE) == 0) {
  854. state = 2; /* found */
  855. return 1;
  856. }
  857. }
  858. break;
  859. case 1: /* found - after previous file */
  860. state = 2;
  861. return 1;
  862. case 2: /* already found position file */
  863. break;
  864. }
  865. return 0;
  866. }
  867. /*
  868. * output a message, if 'v' option was specified
  869. */
  870. void
  871. mesg(int c, char *file)
  872. {
  873. if(vflag)
  874. Bprint(&bout, "%c - %s\n", c, file);
  875. }
  876. /*
  877. * isolate file name by stripping leading directories and trailing slashes
  878. */
  879. void
  880. trim(char *s, char *buf, int n)
  881. {
  882. char *p;
  883. for(;;) {
  884. p = strrchr(s, '/');
  885. if (!p) { /* no slash in name */
  886. strncpy(buf, s, n);
  887. return;
  888. }
  889. if (p[1] != 0) { /* p+1 is first char of file name */
  890. strncpy(buf, p+1, n);
  891. return;
  892. }
  893. *p = 0; /* strip trailing slash */
  894. }
  895. }
  896. /*
  897. * utilities for printing long form of 't' command
  898. */
  899. #define SUID 04000
  900. #define SGID 02000
  901. #define ROWN 0400
  902. #define WOWN 0200
  903. #define XOWN 0100
  904. #define RGRP 040
  905. #define WGRP 020
  906. #define XGRP 010
  907. #define ROTH 04
  908. #define WOTH 02
  909. #define XOTH 01
  910. #define STXT 01000
  911. void
  912. longt(Armember *bp)
  913. {
  914. char *cp;
  915. pmode(strtoul(bp->hdr.mode, 0, 8));
  916. Bprint(&bout, "%3ld/%1ld", atol(bp->hdr.uid), atol(bp->hdr.gid));
  917. Bprint(&bout, "%7ld", bp->size);
  918. cp = ctime(bp->date);
  919. Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24);
  920. }
  921. int m1[] = { 1, ROWN, 'r', '-' };
  922. int m2[] = { 1, WOWN, 'w', '-' };
  923. int m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
  924. int m4[] = { 1, RGRP, 'r', '-' };
  925. int m5[] = { 1, WGRP, 'w', '-' };
  926. int m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
  927. int m7[] = { 1, ROTH, 'r', '-' };
  928. int m8[] = { 1, WOTH, 'w', '-' };
  929. int m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
  930. int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
  931. void
  932. pmode(long mode)
  933. {
  934. int **mp;
  935. for(mp = &m[0]; mp < &m[9];)
  936. select(*mp++, mode);
  937. }
  938. void
  939. select(int *ap, long mode)
  940. {
  941. int n;
  942. n = *ap++;
  943. while(--n>=0 && (mode&*ap++)==0)
  944. ap++;
  945. Bputc(&bout, *ap);
  946. }
  947. /*
  948. * Temp file I/O subsystem. We attempt to cache all three temp files in
  949. * core. When we run out of memory we spill to disk.
  950. * The I/O model assumes that temp files:
  951. * 1) are only written on the end
  952. * 2) are only read from the beginning
  953. * 3) are only read after all writing is complete.
  954. * The architecture uses one control block per temp file. Each control
  955. * block anchors a chain of buffers, each containing an archive member.
  956. */
  957. Arfile *
  958. newtempfile(char *name) /* allocate a file control block */
  959. {
  960. Arfile *ap;
  961. ap = (Arfile *) armalloc(sizeof(Arfile));
  962. ap->fname = name;
  963. return ap;
  964. }
  965. Armember *
  966. newmember(void) /* allocate a member buffer */
  967. {
  968. return (Armember *)armalloc(sizeof(Armember));
  969. }
  970. void
  971. arread(Biobuf *b, Armember *bp, int n) /* read an image into a member buffer */
  972. {
  973. int i;
  974. bp->member = armalloc(n);
  975. i = Bread(b, bp->member, n);
  976. if (i < 0) {
  977. free(bp->member);
  978. bp->member = 0;
  979. rderr();
  980. }
  981. }
  982. /*
  983. * insert a member buffer into the member chain
  984. */
  985. void
  986. arinsert(Arfile *ap, Armember *bp)
  987. {
  988. bp->next = 0;
  989. if (!ap->tail)
  990. ap->head = bp;
  991. else
  992. ap->tail->next = bp;
  993. ap->tail = bp;
  994. }
  995. /*
  996. * stream the members in a temp file to the file referenced by 'fd'.
  997. */
  998. void
  999. arstream(int fd, Arfile *ap)
  1000. {
  1001. Armember *bp;
  1002. int i;
  1003. char buf[8192];
  1004. if (ap->paged) { /* copy from disk */
  1005. seek(ap->fd, 0, 0);
  1006. for (;;) {
  1007. i = read(ap->fd, buf, sizeof(buf));
  1008. if (i < 0)
  1009. rderr();
  1010. if (i == 0)
  1011. break;
  1012. if (write(fd, buf, i) != i)
  1013. wrerr();
  1014. }
  1015. close(ap->fd);
  1016. ap->paged = 0;
  1017. }
  1018. /* dump the in-core buffers */
  1019. for (bp = ap->head; bp; bp = bp->next) {
  1020. if (!arwrite(fd, bp))
  1021. wrerr();
  1022. }
  1023. }
  1024. /*
  1025. * write a member to 'fd'.
  1026. */
  1027. int
  1028. arwrite(int fd, Armember *bp)
  1029. {
  1030. int len;
  1031. if(HEADER_IO(write, fd, bp->hdr))
  1032. return 0;
  1033. len = bp->size;
  1034. if (len & 01)
  1035. len++;
  1036. if (write(fd, bp->member, len) != len)
  1037. return 0;
  1038. return 1;
  1039. }
  1040. /*
  1041. * Spill a member to a disk copy of a temp file
  1042. */
  1043. int
  1044. page(Arfile *ap)
  1045. {
  1046. Armember *bp;
  1047. bp = ap->head;
  1048. if (!ap->paged) { /* not yet paged - create file */
  1049. ap->fname = mktemp(ap->fname);
  1050. ap->fd = create(ap->fname, ORDWR|ORCLOSE, 0600);
  1051. if (ap->fd < 0) {
  1052. fprint(2,"ar: can't create temp file\n");
  1053. return 0;
  1054. }
  1055. ap->paged = 1;
  1056. }
  1057. if (!arwrite(ap->fd, bp)) /* write member and free buffer block */
  1058. return 0;
  1059. ap->head = bp->next;
  1060. if (ap->tail == bp)
  1061. ap->tail = bp->next;
  1062. free(bp->member);
  1063. free(bp);
  1064. return 1;
  1065. }
  1066. /*
  1067. * try to reclaim space by paging. we try to spill the start, middle,
  1068. * and end files, in that order. there is no particular reason for the
  1069. * ordering.
  1070. */
  1071. int
  1072. getspace(void)
  1073. {
  1074. if (astart && astart->head && page(astart))
  1075. return 1;
  1076. if (amiddle && amiddle->head && page(amiddle))
  1077. return 1;
  1078. if (aend && aend->head && page(aend))
  1079. return 1;
  1080. return 0;
  1081. }
  1082. void
  1083. arfree(Arfile *ap) /* free a member buffer */
  1084. {
  1085. Armember *bp, *next;
  1086. for (bp = ap->head; bp; bp = next) {
  1087. next = bp->next;
  1088. if (bp->member)
  1089. free(bp->member);
  1090. free(bp);
  1091. }
  1092. free(ap);
  1093. }
  1094. /*
  1095. * allocate space for a control block or member buffer. if the malloc
  1096. * fails we try to reclaim space by spilling previously allocated
  1097. * member buffers.
  1098. */
  1099. char *
  1100. armalloc(int n)
  1101. {
  1102. char *cp;
  1103. do {
  1104. cp = malloc(n);
  1105. if (cp) {
  1106. memset(cp, 0, n);
  1107. return cp;
  1108. }
  1109. } while (getspace());
  1110. fprint(2, "ar: out of memory\n");
  1111. exits("malloc");
  1112. return 0;
  1113. }