ar.c 23 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210
  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. vlong 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. vlong 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*, long);
  109. void select(int*, long);
  110. void setcom(void(*)(char*, int, char**));
  111. void skip(Biobuf*, vlong);
  112. int symcomp(void*, void*);
  113. void trim(char*, char*, int);
  114. void usage(void);
  115. void wrerr(void);
  116. void wrsym(Biobuf*, long, 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, long size)
  493. {
  494. int obj;
  495. vlong 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)) != 0)
  659. phaseerr(Boffset(b));
  660. strncpy(name, bp->hdr.name, sizeof(bp->hdr.name));
  661. cp = name+sizeof(name)-1;
  662. *cp = '\0';
  663. /* skip trailing spaces and (gnu-produced) slashes */
  664. while(*--cp == ' ' || *cp == '/')
  665. ;
  666. cp[1] = '\0';
  667. file = name;
  668. bp->date = strtol(bp->hdr.date, 0, 0);
  669. bp->size = strtol(bp->hdr.size, 0, 0);
  670. return bp;
  671. }
  672. /*
  673. * Copy the file referenced by fd to the temp file
  674. */
  675. void
  676. armove(Biobuf *b, Arfile *ap, Armember *bp)
  677. {
  678. char *cp;
  679. Dir *d;
  680. d = dirfstat(Bfildes(b));
  681. if (d == nil) {
  682. fprint(2, "ar: cannot stat %s\n", file);
  683. return;
  684. }
  685. trim(file, bp->hdr.name, sizeof(bp->hdr.name));
  686. for (cp = strchr(bp->hdr.name, 0); /* blank pad on right */
  687. cp < bp->hdr.name+sizeof(bp->hdr.name); cp++)
  688. *cp = ' ';
  689. sprint(bp->hdr.date, "%-12ld", d->mtime);
  690. sprint(bp->hdr.uid, "%-6d", 0);
  691. sprint(bp->hdr.gid, "%-6d", 0);
  692. sprint(bp->hdr.mode, "%-8lo", d->mode);
  693. sprint(bp->hdr.size, "%-10lld", d->length);
  694. strncpy(bp->hdr.fmag, ARFMAG, 2);
  695. bp->size = d->length;
  696. arread(b, bp, bp->size);
  697. if (d->length&0x01)
  698. d->length++;
  699. if (ap) {
  700. arinsert(ap, bp);
  701. ap->size += d->length+SAR_HDR;
  702. }
  703. free(d);
  704. }
  705. /*
  706. * Copy the archive member at the current offset into the temp file.
  707. */
  708. void
  709. arcopy(Biobuf *b, Arfile *ap, Armember *bp)
  710. {
  711. long n;
  712. n = bp->size;
  713. if (n & 01)
  714. n++;
  715. arread(b, bp, n);
  716. if (ap) {
  717. arinsert(ap, bp);
  718. ap->size += n+SAR_HDR;
  719. }
  720. }
  721. /*
  722. * Skip an archive member
  723. */
  724. void
  725. skip(Biobuf *bp, vlong len)
  726. {
  727. if (len & 01)
  728. len++;
  729. Bseek(bp, len, 1);
  730. }
  731. /*
  732. * Stream the three temp files to an archive
  733. */
  734. void
  735. install(char *arname, Arfile *astart, Arfile *amiddle, Arfile *aend, int createflag)
  736. {
  737. int fd;
  738. if(allobj && dupfound) {
  739. fprint(2, "%s not changed\n", arname);
  740. return;
  741. }
  742. /* leave note group behind when copying back; i.e. sidestep interrupts */
  743. rfork(RFNOTEG);
  744. if(createflag)
  745. fprint(2, "ar: creating %s\n", arname);
  746. fd = arcreate(arname);
  747. if(allobj)
  748. rl(fd);
  749. if (astart) {
  750. arstream(fd, astart);
  751. arfree(astart);
  752. }
  753. if (amiddle) {
  754. arstream(fd, amiddle);
  755. arfree(amiddle);
  756. }
  757. if (aend) {
  758. arstream(fd, aend);
  759. arfree(aend);
  760. }
  761. close(fd);
  762. }
  763. void
  764. rl(int fd)
  765. {
  766. Biobuf b;
  767. char *cp;
  768. struct ar_hdr a;
  769. long len;
  770. Binit(&b, fd, OWRITE);
  771. Bseek(&b,seek(fd,0,1), 0);
  772. len = symdefsize;
  773. if(len&01)
  774. len++;
  775. sprint(a.date, "%-12ld", time(0));
  776. sprint(a.uid, "%-6d", 0);
  777. sprint(a.gid, "%-6d", 0);
  778. sprint(a.mode, "%-8lo", 0644L);
  779. sprint(a.size, "%-10ld", len);
  780. strncpy(a.fmag, ARFMAG, 2);
  781. strcpy(a.name, symdef);
  782. for (cp = strchr(a.name, 0); /* blank pad on right */
  783. cp < a.name+sizeof(a.name); cp++)
  784. *cp = ' ';
  785. if(HEADER_IO(Bwrite, &b, a))
  786. wrerr();
  787. len += Boffset(&b);
  788. if (astart) {
  789. wrsym(&b, len, astart->sym);
  790. len += astart->size;
  791. }
  792. if(amiddle) {
  793. wrsym(&b, len, amiddle->sym);
  794. len += amiddle->size;
  795. }
  796. if(aend)
  797. wrsym(&b, len, aend->sym);
  798. if(symdefsize&0x01)
  799. Bputc(&b, 0);
  800. Bterm(&b);
  801. }
  802. /*
  803. * Write the defined symbols to the symdef file
  804. */
  805. void
  806. wrsym(Biobuf *bp, long offset, Arsymref *as)
  807. {
  808. int off;
  809. while(as) {
  810. Bputc(bp, as->type);
  811. off = as->offset+offset;
  812. Bputc(bp, off);
  813. Bputc(bp, off>>8);
  814. Bputc(bp, off>>16);
  815. Bputc(bp, off>>24);
  816. if (Bwrite(bp, as->name, as->len+1) != as->len+1)
  817. wrerr();
  818. as = as->next;
  819. }
  820. }
  821. /*
  822. * Check if the archive member matches an entry on the command line.
  823. */
  824. int
  825. match(int count, char **files)
  826. {
  827. int i;
  828. char name[ARNAMESIZE+1];
  829. for(i=0; i<count; i++) {
  830. if(files[i] == 0)
  831. continue;
  832. trim(files[i], name, ARNAMESIZE);
  833. if(strncmp(name, file, ARNAMESIZE) == 0) {
  834. file = files[i];
  835. files[i] = 0;
  836. return 1;
  837. }
  838. }
  839. return 0;
  840. }
  841. /*
  842. * compare the current member to the name of the pivot member
  843. */
  844. int
  845. bamatch(char *file, char *pivot)
  846. {
  847. static int state = 0;
  848. switch(state)
  849. {
  850. case 0: /* looking for position file */
  851. if (aflag) {
  852. if (strncmp(file, pivot, ARNAMESIZE) == 0)
  853. state = 1;
  854. } else if (bflag) {
  855. if (strncmp(file, pivot, ARNAMESIZE) == 0) {
  856. state = 2; /* found */
  857. return 1;
  858. }
  859. }
  860. break;
  861. case 1: /* found - after previous file */
  862. state = 2;
  863. return 1;
  864. case 2: /* already found position file */
  865. break;
  866. }
  867. return 0;
  868. }
  869. /*
  870. * output a message, if 'v' option was specified
  871. */
  872. void
  873. mesg(int c, char *file)
  874. {
  875. if(vflag)
  876. Bprint(&bout, "%c - %s\n", c, file);
  877. }
  878. /*
  879. * isolate file name by stripping leading directories and trailing slashes
  880. */
  881. void
  882. trim(char *s, char *buf, int n)
  883. {
  884. char *p;
  885. for(;;) {
  886. p = strrchr(s, '/');
  887. if (!p) { /* no slash in name */
  888. strncpy(buf, s, n);
  889. return;
  890. }
  891. if (p[1] != 0) { /* p+1 is first char of file name */
  892. strncpy(buf, p+1, n);
  893. return;
  894. }
  895. *p = 0; /* strip trailing slash */
  896. }
  897. }
  898. /*
  899. * utilities for printing long form of 't' command
  900. */
  901. #define SUID 04000
  902. #define SGID 02000
  903. #define ROWN 0400
  904. #define WOWN 0200
  905. #define XOWN 0100
  906. #define RGRP 040
  907. #define WGRP 020
  908. #define XGRP 010
  909. #define ROTH 04
  910. #define WOTH 02
  911. #define XOTH 01
  912. #define STXT 01000
  913. void
  914. longt(Armember *bp)
  915. {
  916. char *cp;
  917. pmode(strtoul(bp->hdr.mode, 0, 8));
  918. Bprint(&bout, "%3ld/%1ld", strtol(bp->hdr.uid, 0, 0), strtol(bp->hdr.gid, 0, 0));
  919. Bprint(&bout, "%7ld", bp->size);
  920. cp = ctime(bp->date);
  921. Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24);
  922. }
  923. int m1[] = { 1, ROWN, 'r', '-' };
  924. int m2[] = { 1, WOWN, 'w', '-' };
  925. int m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
  926. int m4[] = { 1, RGRP, 'r', '-' };
  927. int m5[] = { 1, WGRP, 'w', '-' };
  928. int m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
  929. int m7[] = { 1, ROTH, 'r', '-' };
  930. int m8[] = { 1, WOTH, 'w', '-' };
  931. int m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
  932. int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
  933. void
  934. pmode(long mode)
  935. {
  936. int **mp;
  937. for(mp = &m[0]; mp < &m[9];)
  938. select(*mp++, mode);
  939. }
  940. void
  941. select(int *ap, long mode)
  942. {
  943. int n;
  944. n = *ap++;
  945. while(--n>=0 && (mode&*ap++)==0)
  946. ap++;
  947. Bputc(&bout, *ap);
  948. }
  949. /*
  950. * Temp file I/O subsystem. We attempt to cache all three temp files in
  951. * core. When we run out of memory we spill to disk.
  952. * The I/O model assumes that temp files:
  953. * 1) are only written on the end
  954. * 2) are only read from the beginning
  955. * 3) are only read after all writing is complete.
  956. * The architecture uses one control block per temp file. Each control
  957. * block anchors a chain of buffers, each containing an archive member.
  958. */
  959. Arfile *
  960. newtempfile(char *name) /* allocate a file control block */
  961. {
  962. Arfile *ap;
  963. ap = (Arfile *) armalloc(sizeof(Arfile));
  964. ap->fname = name;
  965. return ap;
  966. }
  967. Armember *
  968. newmember(void) /* allocate a member buffer */
  969. {
  970. return (Armember *)armalloc(sizeof(Armember));
  971. }
  972. void
  973. arread(Biobuf *b, Armember *bp, int n) /* read an image into a member buffer */
  974. {
  975. int i;
  976. bp->member = armalloc(n);
  977. i = Bread(b, bp->member, n);
  978. if (i < 0) {
  979. free(bp->member);
  980. bp->member = 0;
  981. rderr();
  982. }
  983. }
  984. /*
  985. * insert a member buffer into the member chain
  986. */
  987. void
  988. arinsert(Arfile *ap, Armember *bp)
  989. {
  990. bp->next = 0;
  991. if (!ap->tail)
  992. ap->head = bp;
  993. else
  994. ap->tail->next = bp;
  995. ap->tail = bp;
  996. }
  997. /*
  998. * stream the members in a temp file to the file referenced by 'fd'.
  999. */
  1000. void
  1001. arstream(int fd, Arfile *ap)
  1002. {
  1003. Armember *bp;
  1004. int i;
  1005. char buf[8192];
  1006. if (ap->paged) { /* copy from disk */
  1007. seek(ap->fd, 0, 0);
  1008. for (;;) {
  1009. i = read(ap->fd, buf, sizeof(buf));
  1010. if (i < 0)
  1011. rderr();
  1012. if (i == 0)
  1013. break;
  1014. if (write(fd, buf, i) != i)
  1015. wrerr();
  1016. }
  1017. close(ap->fd);
  1018. ap->paged = 0;
  1019. }
  1020. /* dump the in-core buffers */
  1021. for (bp = ap->head; bp; bp = bp->next) {
  1022. if (!arwrite(fd, bp))
  1023. wrerr();
  1024. }
  1025. }
  1026. /*
  1027. * write a member to 'fd'.
  1028. */
  1029. int
  1030. arwrite(int fd, Armember *bp)
  1031. {
  1032. int len;
  1033. if(HEADER_IO(write, fd, bp->hdr))
  1034. return 0;
  1035. len = bp->size;
  1036. if (len & 01)
  1037. len++;
  1038. if (write(fd, bp->member, len) != len)
  1039. return 0;
  1040. return 1;
  1041. }
  1042. /*
  1043. * Spill a member to a disk copy of a temp file
  1044. */
  1045. int
  1046. page(Arfile *ap)
  1047. {
  1048. Armember *bp;
  1049. bp = ap->head;
  1050. if (!ap->paged) { /* not yet paged - create file */
  1051. ap->fname = mktemp(ap->fname);
  1052. ap->fd = create(ap->fname, ORDWR|ORCLOSE, 0600);
  1053. if (ap->fd < 0) {
  1054. fprint(2,"ar: can't create temp file\n");
  1055. return 0;
  1056. }
  1057. ap->paged = 1;
  1058. }
  1059. if (!arwrite(ap->fd, bp)) /* write member and free buffer block */
  1060. return 0;
  1061. ap->head = bp->next;
  1062. if (ap->tail == bp)
  1063. ap->tail = bp->next;
  1064. free(bp->member);
  1065. free(bp);
  1066. return 1;
  1067. }
  1068. /*
  1069. * try to reclaim space by paging. we try to spill the start, middle,
  1070. * and end files, in that order. there is no particular reason for the
  1071. * ordering.
  1072. */
  1073. int
  1074. getspace(void)
  1075. {
  1076. if (astart && astart->head && page(astart))
  1077. return 1;
  1078. if (amiddle && amiddle->head && page(amiddle))
  1079. return 1;
  1080. if (aend && aend->head && page(aend))
  1081. return 1;
  1082. return 0;
  1083. }
  1084. void
  1085. arfree(Arfile *ap) /* free a member buffer */
  1086. {
  1087. Armember *bp, *next;
  1088. for (bp = ap->head; bp; bp = next) {
  1089. next = bp->next;
  1090. if (bp->member)
  1091. free(bp->member);
  1092. free(bp);
  1093. }
  1094. free(ap);
  1095. }
  1096. /*
  1097. * allocate space for a control block or member buffer. if the malloc
  1098. * fails we try to reclaim space by spilling previously allocated
  1099. * member buffers.
  1100. */
  1101. char *
  1102. armalloc(int n)
  1103. {
  1104. char *cp;
  1105. do {
  1106. cp = malloc(n);
  1107. if (cp) {
  1108. memset(cp, 0, n);
  1109. return cp;
  1110. }
  1111. } while (getspace());
  1112. fprint(2, "ar: out of memory\n");
  1113. exits("malloc");
  1114. return 0;
  1115. }