ar.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194
  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. dx = dirfstat(f);
  345. if(dx == nil)
  346. perror(file);
  347. else {
  348. dx->atime = bp->date;
  349. dx->mtime = bp->date;
  350. if(dirwstat(file, dx) < 0)
  351. perror(file);
  352. free(dx);
  353. }
  354. }
  355. free(bp->member);
  356. close(f);
  357. }
  358. free(bp);
  359. if (count && ++i >= count)
  360. break;
  361. } else {
  362. skip(&bar, bp->size);
  363. free(bp);
  364. }
  365. }
  366. close(fd);
  367. }
  368. void
  369. pcmd(char *arname, int count, char **files)
  370. {
  371. int fd;
  372. Armember *bp;
  373. fd = openar(arname, OREAD, 0);
  374. Binit(&bar, fd, OREAD);
  375. Bseek(&bar,seek(fd,0,1), 1);
  376. while(bp = getdir(&bar)) {
  377. if(count == 0 || match(count, files)) {
  378. if(vflag)
  379. print("\n<%s>\n\n", file);
  380. arcopy(&bar, 0, bp);
  381. if (write(1, bp->member, bp->size) < 0)
  382. wrerr();
  383. } else
  384. skip(&bar, bp->size);
  385. free(bp);
  386. }
  387. close(fd);
  388. }
  389. void
  390. mcmd(char *arname, int count, char **files)
  391. {
  392. int fd, i;
  393. Arfile *ap;
  394. Armember *bp;
  395. if (count == 0)
  396. return;
  397. fd = openar(arname, ORDWR, 0);
  398. Binit(&bar, fd, OREAD);
  399. Bseek(&bar,seek(fd,0,1), 1);
  400. astart = newtempfile(artemp);
  401. amiddle = newtempfile(movtemp);
  402. aend = 0;
  403. ap = astart;
  404. for (i = 0; bp = getdir(&bar); i++) {
  405. if (bamatch(file, poname)) {
  406. aend = newtempfile(tailtemp);
  407. ap = aend;
  408. }
  409. if(match(count, files)) {
  410. mesg('m', file);
  411. scanobj(&bar, amiddle, bp->size);
  412. arcopy(&bar, amiddle, bp);
  413. } else
  414. /*
  415. * pitch the symdef file if it is at the beginning
  416. * of the archive and we aren't inserting in front
  417. * of it (ap == astart).
  418. */
  419. if (ap == astart && i == 0 && strcmp(file, symdef) == 0)
  420. skip(&bar, bp->size);
  421. else {
  422. scanobj(&bar, ap, bp->size);
  423. arcopy(&bar, ap, bp);
  424. }
  425. }
  426. close(fd);
  427. if (poname[0] && aend == 0)
  428. fprint(2, "ar: %s not found - files moved to end.\n", poname);
  429. install(arname, astart, amiddle, aend, 0);
  430. }
  431. void
  432. tcmd(char *arname, int count, char **files)
  433. {
  434. int fd;
  435. Armember *bp;
  436. char name[ARNAMESIZE+1];
  437. fd = openar(arname, OREAD, 0);
  438. Binit(&bar, fd, OREAD);
  439. Bseek(&bar,seek(fd,0,1), 1);
  440. while(bp = getdir(&bar)) {
  441. if(count == 0 || match(count, files)) {
  442. if(vflag)
  443. longt(bp);
  444. trim(file, name, ARNAMESIZE);
  445. Bprint(&bout, "%s\n", name);
  446. }
  447. skip(&bar, bp->size);
  448. free(bp);
  449. }
  450. close(fd);
  451. }
  452. void
  453. qcmd(char *arname, int count, char **files)
  454. {
  455. int fd, i;
  456. Armember *bp;
  457. Biobuf *bfile;
  458. if(aflag || bflag) {
  459. fprint(2, "ar: abi not allowed with q\n");
  460. exits("error");
  461. }
  462. fd = openar(arname, ORDWR, 1);
  463. if (fd < 0) {
  464. if(!cflag)
  465. fprint(2, "ar: creating %s\n", arname);
  466. fd = arcreate(arname);
  467. }
  468. Binit(&bar, fd, OREAD);
  469. Bseek(&bar,seek(fd,0,1), 1);
  470. /* leave note group behind when writing archive; i.e. sidestep interrupts */
  471. rfork(RFNOTEG);
  472. Bseek(&bar, 0, 2);
  473. bp = newmember();
  474. for(i=0; i<count && files[i]; i++) {
  475. file = files[i];
  476. files[i] = 0;
  477. bfile = Bopen(file, OREAD);
  478. if(!bfile)
  479. fprint(2, "ar: %s cannot open\n", file);
  480. else {
  481. mesg('q', file);
  482. armove(bfile, 0, bp);
  483. if (!arwrite(fd, bp))
  484. wrerr();
  485. free(bp->member);
  486. bp->member = 0;
  487. Bterm(bfile);
  488. }
  489. }
  490. free(bp);
  491. close(fd);
  492. }
  493. /*
  494. * extract the symbol references from an object file
  495. */
  496. void
  497. scanobj(Biobuf *b, Arfile *ap, int size)
  498. {
  499. int obj;
  500. long offset;
  501. Dir *d;
  502. static int lastobj = -1;
  503. if (!allobj) /* non-object file encountered */
  504. return;
  505. offset = Boffset(b);
  506. obj = objtype(b, 0);
  507. if (obj < 0) { /* not an object file */
  508. allobj = 0;
  509. d = dirfstat(Bfildes(b));
  510. if (d != nil && d->length == 0)
  511. fprint(2, "ar: zero length file %s\n", file);
  512. free(d);
  513. Bseek(b, offset, 0);
  514. return;
  515. }
  516. if (lastobj >= 0 && obj != lastobj) {
  517. fprint(2, "ar: inconsistent object file %s\n", file);
  518. allobj = 0;
  519. Bseek(b, offset, 0);
  520. return;
  521. }
  522. lastobj = obj;
  523. if (!readar(b, obj, offset+size, 0)) {
  524. fprint(2, "ar: invalid symbol reference in file %s\n", file);
  525. allobj = 0;
  526. Bseek(b, offset, 0);
  527. return;
  528. }
  529. Bseek(b, offset, 0);
  530. objtraverse(objsym, ap);
  531. }
  532. /*
  533. * add text and data symbols to the symbol list
  534. */
  535. void
  536. objsym(Sym *s, void *p)
  537. {
  538. int n;
  539. Arsymref *as;
  540. Arfile *ap;
  541. if (s->type != 'T' && s->type != 'D')
  542. return;
  543. ap = (Arfile*)p;
  544. as = (Arsymref*)armalloc(sizeof(Arsymref));
  545. as->offset = ap->size;
  546. n = strlen(s->name);
  547. as->name = armalloc(n+1);
  548. strcpy(as->name, s->name);
  549. if(s->type == 'T' && duplicate(as->name)) {
  550. dupfound = 1;
  551. fprint(2, "duplicate text symbol: %s\n", as->name);
  552. free(as->name);
  553. free(as);
  554. return;
  555. }
  556. as->type = s->type;
  557. symdefsize += 4+(n+1)+1;
  558. as->len = n;
  559. as->next = ap->sym;
  560. ap->sym = as;
  561. }
  562. /*
  563. * Check the symbol table for duplicate text symbols
  564. */
  565. int
  566. duplicate(char *name)
  567. {
  568. Hashchain *p;
  569. char *cp;
  570. int h;
  571. h = 0;
  572. for(cp = name; *cp; h += *cp++)
  573. h *= 1119;
  574. if(h < 0)
  575. h = ~h;
  576. h %= NHASH;
  577. for(p = hash[h]; p; p = p->next)
  578. if(strcmp(p->name, name) == 0)
  579. return 1;
  580. p = (Hashchain*) armalloc(sizeof(Hashchain));
  581. p->next = hash[h];
  582. p->name = name;
  583. hash[h] = p;
  584. return 0;
  585. }
  586. /*
  587. * open an archive and validate its header
  588. */
  589. int
  590. openar(char *arname, int mode, int errok)
  591. {
  592. int fd;
  593. char mbuf[SARMAG];
  594. fd = open(arname, mode);
  595. if(fd >= 0){
  596. if(read(fd, mbuf, SARMAG) != SARMAG || strncmp(mbuf, ARMAG, SARMAG)) {
  597. fprint(2, "ar: %s not in archive format\n", arname);
  598. exits("error");
  599. }
  600. }else if(!errok){
  601. fprint(2, "ar: cannot open %s: %r\n", arname);
  602. exits("error");
  603. }
  604. return fd;
  605. }
  606. /*
  607. * create an archive and set its header
  608. */
  609. int
  610. arcreate(char *arname)
  611. {
  612. int fd;
  613. fd = create(arname, OWRITE, 0664);
  614. if(fd < 0){
  615. fprint(2, "ar: cannot create %s: %r\n", arname);
  616. exits("error");
  617. }
  618. if(write(fd, ARMAG, SARMAG) != SARMAG)
  619. wrerr();
  620. return fd;
  621. }
  622. /*
  623. * error handling
  624. */
  625. void
  626. wrerr(void)
  627. {
  628. perror("ar: write error");
  629. exits("error");
  630. }
  631. void
  632. rderr(void)
  633. {
  634. perror("ar: read error");
  635. exits("error");
  636. }
  637. void
  638. phaseerr(int offset)
  639. {
  640. fprint(2, "ar: phase error at offset %d\n", offset);
  641. exits("error");
  642. }
  643. void
  644. usage(void)
  645. {
  646. fprint(2, "usage: ar [%s][%s] archive files ...\n", opt, man);
  647. exits("error");
  648. }
  649. /*
  650. * read the header for the next archive member
  651. */
  652. Armember *
  653. getdir(Biobuf *b)
  654. {
  655. Armember *bp;
  656. char *cp;
  657. static char name[ARNAMESIZE+1];
  658. bp = newmember();
  659. if(HEADER_IO(Bread, b, bp->hdr)) {
  660. free(bp);
  661. return 0;
  662. }
  663. if(strncmp(bp->hdr.fmag, ARFMAG, sizeof(bp->hdr.fmag)))
  664. phaseerr(Boffset(b));
  665. strncpy(name, bp->hdr.name, sizeof(bp->hdr.name));
  666. cp = name+sizeof(name)-1;
  667. while(*--cp==' ')
  668. ;
  669. cp[1] = '\0';
  670. file = name;
  671. bp->date = atol(bp->hdr.date);
  672. bp->size = atol(bp->hdr.size);
  673. return bp;
  674. }
  675. /*
  676. * Copy the file referenced by fd to the temp file
  677. */
  678. void
  679. armove(Biobuf *b, Arfile *ap, Armember *bp)
  680. {
  681. char *cp;
  682. Dir *d;
  683. d = dirfstat(Bfildes(b));
  684. if (d == nil) {
  685. fprint(2, "ar: cannot stat %s\n", file);
  686. return;
  687. }
  688. trim(file, bp->hdr.name, sizeof(bp->hdr.name));
  689. for (cp = strchr(bp->hdr.name, 0); /* blank pad on right */
  690. cp < bp->hdr.name+sizeof(bp->hdr.name); cp++)
  691. *cp = ' ';
  692. sprint(bp->hdr.date, "%-12ld", d->mtime);
  693. sprint(bp->hdr.uid, "%-6d", 0);
  694. sprint(bp->hdr.gid, "%-6d", 0);
  695. sprint(bp->hdr.mode, "%-8lo", d->mode);
  696. sprint(bp->hdr.size, "%-10lld", d->length);
  697. strncpy(bp->hdr.fmag, ARFMAG, 2);
  698. bp->size = d->length;
  699. arread(b, bp, bp->size);
  700. if (d->length&0x01)
  701. d->length++;
  702. if (ap) {
  703. arinsert(ap, bp);
  704. ap->size += d->length+SAR_HDR;
  705. }
  706. free(d);
  707. }
  708. /*
  709. * Copy the archive member at the current offset into the temp file.
  710. */
  711. void
  712. arcopy(Biobuf *b, Arfile *ap, Armember *bp)
  713. {
  714. int n;
  715. n = bp->size;
  716. if (n & 01)
  717. n++;
  718. arread(b, bp, n);
  719. if (ap) {
  720. arinsert(ap, bp);
  721. ap->size += n+SAR_HDR;
  722. }
  723. }
  724. /*
  725. * Skip an archive member
  726. */
  727. void
  728. skip(Biobuf *bp, long len)
  729. {
  730. if (len & 01)
  731. len++;
  732. Bseek(bp, len, 1);
  733. }
  734. /*
  735. * Stream the three temp files to an archive
  736. */
  737. void
  738. install(char *arname, Arfile *astart, Arfile *amiddle, Arfile *aend, int createflag)
  739. {
  740. int fd;
  741. if(allobj && dupfound) {
  742. fprint(2, "%s not changed\n", arname);
  743. return;
  744. }
  745. /* leave note group behind when copying back; i.e. sidestep interrupts */
  746. rfork(RFNOTEG);
  747. if(createflag)
  748. fprint(2, "ar: creating %s\n", arname);
  749. fd = arcreate(arname);
  750. if(allobj)
  751. rl(fd);
  752. if (astart) {
  753. arstream(fd, astart);
  754. arfree(astart);
  755. }
  756. if (amiddle) {
  757. arstream(fd, amiddle);
  758. arfree(amiddle);
  759. }
  760. if (aend) {
  761. arstream(fd, aend);
  762. arfree(aend);
  763. }
  764. close(fd);
  765. }
  766. void
  767. rl(int fd)
  768. {
  769. Biobuf b;
  770. char *cp;
  771. struct ar_hdr a;
  772. long len;
  773. Binit(&b, fd, OWRITE);
  774. Bseek(&b,seek(fd,0,1), 0);
  775. len = symdefsize;
  776. if(len&01)
  777. len++;
  778. sprint(a.date, "%-12ld", time(0));
  779. sprint(a.uid, "%-6d", 0);
  780. sprint(a.gid, "%-6d", 0);
  781. sprint(a.mode, "%-8lo", 0644L);
  782. sprint(a.size, "%-10ld", len);
  783. strncpy(a.fmag, ARFMAG, 2);
  784. strcpy(a.name, symdef);
  785. for (cp = strchr(a.name, 0); /* blank pad on right */
  786. cp < a.name+sizeof(a.name); cp++)
  787. *cp = ' ';
  788. if(HEADER_IO(Bwrite, &b, a))
  789. wrerr();
  790. len += Boffset(&b);
  791. if (astart) {
  792. wrsym(&b, len, astart->sym);
  793. len += astart->size;
  794. }
  795. if(amiddle) {
  796. wrsym(&b, len, amiddle->sym);
  797. len += amiddle->size;
  798. }
  799. if(aend)
  800. wrsym(&b, len, aend->sym);
  801. if(symdefsize&0x01)
  802. Bputc(&b, 0);
  803. Bterm(&b);
  804. }
  805. /*
  806. * Write the defined symbols to the symdef file
  807. */
  808. void
  809. wrsym(Biobuf *bp, int offset, Arsymref *as)
  810. {
  811. int off;
  812. while(as) {
  813. Bputc(bp, as->type);
  814. off = as->offset+offset;
  815. Bputc(bp, off);
  816. Bputc(bp, off>>8);
  817. Bputc(bp, off>>16);
  818. Bputc(bp, off>>24);
  819. if (Bwrite(bp, as->name, as->len+1) != as->len+1)
  820. wrerr();
  821. as = as->next;
  822. }
  823. }
  824. /*
  825. * Check if the archive member matches an entry on the command line.
  826. */
  827. int
  828. match(int count, char **files)
  829. {
  830. int i;
  831. char name[ARNAMESIZE+1];
  832. for(i=0; i<count; i++) {
  833. if(files[i] == 0)
  834. continue;
  835. trim(files[i], name, ARNAMESIZE);
  836. if(strncmp(name, file, ARNAMESIZE) == 0) {
  837. file = files[i];
  838. files[i] = 0;
  839. return 1;
  840. }
  841. }
  842. return 0;
  843. }
  844. /*
  845. * compare the current member to the name of the pivot member
  846. */
  847. int
  848. bamatch(char *file, char *pivot)
  849. {
  850. static int state = 0;
  851. switch(state)
  852. {
  853. case 0: /* looking for position file */
  854. if (aflag) {
  855. if (strncmp(file, pivot, ARNAMESIZE) == 0)
  856. state = 1;
  857. } else if (bflag) {
  858. if (strncmp(file, pivot, ARNAMESIZE) == 0) {
  859. state = 2; /* found */
  860. return 1;
  861. }
  862. }
  863. break;
  864. case 1: /* found - after previous file */
  865. state = 2;
  866. return 1;
  867. case 2: /* already found position file */
  868. break;
  869. }
  870. return 0;
  871. }
  872. /*
  873. * output a message, if 'v' option was specified
  874. */
  875. void
  876. mesg(int c, char *file)
  877. {
  878. if(vflag)
  879. Bprint(&bout, "%c - %s\n", c, file);
  880. }
  881. /*
  882. * isolate file name by stripping leading directories and trailing slashes
  883. */
  884. void
  885. trim(char *s, char *buf, int n)
  886. {
  887. char *p;
  888. for(;;) {
  889. p = strrchr(s, '/');
  890. if (!p) { /* no slash in name */
  891. strncpy(buf, s, n);
  892. return;
  893. }
  894. if (p[1] != 0) { /* p+1 is first char of file name */
  895. strncpy(buf, p+1, n);
  896. return;
  897. }
  898. *p = 0; /* strip trailing slash */
  899. }
  900. }
  901. /*
  902. * utilities for printing long form of 't' command
  903. */
  904. #define SUID 04000
  905. #define SGID 02000
  906. #define ROWN 0400
  907. #define WOWN 0200
  908. #define XOWN 0100
  909. #define RGRP 040
  910. #define WGRP 020
  911. #define XGRP 010
  912. #define ROTH 04
  913. #define WOTH 02
  914. #define XOTH 01
  915. #define STXT 01000
  916. void
  917. longt(Armember *bp)
  918. {
  919. char *cp;
  920. pmode(strtoul(bp->hdr.mode, 0, 8));
  921. Bprint(&bout, "%3ld/%1ld", atol(bp->hdr.uid), atol(bp->hdr.gid));
  922. Bprint(&bout, "%7ld", bp->size);
  923. cp = ctime(bp->date);
  924. Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24);
  925. }
  926. int m1[] = { 1, ROWN, 'r', '-' };
  927. int m2[] = { 1, WOWN, 'w', '-' };
  928. int m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
  929. int m4[] = { 1, RGRP, 'r', '-' };
  930. int m5[] = { 1, WGRP, 'w', '-' };
  931. int m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
  932. int m7[] = { 1, ROTH, 'r', '-' };
  933. int m8[] = { 1, WOTH, 'w', '-' };
  934. int m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
  935. int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
  936. void
  937. pmode(long mode)
  938. {
  939. int **mp;
  940. for(mp = &m[0]; mp < &m[9];)
  941. select(*mp++, mode);
  942. }
  943. void
  944. select(int *ap, long mode)
  945. {
  946. int n;
  947. n = *ap++;
  948. while(--n>=0 && (mode&*ap++)==0)
  949. ap++;
  950. Bputc(&bout, *ap);
  951. }
  952. /*
  953. * Temp file I/O subsystem. We attempt to cache all three temp files in
  954. * core. When we run out of memory we spill to disk.
  955. * The I/O model assumes that temp files:
  956. * 1) are only written on the end
  957. * 2) are only read from the beginning
  958. * 3) are only read after all writing is complete.
  959. * The architecture uses one control block per temp file. Each control
  960. * block anchors a chain of buffers, each containing an archive member.
  961. */
  962. Arfile *
  963. newtempfile(char *name) /* allocate a file control block */
  964. {
  965. Arfile *ap;
  966. ap = (Arfile *) armalloc(sizeof(Arfile));
  967. ap->fname = name;
  968. return ap;
  969. }
  970. Armember *
  971. newmember(void) /* allocate a member buffer */
  972. {
  973. return (Armember *)armalloc(sizeof(Armember));
  974. }
  975. void
  976. arread(Biobuf *b, Armember *bp, int n) /* read an image into a member buffer */
  977. {
  978. int i;
  979. bp->member = armalloc(n);
  980. i = Bread(b, bp->member, n);
  981. if (i < 0) {
  982. free(bp->member);
  983. bp->member = 0;
  984. rderr();
  985. }
  986. }
  987. /*
  988. * insert a member buffer into the member chain
  989. */
  990. void
  991. arinsert(Arfile *ap, Armember *bp)
  992. {
  993. bp->next = 0;
  994. if (!ap->tail)
  995. ap->head = bp;
  996. else
  997. ap->tail->next = bp;
  998. ap->tail = bp;
  999. }
  1000. /*
  1001. * stream the members in a temp file to the file referenced by 'fd'.
  1002. */
  1003. void
  1004. arstream(int fd, Arfile *ap)
  1005. {
  1006. Armember *bp;
  1007. int i;
  1008. char buf[8192];
  1009. if (ap->paged) { /* copy from disk */
  1010. seek(ap->fd, 0, 0);
  1011. for (;;) {
  1012. i = read(ap->fd, buf, sizeof(buf));
  1013. if (i < 0)
  1014. rderr();
  1015. if (i == 0)
  1016. break;
  1017. if (write(fd, buf, i) != i)
  1018. wrerr();
  1019. }
  1020. close(ap->fd);
  1021. ap->paged = 0;
  1022. }
  1023. /* dump the in-core buffers */
  1024. for (bp = ap->head; bp; bp = bp->next) {
  1025. if (!arwrite(fd, bp))
  1026. wrerr();
  1027. }
  1028. }
  1029. /*
  1030. * write a member to 'fd'.
  1031. */
  1032. int
  1033. arwrite(int fd, Armember *bp)
  1034. {
  1035. int len;
  1036. if(HEADER_IO(write, fd, bp->hdr))
  1037. return 0;
  1038. len = bp->size;
  1039. if (len & 01)
  1040. len++;
  1041. if (write(fd, bp->member, len) != len)
  1042. return 0;
  1043. return 1;
  1044. }
  1045. /*
  1046. * Spill a member to a disk copy of a temp file
  1047. */
  1048. int
  1049. page(Arfile *ap)
  1050. {
  1051. Armember *bp;
  1052. bp = ap->head;
  1053. if (!ap->paged) { /* not yet paged - create file */
  1054. ap->fname = mktemp(ap->fname);
  1055. ap->fd = create(ap->fname, ORDWR|ORCLOSE, 0600);
  1056. if (ap->fd < 0) {
  1057. fprint(2,"ar: can't create temp file\n");
  1058. return 0;
  1059. }
  1060. ap->paged = 1;
  1061. }
  1062. if (!arwrite(ap->fd, bp)) /* write member and free buffer block */
  1063. return 0;
  1064. ap->head = bp->next;
  1065. if (ap->tail == bp)
  1066. ap->tail = bp->next;
  1067. free(bp->member);
  1068. free(bp);
  1069. return 1;
  1070. }
  1071. /*
  1072. * try to reclaim space by paging. we try to spill the start, middle,
  1073. * and end files, in that order. there is no particular reason for the
  1074. * ordering.
  1075. */
  1076. int
  1077. getspace(void)
  1078. {
  1079. if (astart && astart->head && page(astart))
  1080. return 1;
  1081. if (amiddle && amiddle->head && page(amiddle))
  1082. return 1;
  1083. if (aend && aend->head && page(aend))
  1084. return 1;
  1085. return 0;
  1086. }
  1087. void
  1088. arfree(Arfile *ap) /* free a member buffer */
  1089. {
  1090. Armember *bp, *next;
  1091. for (bp = ap->head; bp; bp = next) {
  1092. next = bp->next;
  1093. if (bp->member)
  1094. free(bp->member);
  1095. free(bp);
  1096. }
  1097. free(ap);
  1098. }
  1099. /*
  1100. * allocate space for a control block or member buffer. if the malloc
  1101. * fails we try to reclaim space by spilling previously allocated
  1102. * member buffers.
  1103. */
  1104. char *
  1105. armalloc(int n)
  1106. {
  1107. char *cp;
  1108. do {
  1109. cp = malloc(n);
  1110. if (cp) {
  1111. memset(cp, 0, n);
  1112. return cp;
  1113. }
  1114. } while (getspace());
  1115. fprint(2, "ar: out of memory\n");
  1116. exits("malloc");
  1117. return 0;
  1118. }