1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: char copyright[] =
9: "@(#) Copyright (c) 1980 Regents of the University of California.\n\
10: All rights reserved.\n";
11: #endif not lint
12:
13: #ifndef lint
14: static char sccsid[] = "@(#)tar.c 5.7 (Berkeley) 4/26/86";
15: #endif not lint
16:
17: /*
18: * Tape Archival Program
19: */
20: #include <stdio.h>
21: #include <sys/param.h>
22: #include <sys/stat.h>
23: #include <sys/dir.h>
24: #include <sys/ioctl.h>
25: #include <sys/mtio.h>
26: #include <sys/time.h>
27: #include <signal.h>
28: #include <errno.h>
29: #include <fcntl.h>
30:
31: #define TBLOCK 512
32: #define NBLOCK 20
33: #define NAMSIZ 100
34:
35: #define writetape(b) writetbuf(b, 1)
36: #define min(a,b) ((a) < (b) ? (a) : (b))
37: #define max(a,b) ((a) > (b) ? (a) : (b))
38:
39: union hblock {
40: char dummy[TBLOCK];
41: struct {
42: char name[NAMSIZ];
43: char mode[8];
44: char uid[8];
45: char gid[8];
46: char size[12];
47: char mtime[12];
48: char chksum[8];
49: char linkflag;
50: char linkname[NAMSIZ];
51: } dbuf;
52: };
53:
54: struct linkbuf {
55: ino_t inum;
56: dev_t devnum;
57: int count;
58: char pathname[NAMSIZ];
59: struct linkbuf *nextp;
60: };
61:
62: union hblock dblock;
63: union hblock *tbuf;
64: struct linkbuf *ihead;
65: struct stat stbuf;
66:
67: int rflag;
68: int xflag;
69: int vflag;
70: int tflag;
71: int cflag;
72: int mflag;
73: int fflag;
74: int iflag;
75: int oflag;
76: int pflag;
77: int wflag;
78: int hflag;
79: int Bflag;
80: int Fflag;
81:
82: int mt;
83: int term;
84: int chksum;
85: int recno;
86: int first;
87: int prtlinkerr;
88: int freemem = 1;
89: int nblock = 0;
90: int onintr();
91: int onquit();
92: int onhup();
93: #ifdef notdef
94: int onterm();
95: #endif
96:
97: daddr_t low;
98: daddr_t high;
99: daddr_t bsrch();
100:
101: FILE *vfile = stdout;
102: FILE *tfile;
103: char tname[] = "/tmp/tarXXXXXX";
104: char *usefile;
105: char magtape[] = "/dev/rmt8";
106: char *malloc();
107: long time();
108: off_t lseek();
109: char *mktemp();
110: char *sprintf();
111: char *strcat();
112: char *strcpy();
113: char *rindex();
114: char *getcwd();
115: char *getwd();
116: char *getmem();
117:
118: main(argc, argv)
119: int argc;
120: char *argv[];
121: {
122: char *cp;
123:
124: if (argc < 2)
125: usage();
126:
127: tfile = NULL;
128: usefile = magtape;
129: argv[argc] = 0;
130: argv++;
131: for (cp = *argv++; *cp; cp++)
132: switch(*cp) {
133:
134: case 'f':
135: if (*argv == 0) {
136: fprintf(stderr,
137: "tar: tapefile must be specified with 'f' option\n");
138: usage();
139: }
140: usefile = *argv++;
141: fflag++;
142: break;
143:
144: case 'c':
145: cflag++;
146: rflag++;
147: break;
148:
149: case 'o':
150: oflag++;
151: break;
152:
153: case 'p':
154: pflag++;
155: break;
156:
157: case 'u':
158: mktemp(tname);
159: if ((tfile = fopen(tname, "w")) == NULL) {
160: fprintf(stderr,
161: "tar: cannot create temporary file (%s)\n",
162: tname);
163: done(1);
164: }
165: fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n");
166: /*FALL THRU*/
167:
168: case 'r':
169: rflag++;
170: break;
171:
172: case 'v':
173: vflag++;
174: break;
175:
176: case 'w':
177: wflag++;
178: break;
179:
180: case 'x':
181: xflag++;
182: break;
183:
184: case 't':
185: tflag++;
186: break;
187:
188: case 'm':
189: mflag++;
190: break;
191:
192: case '-':
193: break;
194:
195: case '0':
196: case '1':
197: case '4':
198: case '5':
199: case '7':
200: case '8':
201: magtape[8] = *cp;
202: usefile = magtape;
203: break;
204:
205: case 'b':
206: if (*argv == 0) {
207: fprintf(stderr,
208: "tar: blocksize must be specified with 'b' option\n");
209: usage();
210: }
211: nblock = atoi(*argv);
212: if (nblock <= 0) {
213: fprintf(stderr,
214: "tar: invalid blocksize \"%s\"\n", *argv);
215: done(1);
216: }
217: argv++;
218: break;
219:
220: case 'l':
221: prtlinkerr++;
222: break;
223:
224: case 'h':
225: hflag++;
226: break;
227:
228: case 'i':
229: iflag++;
230: break;
231:
232: case 'B':
233: Bflag++;
234: break;
235:
236: case 'F':
237: Fflag++;
238: break;
239:
240: default:
241: fprintf(stderr, "tar: %c: unknown option\n", *cp);
242: usage();
243: }
244:
245: if (!rflag && !xflag && !tflag)
246: usage();
247: if (rflag) {
248: if (cflag && tfile != NULL)
249: usage();
250: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
251: (void) signal(SIGINT, onintr);
252: if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
253: (void) signal(SIGHUP, onhup);
254: if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
255: (void) signal(SIGQUIT, onquit);
256: #ifdef notdef
257: if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
258: (void) signal(SIGTERM, onterm);
259: #endif
260: mt = openmt(usefile, 1);
261: dorep(argv);
262: done(0);
263: }
264: mt = openmt(usefile, 0);
265: if (xflag)
266: doxtract(argv);
267: else
268: dotable(argv);
269: done(0);
270: }
271:
272: usage()
273: {
274: fprintf(stderr,
275: "tar: usage: tar -{txru}[cvfblmhopwBi] [tapefile] [blocksize] file1 file2...\n");
276: done(1);
277: }
278:
279: int
280: openmt(tape, writing)
281: char *tape;
282: int writing;
283: {
284:
285: if (strcmp(tape, "-") == 0) {
286: /*
287: * Read from standard input or write to standard output.
288: */
289: if (writing) {
290: if (cflag == 0) {
291: fprintf(stderr,
292: "tar: can only create standard output archives\n");
293: done(1);
294: }
295: vfile = stderr;
296: setlinebuf(vfile);
297: mt = dup(1);
298: } else {
299: mt = dup(0);
300: Bflag++;
301: }
302: } else {
303: /*
304: * Use file or tape on local machine.
305: */
306: if (writing) {
307: if (cflag)
308: mt = open(tape, O_RDWR|O_CREAT|O_TRUNC, 0666);
309: else
310: mt = open(tape, O_RDWR);
311: } else
312: mt = open(tape, O_RDONLY);
313: if (mt < 0) {
314: fprintf(stderr, "tar: ");
315: perror(tape);
316: done(1);
317: }
318: }
319: return(mt);
320: }
321:
322: dorep(argv)
323: char *argv[];
324: {
325: register char *cp, *cp2;
326: char wdir[MAXPATHLEN], tempdir[MAXPATHLEN], *parent;
327:
328: if (!cflag) {
329: getdir();
330: do {
331: passtape();
332: if (term)
333: done(0);
334: getdir();
335: } while (!endtape());
336: backtape();
337: if (tfile != NULL) {
338: char buf[200];
339:
340: sprintf(buf,
341: "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s",
342: tname, tname, tname, tname, tname, tname);
343: fflush(tfile);
344: system(buf);
345: freopen(tname, "r", tfile);
346: fstat(fileno(tfile), &stbuf);
347: high = stbuf.st_size;
348: }
349: }
350:
351: (void) getcwd(wdir);
352: while (*argv && ! term) {
353: cp2 = *argv;
354: if (!strcmp(cp2, "-C") && argv[1]) {
355: argv++;
356: if (chdir(*argv) < 0) {
357: fprintf(stderr, "tar: can't change directories to ");
358: perror(*argv);
359: } else
360: (void) getcwd(wdir);
361: argv++;
362: continue;
363: }
364:
365: if (*argv[0] == '/'){
366: parent = "";
367: } else {
368: parent = wdir;
369: }
370:
371: for (cp = *argv; *cp; cp++)
372: if (*cp == '/')
373: cp2 = cp;
374: if (cp2 != *argv) {
375: *cp2 = '\0';
376: if (chdir(*argv) < 0) {
377: fprintf(stderr, "tar: can't change directories to ");
378: perror(*argv);
379: continue;
380: }
381: parent = getcwd(tempdir);
382: *cp2 = '/';
383: cp2++;
384: }
385: putfile(*argv++, cp2, parent);
386: if (chdir(wdir) < 0) {
387: fprintf(stderr, "tar: cannot change back?: ");
388: perror(wdir);
389: }
390: }
391: putempty();
392: putempty();
393: flushtape();
394: if (prtlinkerr == 0)
395: return;
396: for (; ihead != NULL; ihead = ihead->nextp) {
397: if (ihead->count == 0)
398: continue;
399: fprintf(stderr, "tar: missing links to %s\n", ihead->pathname);
400: }
401: }
402:
403: endtape()
404: {
405: return (dblock.dbuf.name[0] == '\0');
406: }
407:
408: getdir()
409: {
410: register struct stat *sp;
411: int i;
412:
413: top:
414: readtape((char *)&dblock);
415: if (dblock.dbuf.name[0] == '\0')
416: return;
417: sp = &stbuf;
418: sscanf(dblock.dbuf.mode, "%o", &i);
419: sp->st_mode = i;
420: sscanf(dblock.dbuf.uid, "%o", &i);
421: sp->st_uid = i;
422: sscanf(dblock.dbuf.gid, "%o", &i);
423: sp->st_gid = i;
424: sscanf(dblock.dbuf.size, "%lo", &sp->st_size);
425: sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime);
426: sscanf(dblock.dbuf.chksum, "%o", &chksum);
427: if (chksum != (i = checksum())) {
428: fprintf(stderr, "tar: directory checksum error (%d != %d)\n",
429: chksum, i);
430: if (iflag)
431: goto top;
432: done(2);
433: }
434: if (tfile != NULL)
435: fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime);
436: }
437:
438: passtape()
439: {
440: long blocks;
441: char *bufp;
442:
443: if (dblock.dbuf.linkflag == '1')
444: return;
445: blocks = stbuf.st_size;
446: blocks += TBLOCK-1;
447: blocks /= TBLOCK;
448:
449: while (blocks-- > 0)
450: (void) readtbuf(&bufp, TBLOCK);
451: }
452:
453: putfile(longname, shortname, parent)
454: char *longname;
455: char *shortname;
456: char *parent;
457: {
458: int infile = 0;
459: long blocks;
460: char buf[TBLOCK];
461: char *bigbuf;
462: register char *cp;
463: struct direct *dp;
464: DIR *dirp;
465: register int i;
466: long l;
467: char newparent[NAMSIZ+64];
468: extern int errno;
469: int maxread;
470: int hint; /* amount to write to get "in sync" */
471:
472: if (!hflag)
473: i = lstat(shortname, &stbuf);
474: else
475: i = stat(shortname, &stbuf);
476: if (i < 0) {
477: fprintf(stderr, "tar: ");
478: perror(longname);
479: return;
480: }
481: if (tfile != NULL && checkupdate(longname) == 0)
482: return;
483: if (checkw('r', longname) == 0)
484: return;
485: if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0)
486: return;
487:
488: switch (stbuf.st_mode & S_IFMT) {
489: case S_IFDIR:
490: for (i = 0, cp = buf; *cp++ = longname[i++];)
491: ;
492: *--cp = '/';
493: *++cp = 0 ;
494: if (!oflag) {
495: if ((cp - buf) >= NAMSIZ) {
496: fprintf(stderr, "tar: %s: file name too long\n",
497: longname);
498: return;
499: }
500: stbuf.st_size = 0;
501: tomodes(&stbuf);
502: strcpy(dblock.dbuf.name,buf);
503: sprintf(dblock.dbuf.chksum, "%6o", checksum());
504: (void) writetape((char *)&dblock);
505: }
506: sprintf(newparent, "%s/%s", parent, shortname);
507: if (chdir(shortname) < 0) {
508: perror(shortname);
509: return;
510: }
511: if ((dirp = opendir(".")) == NULL) {
512: fprintf(stderr, "tar: %s: directory read error\n",
513: longname);
514: if (chdir(parent) < 0) {
515: fprintf(stderr, "tar: cannot change back?: ");
516: perror(parent);
517: }
518: return;
519: }
520: while ((dp = readdir(dirp)) != NULL && !term) {
521: if (dp->d_ino == 0)
522: continue;
523: if (!strcmp(".", dp->d_name) ||
524: !strcmp("..", dp->d_name))
525: continue;
526: strcpy(cp, dp->d_name);
527: l = telldir(dirp);
528: closedir(dirp);
529: putfile(buf, cp, newparent);
530: dirp = opendir(".");
531: seekdir(dirp, l);
532: }
533: closedir(dirp);
534: if (chdir(parent) < 0) {
535: fprintf(stderr, "tar: cannot change back?: ");
536: perror(parent);
537: }
538: break;
539:
540: case S_IFLNK:
541: tomodes(&stbuf);
542: if (strlen(longname) >= NAMSIZ) {
543: fprintf(stderr, "tar: %s: file name too long\n",
544: longname);
545: return;
546: }
547: strcpy(dblock.dbuf.name, longname);
548: if (stbuf.st_size + 1 >= NAMSIZ) {
549: fprintf(stderr, "tar: %s: symbolic link too long\n",
550: longname);
551: return;
552: }
553: i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1);
554: if (i < 0) {
555: fprintf(stderr, "tar: can't read symbolic link ");
556: perror(longname);
557: return;
558: }
559: dblock.dbuf.linkname[i] = '\0';
560: dblock.dbuf.linkflag = '2';
561: if (vflag)
562: fprintf(vfile, "a %s symbolic link to %s\n",
563: longname, dblock.dbuf.linkname);
564: sprintf(dblock.dbuf.size, "%11lo", 0L);
565: sprintf(dblock.dbuf.chksum, "%6o", checksum());
566: (void) writetape((char *)&dblock);
567: break;
568:
569: case S_IFREG:
570: if ((infile = open(shortname, 0)) < 0) {
571: fprintf(stderr, "tar: ");
572: perror(longname);
573: return;
574: }
575: tomodes(&stbuf);
576: if (strlen(longname) >= NAMSIZ) {
577: fprintf(stderr, "tar: %s: file name too long\n",
578: longname);
579: close(infile);
580: return;
581: }
582: strcpy(dblock.dbuf.name, longname);
583: if (stbuf.st_nlink > 1) {
584: struct linkbuf *lp;
585: int found = 0;
586:
587: for (lp = ihead; lp != NULL; lp = lp->nextp)
588: if (lp->inum == stbuf.st_ino &&
589: lp->devnum == stbuf.st_dev) {
590: found++;
591: break;
592: }
593: if (found) {
594: strcpy(dblock.dbuf.linkname, lp->pathname);
595: dblock.dbuf.linkflag = '1';
596: sprintf(dblock.dbuf.chksum, "%6o", checksum());
597: (void) writetape( (char *) &dblock);
598: if (vflag)
599: fprintf(vfile, "a %s link to %s\n",
600: longname, lp->pathname);
601: lp->count--;
602: close(infile);
603: return;
604: }
605: lp = (struct linkbuf *) getmem(sizeof(*lp));
606: if (lp != NULL) {
607: lp->nextp = ihead;
608: ihead = lp;
609: lp->inum = stbuf.st_ino;
610: lp->devnum = stbuf.st_dev;
611: lp->count = stbuf.st_nlink - 1;
612: strcpy(lp->pathname, longname);
613: }
614: }
615: blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK;
616: if (vflag)
617: fprintf(vfile, "a %s %ld blocks\n", longname, blocks);
618: sprintf(dblock.dbuf.chksum, "%6o", checksum());
619: hint = writetape((char *)&dblock);
620: maxread = max(stbuf.st_blksize, (nblock * TBLOCK));
621: if ((bigbuf = malloc((unsigned)maxread)) == 0) {
622: maxread = TBLOCK;
623: bigbuf = buf;
624: }
625:
626: while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0
627: && blocks > 0) {
628: register int nblks;
629:
630: nblks = ((i-1)/TBLOCK)+1;
631: if (nblks > blocks)
632: nblks = blocks;
633: hint = writetbuf(bigbuf, nblks);
634: blocks -= nblks;
635: }
636: close(infile);
637: if (bigbuf != buf)
638: free(bigbuf);
639: if (i < 0) {
640: fprintf(stderr, "tar: Read error on ");
641: perror(longname);
642: } else if (blocks != 0 || i != 0)
643: fprintf(stderr, "tar: %s: file changed size\n",
644: longname);
645: while (--blocks >= 0)
646: putempty();
647: break;
648:
649: default:
650: fprintf(stderr, "tar: %s is not a file. Not dumped\n",
651: longname);
652: break;
653: }
654: }
655:
656: doxtract(argv)
657: char *argv[];
658: {
659: long blocks, bytes;
660: int ofile, i;
661: extern int errno;
662:
663: for (;;) {
664: if ((i = wantit(argv)) == 0)
665: continue;
666: if (i == -1)
667: break; /* end of tape */
668: if (checkw('x', dblock.dbuf.name) == 0) {
669: passtape();
670: continue;
671: }
672: if (Fflag) {
673: char *s;
674:
675: if ((s = rindex(dblock.dbuf.name, '/')) == 0)
676: s = dblock.dbuf.name;
677: else
678: s++;
679: if (checkf(s, stbuf.st_mode, Fflag) == 0) {
680: passtape();
681: continue;
682: }
683: }
684: if (checkdir(dblock.dbuf.name)) { /* have a directory */
685: if (mflag == 0)
686: dodirtimes(&dblock);
687: continue;
688: }
689: if (dblock.dbuf.linkflag == '2') { /* symlink */
690: /*
691: * only unlink non directories or empty
692: * directories
693: */
694: if (rmdir(dblock.dbuf.name) < 0) {
695: if (errno == ENOTDIR)
696: unlink(dblock.dbuf.name);
697: }
698: if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) {
699: fprintf(stderr, "tar: %s: symbolic link failed: ",
700: dblock.dbuf.name);
701: perror("");
702: continue;
703: }
704: if (vflag)
705: fprintf(vfile, "x %s symbolic link to %s\n",
706: dblock.dbuf.name, dblock.dbuf.linkname);
707: #ifdef notdef
708: /* ignore alien orders */
709: chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
710: if (mflag == 0)
711: setimes(dblock.dbuf.name, stbuf.st_mtime);
712: if (pflag)
713: chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
714: #endif
715: continue;
716: }
717: if (dblock.dbuf.linkflag == '1') { /* regular link */
718: /*
719: * only unlink non directories or empty
720: * directories
721: */
722: if (rmdir(dblock.dbuf.name) < 0) {
723: if (errno == ENOTDIR)
724: unlink(dblock.dbuf.name);
725: }
726: if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) {
727: fprintf(stderr, "tar: can't link %s to %s: ",
728: dblock.dbuf.name, dblock.dbuf.linkname);
729: perror("");
730: continue;
731: }
732: if (vflag)
733: fprintf(vfile, "%s linked to %s\n",
734: dblock.dbuf.name, dblock.dbuf.linkname);
735: continue;
736: }
737: if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) {
738: fprintf(stderr, "tar: can't create %s: ",
739: dblock.dbuf.name);
740: perror("");
741: passtape();
742: continue;
743: }
744: chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
745: blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK;
746: if (vflag)
747: fprintf(vfile, "x %s, %ld bytes, %ld tape blocks\n",
748: dblock.dbuf.name, bytes, blocks);
749: for (; blocks > 0;) {
750: register int nread;
751: char *bufp;
752: register int nwant;
753:
754: nwant = NBLOCK*TBLOCK;
755: if (nwant > (blocks*TBLOCK))
756: nwant = (blocks*TBLOCK);
757: nread = readtbuf(&bufp, nwant);
758: if (write(ofile, bufp, (int)min(nread, bytes)) < 0) {
759: fprintf(stderr,
760: "tar: %s: HELP - extract write error",
761: dblock.dbuf.name);
762: perror("");
763: done(2);
764: }
765: bytes -= nread;
766: blocks -= (((nread-1)/TBLOCK)+1);
767: }
768: close(ofile);
769: if (mflag == 0)
770: setimes(dblock.dbuf.name, stbuf.st_mtime);
771: if (pflag)
772: chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
773: }
774: if (mflag == 0) {
775: dblock.dbuf.name[0] = '\0'; /* process the whole stack */
776: dodirtimes(&dblock);
777: }
778: }
779:
780: dotable(argv)
781: char *argv[];
782: {
783: register int i;
784:
785: for (;;) {
786: if ((i = wantit(argv)) == 0)
787: continue;
788: if (i == -1)
789: break; /* end of tape */
790: if (vflag)
791: longt(&stbuf);
792: printf("%s", dblock.dbuf.name);
793: if (dblock.dbuf.linkflag == '1')
794: printf(" linked to %s", dblock.dbuf.linkname);
795: if (dblock.dbuf.linkflag == '2')
796: printf(" symbolic link to %s", dblock.dbuf.linkname);
797: printf("\n");
798: passtape();
799: }
800: }
801:
802: putempty()
803: {
804: char buf[TBLOCK];
805:
806: bzero(buf, sizeof (buf));
807: (void) writetape(buf);
808: }
809:
810: longt(st)
811: register struct stat *st;
812: {
813: register char *cp;
814: char *ctime();
815:
816: pmode(st);
817: printf("%3d/%1d", st->st_uid, st->st_gid);
818: printf("%7ld", st->st_size);
819: cp = ctime(&st->st_mtime);
820: printf(" %-12.12s %-4.4s ", cp+4, cp+20);
821: }
822:
823: #define SUID 04000
824: #define SGID 02000
825: #define ROWN 0400
826: #define WOWN 0200
827: #define XOWN 0100
828: #define RGRP 040
829: #define WGRP 020
830: #define XGRP 010
831: #define ROTH 04
832: #define WOTH 02
833: #define XOTH 01
834: #define STXT 01000
835: int m1[] = { 1, ROWN, 'r', '-' };
836: int m2[] = { 1, WOWN, 'w', '-' };
837: int m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
838: int m4[] = { 1, RGRP, 'r', '-' };
839: int m5[] = { 1, WGRP, 'w', '-' };
840: int m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
841: int m7[] = { 1, ROTH, 'r', '-' };
842: int m8[] = { 1, WOTH, 'w', '-' };
843: int m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
844:
845: int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
846:
847: pmode(st)
848: register struct stat *st;
849: {
850: register int **mp;
851:
852: for (mp = &m[0]; mp < &m[9];)
853: selectbits(*mp++, st);
854: }
855:
856: selectbits(pairp, st)
857: int *pairp;
858: struct stat *st;
859: {
860: register int n, *ap;
861:
862: ap = pairp;
863: n = *ap++;
864: while (--n>=0 && (st->st_mode&*ap++)==0)
865: ap++;
866: putchar(*ap);
867: }
868:
869: /*
870: * Make all directories needed by `name'. If `name' is itself
871: * a directory on the tar tape (indicated by a trailing '/'),
872: * return 1; else 0.
873: */
874: checkdir(name)
875: register char *name;
876: {
877: register char *cp;
878:
879: /*
880: * Quick check for existence of directory.
881: */
882: if ((cp = rindex(name, '/')) == 0)
883: return (0);
884: *cp = '\0';
885: if (access(name, 0) == 0) { /* already exists */
886: *cp = '/';
887: return (cp[1] == '\0'); /* return (lastchar == '/') */
888: }
889: *cp = '/';
890:
891: /*
892: * No luck, try to make all directories in path.
893: */
894: for (cp = name; *cp; cp++) {
895: if (*cp != '/')
896: continue;
897: *cp = '\0';
898: if (access(name, 0) < 0) {
899: if (mkdir(name, 0777) < 0) {
900: perror(name);
901: *cp = '/';
902: return (0);
903: }
904: chown(name, stbuf.st_uid, stbuf.st_gid);
905: if (pflag && cp[1] == '\0') /* dir on the tape */
906: chmod(name, stbuf.st_mode & 07777);
907: }
908: *cp = '/';
909: }
910: return (cp[-1]=='/');
911: }
912:
913: onintr()
914: {
915: (void) signal(SIGINT, SIG_IGN);
916: term++;
917: }
918:
919: onquit()
920: {
921: (void) signal(SIGQUIT, SIG_IGN);
922: term++;
923: }
924:
925: onhup()
926: {
927: (void) signal(SIGHUP, SIG_IGN);
928: term++;
929: }
930:
931: #ifdef notdef
932: onterm()
933: {
934: (void) signal(SIGTERM, SIG_IGN);
935: term++;
936: }
937: #endif
938:
939: tomodes(sp)
940: register struct stat *sp;
941: {
942: register char *cp;
943:
944: for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
945: *cp = '\0';
946: sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777);
947: sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid);
948: sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid);
949: sprintf(dblock.dbuf.size, "%11lo ", sp->st_size);
950: sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime);
951: }
952:
953: checksum()
954: {
955: register i;
956: register char *cp;
957:
958: for (cp = dblock.dbuf.chksum;
959: cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++)
960: *cp = ' ';
961: i = 0;
962: for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
963: i += *cp;
964: return (i);
965: }
966:
967: checkw(c, name)
968: char *name;
969: {
970: if (!wflag)
971: return (1);
972: printf("%c ", c);
973: if (vflag)
974: longt(&stbuf);
975: printf("%s: ", name);
976: return (response() == 'y');
977: }
978:
979: response()
980: {
981: char c;
982:
983: c = getchar();
984: if (c != '\n')
985: while (getchar() != '\n')
986: ;
987: else
988: c = 'n';
989: return (c);
990: }
991:
992: checkf(name, mode, howmuch)
993: char *name;
994: int mode, howmuch;
995: {
996: int l;
997:
998: if ((mode & S_IFMT) == S_IFDIR){
999: if ((strcmp(name, "SCCS")==0) || (strcmp(name, "RCS")==0))
1000: return(0);
1001: return(1);
1002: }
1003: if ((l = strlen(name)) < 3)
1004: return (1);
1005: if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o')
1006: return (0);
1007: if (strcmp(name, "core") == 0 ||
1008: strcmp(name, "errs") == 0 ||
1009: (howmuch > 1 && strcmp(name, "a.out") == 0))
1010: return (0);
1011: /* SHOULD CHECK IF IT IS EXECUTABLE */
1012: return (1);
1013: }
1014:
1015: /* Is the current file a new file, or the newest one of the same name? */
1016: checkupdate(arg)
1017: char *arg;
1018: {
1019: char name[100];
1020: long mtime;
1021: daddr_t seekp;
1022: daddr_t lookup();
1023:
1024: rewind(tfile);
1025: for (;;) {
1026: if ((seekp = lookup(arg)) < 0)
1027: return (1);
1028: fseek(tfile, seekp, 0);
1029: fscanf(tfile, "%s %lo", name, &mtime);
1030: return (stbuf.st_mtime > mtime);
1031: }
1032: }
1033:
1034: done(n)
1035: {
1036: unlink(tname);
1037: exit(n);
1038: }
1039:
1040: /*
1041: * Do we want the next entry on the tape, i.e. is it selected? If
1042: * not, skip over the entire entry. Return -1 if reached end of tape.
1043: */
1044: wantit(argv)
1045: char *argv[];
1046: {
1047: register char **cp;
1048:
1049: getdir();
1050: if (endtape())
1051: return (-1);
1052: if (*argv == 0)
1053: return (1);
1054: for (cp = argv; *cp; cp++)
1055: if (prefix(*cp, dblock.dbuf.name))
1056: return (1);
1057: passtape();
1058: return (0);
1059: }
1060:
1061: /*
1062: * Does s2 begin with the string s1, on a directory boundary?
1063: */
1064: prefix(s1, s2)
1065: register char *s1, *s2;
1066: {
1067: while (*s1)
1068: if (*s1++ != *s2++)
1069: return (0);
1070: if (*s2)
1071: return (*s2 == '/');
1072: return (1);
1073: }
1074:
1075: #define N 200
1076: int njab;
1077:
1078: daddr_t
1079: lookup(s)
1080: char *s;
1081: {
1082: register i;
1083: daddr_t a;
1084:
1085: for(i=0; s[i]; i++)
1086: if (s[i] == ' ')
1087: break;
1088: a = bsrch(s, i, low, high);
1089: return (a);
1090: }
1091:
1092: daddr_t
1093: bsrch(s, n, l, h)
1094: daddr_t l, h;
1095: char *s;
1096: {
1097: register i, j;
1098: char b[N];
1099: daddr_t m, m1;
1100:
1101: njab = 0;
1102:
1103: loop:
1104: if (l >= h)
1105: return ((daddr_t) -1);
1106: m = l + (h-l)/2 - N/2;
1107: if (m < l)
1108: m = l;
1109: fseek(tfile, m, 0);
1110: fread(b, 1, N, tfile);
1111: njab++;
1112: for(i=0; i<N; i++) {
1113: if (b[i] == '\n')
1114: break;
1115: m++;
1116: }
1117: if (m >= h)
1118: return ((daddr_t) -1);
1119: m1 = m;
1120: j = i;
1121: for(i++; i<N; i++) {
1122: m1++;
1123: if (b[i] == '\n')
1124: break;
1125: }
1126: i = cmp(b+j, s, n);
1127: if (i < 0) {
1128: h = m;
1129: goto loop;
1130: }
1131: if (i > 0) {
1132: l = m1;
1133: goto loop;
1134: }
1135: return (m);
1136: }
1137:
1138: cmp(b, s, n)
1139: char *b, *s;
1140: {
1141: register i;
1142:
1143: if (b[0] != '\n')
1144: exit(2);
1145: for(i=0; i<n; i++) {
1146: if (b[i+1] > s[i])
1147: return (-1);
1148: if (b[i+1] < s[i])
1149: return (1);
1150: }
1151: return (b[i+1] == ' '? 0 : -1);
1152: }
1153:
1154: readtape(buffer)
1155: char *buffer;
1156: {
1157: char *bufp;
1158:
1159: if (first == 0)
1160: getbuf();
1161: (void) readtbuf(&bufp, TBLOCK);
1162: bcopy(bufp, buffer, TBLOCK);
1163: return(TBLOCK);
1164: }
1165:
1166: readtbuf(bufpp, size)
1167: char **bufpp;
1168: int size;
1169: {
1170: register int i;
1171:
1172: if (recno >= nblock || first == 0) {
1173: if ((i = bread(mt, (char *)tbuf, TBLOCK*nblock)) < 0)
1174: mterr("read", i, 3);
1175: if (first == 0) {
1176: if ((i % TBLOCK) != 0) {
1177: fprintf(stderr, "tar: tape blocksize error\n");
1178: done(3);
1179: }
1180: i /= TBLOCK;
1181: if (i != nblock) {
1182: fprintf(stderr, "tar: blocksize = %d\n", i);
1183: nblock = i;
1184: }
1185: first = 1;
1186: }
1187: recno = 0;
1188: }
1189: if (size > ((nblock-recno)*TBLOCK))
1190: size = (nblock-recno)*TBLOCK;
1191: *bufpp = (char *)&tbuf[recno];
1192: recno += (size/TBLOCK);
1193: return (size);
1194: }
1195:
1196: writetbuf(buffer, n)
1197: register char *buffer;
1198: register int n;
1199: {
1200: int i;
1201:
1202: if (first == 0) {
1203: getbuf();
1204: first = 1;
1205: }
1206: if (recno >= nblock) {
1207: i = write(mt, (char *)tbuf, TBLOCK*nblock);
1208: if (i != TBLOCK*nblock)
1209: mterr("write", i, 2);
1210: recno = 0;
1211: }
1212:
1213: /*
1214: * Special case: We have an empty tape buffer, and the
1215: * users data size is >= the tape block size: Avoid
1216: * the bcopy and dma direct to tape. BIG WIN. Add the
1217: * residual to the tape buffer.
1218: */
1219: while (recno == 0 && n >= nblock) {
1220: i = write(mt, buffer, TBLOCK*nblock);
1221: if (i != TBLOCK*nblock)
1222: mterr("write", i, 2);
1223: n -= nblock;
1224: buffer += (nblock * TBLOCK);
1225: }
1226:
1227: while (n-- > 0) {
1228: bcopy(buffer, (char *)&tbuf[recno++], TBLOCK);
1229: buffer += TBLOCK;
1230: if (recno >= nblock) {
1231: i = write(mt, (char *)tbuf, TBLOCK*nblock);
1232: if (i != TBLOCK*nblock)
1233: mterr("write", i, 2);
1234: recno = 0;
1235: }
1236: }
1237:
1238: /* Tell the user how much to write to get in sync */
1239: return (nblock - recno);
1240: }
1241:
1242: backtape()
1243: {
1244: static int mtdev = 1;
1245: static struct mtop mtop = {MTBSR, 1};
1246: struct mtget mtget;
1247:
1248: if (mtdev == 1)
1249: mtdev = ioctl(mt, MTIOCGET, (char *)&mtget);
1250: if (mtdev == 0) {
1251: if (ioctl(mt, MTIOCTOP, (char *)&mtop) < 0) {
1252: fprintf(stderr, "tar: tape backspace error: ");
1253: perror("");
1254: done(4);
1255: }
1256: } else
1257: lseek(mt, (daddr_t) -TBLOCK*nblock, 1);
1258: recno--;
1259: }
1260:
1261: flushtape()
1262: {
1263: int i;
1264:
1265: i = write(mt, (char *)tbuf, TBLOCK*nblock);
1266: if (i != TBLOCK*nblock)
1267: mterr("write", i, 2);
1268: }
1269:
1270: mterr(operation, i, exitcode)
1271: char *operation;
1272: int i;
1273: {
1274: fprintf(stderr, "tar: tape %s error: ", operation);
1275: if (i < 0)
1276: perror("");
1277: else
1278: fprintf(stderr, "unexpected EOF\n");
1279: done(exitcode);
1280: }
1281:
1282: bread(fd, buf, size)
1283: int fd;
1284: char *buf;
1285: int size;
1286: {
1287: int count;
1288: static int lastread = 0;
1289:
1290: if (!Bflag)
1291: return (read(fd, buf, size));
1292:
1293: for (count = 0; count < size; count += lastread) {
1294: lastread = read(fd, buf, size - count);
1295: if (lastread <= 0) {
1296: if (count > 0)
1297: return (count);
1298: return (lastread);
1299: }
1300: buf += lastread;
1301: }
1302: return (count);
1303: }
1304:
1305: char *
1306: getcwd(buf)
1307: char *buf;
1308: {
1309: if (getwd(buf) == NULL) {
1310: fprintf(stderr, "tar: %s\n", buf);
1311: exit(1);
1312: }
1313: return (buf);
1314: }
1315:
1316: getbuf()
1317: {
1318:
1319: if (nblock == 0) {
1320: fstat(mt, &stbuf);
1321: if ((stbuf.st_mode & S_IFMT) == S_IFCHR)
1322: nblock = NBLOCK;
1323: else {
1324: nblock = stbuf.st_blksize / TBLOCK;
1325: if (nblock == 0)
1326: nblock = NBLOCK;
1327: }
1328: }
1329: tbuf = (union hblock *)malloc((unsigned)nblock*TBLOCK);
1330: if (tbuf == NULL) {
1331: fprintf(stderr, "tar: blocksize %d too big, can't get memory\n",
1332: nblock);
1333: done(1);
1334: }
1335: }
1336:
1337: /*
1338: * Save this directory and its mtime on the stack, popping and setting
1339: * the mtimes of any stacked dirs which aren't parents of this one.
1340: * A null directory causes the entire stack to be unwound and set.
1341: *
1342: * Since all the elements of the directory "stack" share a common
1343: * prefix, we can make do with one string. We keep only the current
1344: * directory path, with an associated array of mtime's, one for each
1345: * '/' in the path. A negative mtime means no mtime. The mtime's are
1346: * offset by one (first index 1, not 0) because calling this with a null
1347: * directory causes mtime[0] to be set.
1348: *
1349: * This stack algorithm is not guaranteed to work for tapes created
1350: * with the 'r' option, but the vast majority of tapes with
1351: * directories are not. This avoids saving every directory record on
1352: * the tape and setting all the times at the end.
1353: */
1354: char dirstack[NAMSIZ];
1355: #define NTIM (NAMSIZ/2+1) /* a/b/c/d/... */
1356: time_t mtime[NTIM];
1357:
1358: dodirtimes(hp)
1359: union hblock *hp;
1360: {
1361: register char *p = dirstack;
1362: register char *q = hp->dbuf.name;
1363: register int ndir = 0;
1364: char *savp;
1365: int savndir;
1366:
1367: /* Find common prefix */
1368: while (*p == *q) {
1369: if (*p++ == '/')
1370: ++ndir;
1371: q++;
1372: }
1373:
1374: savp = p;
1375: savndir = ndir;
1376: while (*p) {
1377: /*
1378: * Not a child: unwind the stack, setting the times.
1379: * The order we do this doesn't matter, so we go "forward."
1380: */
1381: if (*p++ == '/')
1382: if (mtime[++ndir] >= 0) {
1383: *--p = '\0'; /* zap the slash */
1384: setimes(dirstack, mtime[ndir]);
1385: *p++ = '/';
1386: }
1387: }
1388: p = savp;
1389: ndir = savndir;
1390:
1391: /* Push this one on the "stack" */
1392: while (*p = *q++) /* append the rest of the new dir */
1393: if (*p++ == '/')
1394: mtime[++ndir] = -1;
1395: mtime[ndir] = stbuf.st_mtime; /* overwrite the last one */
1396: }
1397:
1398: setimes(path, mt)
1399: char *path;
1400: time_t mt;
1401: {
1402: struct timeval tv[2];
1403:
1404: tv[0].tv_sec = time((time_t *) 0);
1405: tv[1].tv_sec = mt;
1406: tv[0].tv_usec = tv[1].tv_usec = 0;
1407: if (utimes(path, tv) < 0) {
1408: fprintf(stderr, "tar: can't set time on %s: ", path);
1409: perror("");
1410: }
1411: }
1412:
1413: char *
1414: getmem(size)
1415: {
1416: char *p = malloc((unsigned) size);
1417:
1418: if (p == NULL && freemem) {
1419: fprintf(stderr,
1420: "tar: out of memory, link and directory modtime info lost\n");
1421: freemem = 0;
1422: }
1423: return (p);
1424: }