tar.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <auth.h>
  4. #include <fcall.h>
  5. #include <bio.h>
  6. #define TBLOCK 512
  7. #define NBLOCK 40 /* maximum blocksize */
  8. #define DBLOCK 20 /* default blocksize */
  9. #define NAMSIZ 100
  10. union hblock
  11. {
  12. char dummy[TBLOCK];
  13. struct header
  14. {
  15. char name[NAMSIZ];
  16. char mode[8];
  17. char uid[8];
  18. char gid[8];
  19. char size[12];
  20. char mtime[12];
  21. char chksum[8];
  22. char linkflag;
  23. char linkname[NAMSIZ];
  24. } dbuf;
  25. } dblock, tbuf[NBLOCK];
  26. Dir *stbuf;
  27. Biobuf bout;
  28. int rflag, xflag, vflag, tflag, mt, cflag, fflag, Tflag, Rflag;
  29. int uflag, gflag;
  30. int chksum, recno, first;
  31. int nblock = DBLOCK;
  32. void usage(void);
  33. void dorep(char **);
  34. int endtar(void);
  35. void getdir(void);
  36. void passtar(void);
  37. void putfile(char*, char *, char *);
  38. void doxtract(char **);
  39. void dotable(void);
  40. void putempty(void);
  41. void longt(Dir *);
  42. int checkdir(char *, int, Qid*);
  43. void tomodes(Dir *);
  44. int checksum(void);
  45. int checkupdate(char *);
  46. int prefix(char *, char *);
  47. int readtar(char *);
  48. int writetar(char *);
  49. void backtar(void);
  50. void flushtar(void);
  51. void affix(int, char *);
  52. int volprompt(void);
  53. void
  54. main(int argc, char **argv)
  55. {
  56. char *usefile;
  57. char *cp, *ap;
  58. if (argc < 2)
  59. usage();
  60. Binit(&bout, 1, OWRITE);
  61. usefile = 0;
  62. argv[argc] = 0;
  63. argv++;
  64. for (cp = *argv++; *cp; cp++)
  65. switch(*cp) {
  66. case 'f':
  67. usefile = *argv++;
  68. if(!usefile)
  69. usage();
  70. fflag++;
  71. break;
  72. case 'u':
  73. ap = *argv++;
  74. if(!ap)
  75. usage();
  76. uflag = strtoul(ap, 0, 0);
  77. break;
  78. case 'g':
  79. ap = *argv++;
  80. if(!ap)
  81. usage();
  82. gflag = strtoul(ap, 0, 0);
  83. break;
  84. case 'c':
  85. cflag++;
  86. rflag++;
  87. break;
  88. case 'r':
  89. rflag++;
  90. break;
  91. case 'v':
  92. vflag++;
  93. break;
  94. case 'x':
  95. xflag++;
  96. break;
  97. case 'T':
  98. Tflag++;
  99. break;
  100. case 't':
  101. tflag++;
  102. break;
  103. case 'R':
  104. Rflag++;
  105. break;
  106. case '-':
  107. break;
  108. default:
  109. fprint(2, "tar: %c: unknown option\n", *cp);
  110. usage();
  111. }
  112. fmtinstall('M', dirmodefmt);
  113. if (rflag) {
  114. if (!usefile) {
  115. if (cflag == 0) {
  116. fprint(2, "tar: can only create standard output archives\n");
  117. exits("arg error");
  118. }
  119. mt = dup(1, -1);
  120. nblock = 1;
  121. }
  122. else if ((mt = open(usefile, ORDWR)) < 0) {
  123. if (cflag == 0 || (mt = create(usefile, OWRITE, 0666)) < 0) {
  124. fprint(2, "tar: cannot open %s: %r\n", usefile);
  125. exits("open");
  126. }
  127. }
  128. dorep(argv);
  129. }
  130. else if (xflag) {
  131. if (!usefile) {
  132. mt = dup(0, -1);
  133. nblock = 1;
  134. }
  135. else if ((mt = open(usefile, OREAD)) < 0) {
  136. fprint(2, "tar: cannot open %s: %r\n", usefile);
  137. exits("open");
  138. }
  139. doxtract(argv);
  140. }
  141. else if (tflag) {
  142. if (!usefile) {
  143. mt = dup(0, -1);
  144. nblock = 1;
  145. }
  146. else if ((mt = open(usefile, OREAD)) < 0) {
  147. fprint(2, "tar: cannot open %s: %r\n", usefile);
  148. exits("open");
  149. }
  150. dotable();
  151. }
  152. else
  153. usage();
  154. exits(0);
  155. }
  156. void
  157. usage(void)
  158. {
  159. fprint(2, "tar: usage tar {txrc}[Rvf] [tarfile] file1 file2...\n");
  160. exits("usage");
  161. }
  162. void
  163. dorep(char **argv)
  164. {
  165. char cwdbuf[2048], *cwd, thisdir[2048];
  166. char *cp, *cp2;
  167. int cd;
  168. if (getwd(cwdbuf, sizeof(cwdbuf)) == 0) {
  169. fprint(2, "tar: can't find current directory: %r\n");
  170. exits("cwd");
  171. }
  172. cwd = cwdbuf;
  173. if (!cflag) {
  174. getdir();
  175. do {
  176. passtar();
  177. getdir();
  178. } while (!endtar());
  179. }
  180. while (*argv) {
  181. cp2 = *argv;
  182. if (!strcmp(cp2, "-C") && argv[1]) {
  183. argv++;
  184. if (chdir(*argv) < 0)
  185. perror(*argv);
  186. cwd = *argv;
  187. argv++;
  188. continue;
  189. }
  190. cd = 0;
  191. for (cp = *argv; *cp; cp++)
  192. if (*cp == '/')
  193. cp2 = cp;
  194. if (cp2 != *argv) {
  195. *cp2 = '\0';
  196. chdir(*argv);
  197. if(**argv == '/')
  198. strncpy(thisdir, *argv, sizeof(thisdir));
  199. else
  200. snprint(thisdir, sizeof(thisdir), "%s/%s", cwd, *argv);
  201. *cp2 = '/';
  202. cp2++;
  203. cd = 1;
  204. } else
  205. strncpy(thisdir, cwd, sizeof(thisdir));
  206. putfile(thisdir, *argv++, cp2);
  207. if(cd && chdir(cwd) < 0) {
  208. fprint(2, "tar: can't cd back to %s: %r\n", cwd);
  209. exits("cwd");
  210. }
  211. }
  212. putempty();
  213. putempty();
  214. flushtar();
  215. }
  216. int
  217. endtar(void)
  218. {
  219. if (dblock.dbuf.name[0] == '\0') {
  220. backtar();
  221. return(1);
  222. }
  223. else
  224. return(0);
  225. }
  226. void
  227. getdir(void)
  228. {
  229. Dir *sp;
  230. readtar((char*)&dblock);
  231. if (dblock.dbuf.name[0] == '\0')
  232. return;
  233. if(stbuf == nil){
  234. stbuf = malloc(sizeof(Dir));
  235. if(stbuf == nil) {
  236. fprint(2, "tar: can't malloc: %r\n");
  237. exits("malloc");
  238. }
  239. }
  240. sp = stbuf;
  241. sp->mode = strtol(dblock.dbuf.mode, 0, 8);
  242. sp->uid = "adm";
  243. sp->gid = "adm";
  244. sp->length = strtol(dblock.dbuf.size, 0, 8);
  245. sp->mtime = strtol(dblock.dbuf.mtime, 0, 8);
  246. chksum = strtol(dblock.dbuf.chksum, 0, 8);
  247. if (chksum != checksum()) {
  248. fprint(2, "directory checksum error\n");
  249. exits("checksum error");
  250. }
  251. sp->qid.type = 0;
  252. /* the mode test is ugly but sometimes necessary */
  253. if (dblock.dbuf.linkflag == '5' || (sp->mode&0170000) == 040000) {
  254. sp->qid.type |= QTDIR;
  255. sp->mode |= DMDIR;
  256. }
  257. }
  258. void
  259. passtar(void)
  260. {
  261. long blocks;
  262. char buf[TBLOCK];
  263. if (dblock.dbuf.linkflag == '1' || dblock.dbuf.linkflag == 's')
  264. return;
  265. blocks = stbuf->length;
  266. blocks += TBLOCK-1;
  267. blocks /= TBLOCK;
  268. while (blocks-- > 0)
  269. readtar(buf);
  270. }
  271. void
  272. putfile(char *dir, char *longname, char *sname)
  273. {
  274. int infile;
  275. long blocks;
  276. char buf[TBLOCK];
  277. char curdir[4096];
  278. char shortname[4096];
  279. char *cp, *cp2;
  280. Dir *db;
  281. int i, n;
  282. if(strlen(sname) > sizeof shortname - 3){
  283. fprint(2, "tar: %s: name too long (max %d)\n", sname, sizeof shortname - 3);
  284. return;
  285. }
  286. snprint(shortname, sizeof shortname, "./%s", sname);
  287. infile = open(shortname, OREAD);
  288. if (infile < 0) {
  289. fprint(2, "tar: %s: cannot open file - %r\n", longname);
  290. return;
  291. }
  292. if(stbuf != nil)
  293. free(stbuf);
  294. stbuf = dirfstat(infile);
  295. if (stbuf->qid.type & QTDIR) {
  296. /* Directory */
  297. for (i = 0, cp = buf; *cp++ = longname[i++];);
  298. *--cp = '/';
  299. *++cp = 0;
  300. if( (cp - buf) >= NAMSIZ) {
  301. fprint(2, "tar: %s: file name too long\n", longname);
  302. close(infile);
  303. return;
  304. }
  305. stbuf->length = 0;
  306. tomodes(stbuf);
  307. strcpy(dblock.dbuf.name,buf);
  308. dblock.dbuf.linkflag = '5'; /* Directory */
  309. sprint(dblock.dbuf.chksum, "%6o", checksum());
  310. writetar( (char *) &dblock);
  311. if (chdir(shortname) < 0) {
  312. fprint(2, "tar: can't cd to %s: %r\n", shortname);
  313. snprint(curdir, sizeof(curdir), "cd %s", shortname);
  314. exits(curdir);
  315. }
  316. sprint(curdir, "%s/%s", dir, sname);
  317. while ((n = dirread(infile, &db)) > 0) {
  318. for(i = 0; i < n; i++){
  319. strncpy(cp, db[i].name, sizeof buf - (cp-buf));
  320. putfile(curdir, buf, db[i].name);
  321. }free(db);
  322. }
  323. close(infile);
  324. if (chdir(dir) < 0 && chdir("..") < 0) {
  325. fprint(2, "tar: can't cd to ..(%s): %r\n", dir);
  326. snprint(curdir, sizeof(curdir), "cd ..(%s)", dir);
  327. exits(curdir);
  328. }
  329. return;
  330. }
  331. tomodes(stbuf);
  332. cp2 = longname;
  333. for (cp = dblock.dbuf.name, i=0; (*cp++ = *cp2++) && i < NAMSIZ; i++);
  334. if (i >= NAMSIZ) {
  335. fprint(2, "%s: file name too long\n", longname);
  336. close(infile);
  337. return;
  338. }
  339. blocks = (stbuf->length + (TBLOCK-1)) / TBLOCK;
  340. if (vflag) {
  341. fprint(2, "a %s ", longname);
  342. fprint(2, "%ld blocks\n", blocks);
  343. }
  344. dblock.dbuf.linkflag = 0; /* Regular file */
  345. sprint(dblock.dbuf.chksum, "%6o", checksum());
  346. writetar( (char *) &dblock);
  347. while ((i = readn(infile, buf, TBLOCK)) > 0 && blocks > 0) {
  348. writetar(buf);
  349. blocks--;
  350. }
  351. close(infile);
  352. if (blocks != 0 || i != 0)
  353. fprint(2, "%s: file changed size\n", longname);
  354. while (blocks-- > 0)
  355. putempty();
  356. }
  357. void
  358. doxtract(char **argv)
  359. {
  360. Dir null;
  361. long blocks, bytes;
  362. char buf[TBLOCK], outname[NAMSIZ+4];
  363. char **cp;
  364. int ofile;
  365. for (;;) {
  366. getdir();
  367. if (endtar())
  368. break;
  369. if (*argv == 0)
  370. goto gotit;
  371. for (cp = argv; *cp; cp++)
  372. if (prefix(*cp, dblock.dbuf.name))
  373. goto gotit;
  374. passtar();
  375. continue;
  376. gotit:
  377. if(checkdir(dblock.dbuf.name, stbuf->mode, &(stbuf->qid)))
  378. continue;
  379. if (dblock.dbuf.linkflag == '1') {
  380. fprint(2, "tar: can't link %s %s\n",
  381. dblock.dbuf.linkname, dblock.dbuf.name);
  382. remove(dblock.dbuf.name);
  383. continue;
  384. }
  385. if (dblock.dbuf.linkflag == 's') {
  386. fprint(2, "tar: %s: cannot symlink\n", dblock.dbuf.name);
  387. continue;
  388. }
  389. if(dblock.dbuf.name[0] != '/' || Rflag)
  390. sprint(outname, "./%s", dblock.dbuf.name);
  391. else
  392. strcpy(outname, dblock.dbuf.name);
  393. if ((ofile = create(outname, OWRITE, stbuf->mode & 0777)) < 0) {
  394. fprint(2, "tar: %s - cannot create: %r\n", outname);
  395. passtar();
  396. continue;
  397. }
  398. blocks = ((bytes = stbuf->length) + TBLOCK-1)/TBLOCK;
  399. if (vflag)
  400. fprint(2, "x %s, %ld bytes\n",
  401. dblock.dbuf.name, bytes);
  402. while (blocks-- > 0) {
  403. readtar(buf);
  404. if (bytes > TBLOCK) {
  405. if (write(ofile, buf, TBLOCK) < 0) {
  406. fprint(2, "tar: %s: HELP - extract write error: %r\n", dblock.dbuf.name);
  407. exits("extract write");
  408. }
  409. } else
  410. if (write(ofile, buf, bytes) < 0) {
  411. fprint(2, "tar: %s: HELP - extract write error: %r\n", dblock.dbuf.name);
  412. exits("extract write");
  413. }
  414. bytes -= TBLOCK;
  415. }
  416. if(Tflag){
  417. nulldir(&null);
  418. null.mtime = stbuf->mtime;
  419. dirfwstat(ofile, &null);
  420. }
  421. close(ofile);
  422. }
  423. }
  424. void
  425. dotable(void)
  426. {
  427. for (;;) {
  428. getdir();
  429. if (endtar())
  430. break;
  431. if (vflag)
  432. longt(stbuf);
  433. Bprint(&bout, "%s", dblock.dbuf.name);
  434. if (dblock.dbuf.linkflag == '1')
  435. Bprint(&bout, " linked to %s", dblock.dbuf.linkname);
  436. if (dblock.dbuf.linkflag == 's')
  437. Bprint(&bout, " -> %s", dblock.dbuf.linkname);
  438. Bprint(&bout, "\n");
  439. passtar();
  440. }
  441. }
  442. void
  443. putempty(void)
  444. {
  445. char buf[TBLOCK];
  446. memset(buf, 0, TBLOCK);
  447. writetar(buf);
  448. }
  449. void
  450. longt(Dir *st)
  451. {
  452. char *cp;
  453. Bprint(&bout, "%M %4d/%1d ", st->mode, 0, 0); /* 0/0 uid/gid */
  454. Bprint(&bout, "%8lld", st->length);
  455. cp = ctime(st->mtime);
  456. Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24);
  457. }
  458. int
  459. checkdir(char *name, int mode, Qid *qid)
  460. {
  461. char *cp;
  462. int f;
  463. Dir *d, null;
  464. if(Rflag && *name == '/')
  465. name++;
  466. cp = name;
  467. if(*cp == '/')
  468. cp++;
  469. for (; *cp; cp++) {
  470. if (*cp == '/') {
  471. *cp = '\0';
  472. if (access(name, 0) < 0) {
  473. f = create(name, OREAD, DMDIR + 0775L);
  474. if(f < 0)
  475. fprint(2, "tar: mkdir %s failed: %r\n", name);
  476. close(f);
  477. }
  478. *cp = '/';
  479. }
  480. }
  481. /* if this is a directory, chmod it to the mode in the tar plus 700 */
  482. if(cp[-1] == '/' || (qid->type&QTDIR)){
  483. if((d=dirstat(name)) != 0){
  484. nulldir(&null);
  485. null.mode = DMDIR | (mode & 0777) | 0700;
  486. dirwstat(name, &null);
  487. free(d);
  488. }
  489. return 1;
  490. } else
  491. return 0;
  492. }
  493. void
  494. tomodes(Dir *sp)
  495. {
  496. char *cp;
  497. for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
  498. *cp = '\0';
  499. sprint(dblock.dbuf.mode, "%6lo ", sp->mode & 0777);
  500. sprint(dblock.dbuf.uid, "%6o ", uflag);
  501. sprint(dblock.dbuf.gid, "%6o ", gflag);
  502. sprint(dblock.dbuf.size, "%11llo ", sp->length);
  503. sprint(dblock.dbuf.mtime, "%11lo ", sp->mtime);
  504. }
  505. int
  506. checksum(void)
  507. {
  508. int i;
  509. char *cp;
  510. for (cp = dblock.dbuf.chksum; cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++)
  511. *cp = ' ';
  512. i = 0;
  513. for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
  514. i += *cp & 0xff;
  515. return(i);
  516. }
  517. int
  518. prefix(char *s1, char *s2)
  519. {
  520. while (*s1)
  521. if (*s1++ != *s2++)
  522. return(0);
  523. if (*s2)
  524. return(*s2 == '/');
  525. return(1);
  526. }
  527. int
  528. readtar(char *buffer)
  529. {
  530. int i;
  531. if (recno >= nblock || first == 0) {
  532. if ((i = readn(mt, tbuf, TBLOCK*nblock)) <= 0) {
  533. fprint(2, "tar: archive read error: %r\n");
  534. exits("archive read");
  535. }
  536. if (first == 0) {
  537. if ((i % TBLOCK) != 0) {
  538. fprint(2, "tar: archive blocksize error: %r\n");
  539. exits("blocksize");
  540. }
  541. i /= TBLOCK;
  542. if (i != nblock) {
  543. fprint(2, "tar: blocksize = %d\n", i);
  544. nblock = i;
  545. }
  546. }
  547. recno = 0;
  548. }
  549. first = 1;
  550. memmove(buffer, &tbuf[recno++], TBLOCK);
  551. return(TBLOCK);
  552. }
  553. int
  554. writetar(char *buffer)
  555. {
  556. first = 1;
  557. if (recno >= nblock) {
  558. if (write(mt, tbuf, TBLOCK*nblock) != TBLOCK*nblock) {
  559. fprint(2, "tar: archive write error: %r\n");
  560. exits("write");
  561. }
  562. recno = 0;
  563. }
  564. memmove(&tbuf[recno++], buffer, TBLOCK);
  565. if (recno >= nblock) {
  566. if (write(mt, tbuf, TBLOCK*nblock) != TBLOCK*nblock) {
  567. fprint(2, "tar: archive write error: %r\n");
  568. exits("write");
  569. }
  570. recno = 0;
  571. }
  572. return(TBLOCK);
  573. }
  574. /*
  575. * backup over last tar block
  576. */
  577. void
  578. backtar(void)
  579. {
  580. seek(mt, -TBLOCK*nblock, 1);
  581. recno--;
  582. }
  583. void
  584. flushtar(void)
  585. {
  586. write(mt, tbuf, TBLOCK*nblock);
  587. }