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: parent = wdir;
365: for (cp = *argv; *cp; cp++)
366: if (*cp == '/')
367: cp2 = cp;
368: if (cp2 != *argv) {
369: *cp2 = '\0';
370: if (chdir(*argv) < 0) {
371: fprintf(stderr, "tar: can't change directories to ");
372: perror(*argv);
373: continue;
374: }
375: parent = getcwd(tempdir);
376: *cp2 = '/';
377: cp2++;
378: }
379: putfile(*argv++, cp2, parent);
380: if (chdir(wdir) < 0) {
381: fprintf(stderr, "tar: cannot change back?: ");
382: perror(wdir);
383: }
384: }
385: putempty();
386: putempty();
387: flushtape();
388: if (prtlinkerr == 0)
389: return;
390: for (; ihead != NULL; ihead = ihead->nextp) {
391: if (ihead->count == 0)
392: continue;
393: fprintf(stderr, "tar: missing links to %s\n", ihead->pathname);
394: }
395: }
396:
397: endtape()
398: {
399: return (dblock.dbuf.name[0] == '\0');
400: }
401:
402: getdir()
403: {
404: register struct stat *sp;
405: int i;
406:
407: top:
408: readtape((char *)&dblock);
409: if (dblock.dbuf.name[0] == '\0')
410: return;
411: sp = &stbuf;
412: sscanf(dblock.dbuf.mode, "%o", &i);
413: sp->st_mode = i;
414: sscanf(dblock.dbuf.uid, "%o", &i);
415: sp->st_uid = i;
416: sscanf(dblock.dbuf.gid, "%o", &i);
417: sp->st_gid = i;
418: sscanf(dblock.dbuf.size, "%lo", &sp->st_size);
419: sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime);
420: sscanf(dblock.dbuf.chksum, "%o", &chksum);
421: if (chksum != (i = checksum())) {
422: fprintf(stderr, "tar: directory checksum error (%d != %d)\n",
423: chksum, i);
424: if (iflag)
425: goto top;
426: done(2);
427: }
428: if (tfile != NULL)
429: fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime);
430: }
431:
432: passtape()
433: {
434: long blocks;
435: char *bufp;
436:
437: if (dblock.dbuf.linkflag == '1')
438: return;
439: blocks = stbuf.st_size;
440: blocks += TBLOCK-1;
441: blocks /= TBLOCK;
442:
443: while (blocks-- > 0)
444: (void) readtbuf(&bufp, TBLOCK);
445: }
446:
447: putfile(longname, shortname, parent)
448: char *longname;
449: char *shortname;
450: char *parent;
451: {
452: int infile = 0;
453: long blocks;
454: char buf[TBLOCK];
455: char *bigbuf;
456: register char *cp;
457: struct direct *dp;
458: DIR *dirp;
459: register int i;
460: long l;
461: char newparent[NAMSIZ+64];
462: extern int errno;
463: int maxread;
464: int hint; /* amount to write to get "in sync" */
465:
466: if (!hflag)
467: i = lstat(shortname, &stbuf);
468: else
469: i = stat(shortname, &stbuf);
470: if (i < 0) {
471: fprintf(stderr, "tar: ");
472: perror(longname);
473: return;
474: }
475: if (tfile != NULL && checkupdate(longname) == 0)
476: return;
477: if (checkw('r', longname) == 0)
478: return;
479: if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0)
480: return;
481:
482: switch (stbuf.st_mode & S_IFMT) {
483: case S_IFDIR:
484: for (i = 0, cp = buf; *cp++ = longname[i++];)
485: ;
486: *--cp = '/';
487: *++cp = 0 ;
488: if (!oflag) {
489: if ((cp - buf) >= NAMSIZ) {
490: fprintf(stderr, "tar: %s: file name too long\n",
491: longname);
492: return;
493: }
494: stbuf.st_size = 0;
495: tomodes(&stbuf);
496: strcpy(dblock.dbuf.name,buf);
497: sprintf(dblock.dbuf.chksum, "%6o", checksum());
498: (void) writetape((char *)&dblock);
499: }
500: sprintf(newparent, "%s/%s", parent, shortname);
501: if (chdir(shortname) < 0) {
502: perror(shortname);
503: return;
504: }
505: if ((dirp = opendir(".")) == NULL) {
506: fprintf(stderr, "tar: %s: directory read error\n",
507: longname);
508: if (chdir(parent) < 0) {
509: fprintf(stderr, "tar: cannot change back?: ");
510: perror(parent);
511: }
512: return;
513: }
514: while ((dp = readdir(dirp)) != NULL && !term) {
515: if (dp->d_ino == 0)
516: continue;
517: if (!strcmp(".", dp->d_name) ||
518: !strcmp("..", dp->d_name))
519: continue;
520: strcpy(cp, dp->d_name);
521: l = telldir(dirp);
522: closedir(dirp);
523: putfile(buf, cp, newparent);
524: dirp = opendir(".");
525: seekdir(dirp, l);
526: }
527: closedir(dirp);
528: if (chdir(parent) < 0) {
529: fprintf(stderr, "tar: cannot change back?: ");
530: perror(parent);
531: }
532: break;
533:
534: case S_IFLNK:
535: tomodes(&stbuf);
536: if (strlen(longname) >= NAMSIZ) {
537: fprintf(stderr, "tar: %s: file name too long\n",
538: longname);
539: return;
540: }
541: strcpy(dblock.dbuf.name, longname);
542: if (stbuf.st_size + 1 >= NAMSIZ) {
543: fprintf(stderr, "tar: %s: symbolic link too long\n",
544: longname);
545: return;
546: }
547: i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1);
548: if (i < 0) {
549: fprintf(stderr, "tar: can't read symbolic link ");
550: perror(longname);
551: return;
552: }
553: dblock.dbuf.linkname[i] = '\0';
554: dblock.dbuf.linkflag = '2';
555: if (vflag)
556: fprintf(vfile, "a %s symbolic link to %s\n",
557: longname, dblock.dbuf.linkname);
558: sprintf(dblock.dbuf.size, "%11lo", 0);
559: sprintf(dblock.dbuf.chksum, "%6o", checksum());
560: (void) writetape((char *)&dblock);
561: break;
562:
563: case S_IFREG:
564: if ((infile = open(shortname, 0)) < 0) {
565: fprintf(stderr, "tar: ");
566: perror(longname);
567: return;
568: }
569: tomodes(&stbuf);
570: if (strlen(longname) >= NAMSIZ) {
571: fprintf(stderr, "tar: %s: file name too long\n",
572: longname);
573: close(infile);
574: return;
575: }
576: strcpy(dblock.dbuf.name, longname);
577: if (stbuf.st_nlink > 1) {
578: struct linkbuf *lp;
579: int found = 0;
580:
581: for (lp = ihead; lp != NULL; lp = lp->nextp)
582: if (lp->inum == stbuf.st_ino &&
583: lp->devnum == stbuf.st_dev) {
584: found++;
585: break;
586: }
587: if (found) {
588: strcpy(dblock.dbuf.linkname, lp->pathname);
589: dblock.dbuf.linkflag = '1';
590: sprintf(dblock.dbuf.chksum, "%6o", checksum());
591: (void) writetape( (char *) &dblock);
592: if (vflag)
593: fprintf(vfile, "a %s link to %s\n",
594: longname, lp->pathname);
595: lp->count--;
596: close(infile);
597: return;
598: }
599: lp = (struct linkbuf *) getmem(sizeof(*lp));
600: if (lp != NULL) {
601: lp->nextp = ihead;
602: ihead = lp;
603: lp->inum = stbuf.st_ino;
604: lp->devnum = stbuf.st_dev;
605: lp->count = stbuf.st_nlink - 1;
606: strcpy(lp->pathname, longname);
607: }
608: }
609: blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK;
610: if (vflag)
611: fprintf(vfile, "a %s %ld blocks\n", longname, blocks);
612: sprintf(dblock.dbuf.chksum, "%6o", checksum());
613: hint = writetape((char *)&dblock);
614: maxread = max(stbuf.st_blksize, (nblock * TBLOCK));
615: if ((bigbuf = malloc((unsigned)maxread)) == 0) {
616: maxread = TBLOCK;
617: bigbuf = buf;
618: }
619:
620: while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0
621: && blocks > 0) {
622: register int nblks;
623:
624: nblks = ((i-1)/TBLOCK)+1;
625: if (nblks > blocks)
626: nblks = blocks;
627: hint = writetbuf(bigbuf, nblks);
628: blocks -= nblks;
629: }
630: close(infile);
631: if (bigbuf != buf)
632: free(bigbuf);
633: if (i < 0) {
634: fprintf(stderr, "tar: Read error on ");
635: perror(longname);
636: } else if (blocks != 0 || i != 0)
637: fprintf(stderr, "tar: %s: file changed size\n",
638: longname);
639: while (--blocks >= 0)
640: putempty();
641: break;
642:
643: default:
644: fprintf(stderr, "tar: %s is not a file. Not dumped\n",
645: longname);
646: break;
647: }
648: }
649:
650: doxtract(argv)
651: char *argv[];
652: {
653: long blocks, bytes;
654: int ofile, i;
655:
656: for (;;) {
657: if ((i = wantit(argv)) == 0)
658: continue;
659: if (i == -1)
660: break; /* end of tape */
661: if (checkw('x', dblock.dbuf.name) == 0) {
662: passtape();
663: continue;
664: }
665: if (Fflag) {
666: char *s;
667:
668: if ((s = rindex(dblock.dbuf.name, '/')) == 0)
669: s = dblock.dbuf.name;
670: else
671: s++;
672: if (checkf(s, stbuf.st_mode, Fflag) == 0) {
673: passtape();
674: continue;
675: }
676: }
677: if (checkdir(dblock.dbuf.name)) { /* have a directory */
678: if (mflag == 0)
679: dodirtimes(&dblock);
680: continue;
681: }
682: if (dblock.dbuf.linkflag == '2') { /* symlink */
683: /*
684: * only unlink non directories or empty
685: * directories
686: */
687: if (rmdir(dblock.dbuf.name) < 0) {
688: if (errno == ENOTDIR)
689: unlink(dblock.dbuf.name);
690: }
691: if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) {
692: fprintf(stderr, "tar: %s: symbolic link failed: ",
693: dblock.dbuf.name);
694: perror("");
695: continue;
696: }
697: if (vflag)
698: fprintf(vfile, "x %s symbolic link to %s\n",
699: dblock.dbuf.name, dblock.dbuf.linkname);
700: #ifdef notdef
701: /* ignore alien orders */
702: chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
703: if (mflag == 0)
704: setimes(dblock.dbuf.name, stbuf.st_mtime);
705: if (pflag)
706: chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
707: #endif
708: continue;
709: }
710: if (dblock.dbuf.linkflag == '1') { /* regular link */
711: /*
712: * only unlink non directories or empty
713: * directories
714: */
715: if (rmdir(dblock.dbuf.name) < 0) {
716: if (errno == ENOTDIR)
717: unlink(dblock.dbuf.name);
718: }
719: if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) {
720: fprintf(stderr, "tar: can't link %s to %s: ",
721: dblock.dbuf.name, dblock.dbuf.linkname);
722: perror("");
723: continue;
724: }
725: if (vflag)
726: fprintf(vfile, "%s linked to %s\n",
727: dblock.dbuf.name, dblock.dbuf.linkname);
728: continue;
729: }
730: if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) {
731: fprintf(stderr, "tar: can't create %s: ",
732: dblock.dbuf.name);
733: perror("");
734: passtape();
735: continue;
736: }
737: chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
738: blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK;
739: if (vflag)
740: fprintf(vfile, "x %s, %ld bytes, %ld tape blocks\n",
741: dblock.dbuf.name, bytes, blocks);
742: for (; blocks > 0;) {
743: register int nread;
744: char *bufp;
745: register int nwant;
746:
747: nwant = NBLOCK*TBLOCK;
748: if (nwant > (blocks*TBLOCK))
749: nwant = (blocks*TBLOCK);
750: nread = readtbuf(&bufp, nwant);
751: if (write(ofile, bufp, (int)min(nread, bytes)) < 0) {
752: fprintf(stderr,
753: "tar: %s: HELP - extract write error",
754: dblock.dbuf.name);
755: perror("");
756: done(2);
757: }
758: bytes -= nread;
759: blocks -= (((nread-1)/TBLOCK)+1);
760: }
761: close(ofile);
762: if (mflag == 0)
763: setimes(dblock.dbuf.name, stbuf.st_mtime);
764: if (pflag)
765: chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
766: }
767: if (mflag == 0) {
768: dblock.dbuf.name[0] = '\0'; /* process the whole stack */
769: dodirtimes(&dblock);
770: }
771: }
772:
773: dotable(argv)
774: char *argv[];
775: {
776: register int i;
777:
778: for (;;) {
779: if ((i = wantit(argv)) == 0)
780: continue;
781: if (i == -1)
782: break; /* end of tape */
783: if (vflag)
784: longt(&stbuf);
785: printf("%s", dblock.dbuf.name);
786: if (dblock.dbuf.linkflag == '1')
787: printf(" linked to %s", dblock.dbuf.linkname);
788: if (dblock.dbuf.linkflag == '2')
789: printf(" symbolic link to %s", dblock.dbuf.linkname);
790: printf("\n");
791: passtape();
792: }
793: }
794:
795: putempty()
796: {
797: char buf[TBLOCK];
798:
799: bzero(buf, sizeof (buf));
800: (void) writetape(buf);
801: }
802:
803: longt(st)
804: register struct stat *st;
805: {
806: register char *cp;
807: char *ctime();
808:
809: pmode(st);
810: printf("%3d/%1d", st->st_uid, st->st_gid);
811: printf("%7ld", st->st_size);
812: cp = ctime(&st->st_mtime);
813: printf(" %-12.12s %-4.4s ", cp+4, cp+20);
814: }
815:
816: #define SUID 04000
817: #define SGID 02000
818: #define ROWN 0400
819: #define WOWN 0200
820: #define XOWN 0100
821: #define RGRP 040
822: #define WGRP 020
823: #define XGRP 010
824: #define ROTH 04
825: #define WOTH 02
826: #define XOTH 01
827: #define STXT 01000
828: int m1[] = { 1, ROWN, 'r', '-' };
829: int m2[] = { 1, WOWN, 'w', '-' };
830: int m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
831: int m4[] = { 1, RGRP, 'r', '-' };
832: int m5[] = { 1, WGRP, 'w', '-' };
833: int m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
834: int m7[] = { 1, ROTH, 'r', '-' };
835: int m8[] = { 1, WOTH, 'w', '-' };
836: int m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
837:
838: int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
839:
840: pmode(st)
841: register struct stat *st;
842: {
843: register int **mp;
844:
845: for (mp = &m[0]; mp < &m[9];)
846: selectbits(*mp++, st);
847: }
848:
849: selectbits(pairp, st)
850: int *pairp;
851: struct stat *st;
852: {
853: register int n, *ap;
854:
855: ap = pairp;
856: n = *ap++;
857: while (--n>=0 && (st->st_mode&*ap++)==0)
858: ap++;
859: putchar(*ap);
860: }
861:
862: /*
863: * Make all directories needed by `name'. If `name' is itself
864: * a directory on the tar tape (indicated by a trailing '/'),
865: * return 1; else 0.
866: */
867: checkdir(name)
868: register char *name;
869: {
870: register char *cp;
871:
872: /*
873: * Quick check for existence of directory.
874: */
875: if ((cp = rindex(name, '/')) == 0)
876: return (0);
877: *cp = '\0';
878: if (access(name, 0) == 0) { /* already exists */
879: *cp = '/';
880: return (cp[1] == '\0'); /* return (lastchar == '/') */
881: }
882: *cp = '/';
883:
884: /*
885: * No luck, try to make all directories in path.
886: */
887: for (cp = name; *cp; cp++) {
888: if (*cp != '/')
889: continue;
890: *cp = '\0';
891: if (access(name, 0) < 0) {
892: if (mkdir(name, 0777) < 0) {
893: perror(name);
894: *cp = '/';
895: return (0);
896: }
897: chown(name, stbuf.st_uid, stbuf.st_gid);
898: if (pflag && cp[1] == '\0') /* dir on the tape */
899: chmod(name, stbuf.st_mode & 07777);
900: }
901: *cp = '/';
902: }
903: return (cp[-1]=='/');
904: }
905:
906: onintr()
907: {
908: (void) signal(SIGINT, SIG_IGN);
909: term++;
910: }
911:
912: onquit()
913: {
914: (void) signal(SIGQUIT, SIG_IGN);
915: term++;
916: }
917:
918: onhup()
919: {
920: (void) signal(SIGHUP, SIG_IGN);
921: term++;
922: }
923:
924: #ifdef notdef
925: onterm()
926: {
927: (void) signal(SIGTERM, SIG_IGN);
928: term++;
929: }
930: #endif
931:
932: tomodes(sp)
933: register struct stat *sp;
934: {
935: register char *cp;
936:
937: for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
938: *cp = '\0';
939: sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777);
940: sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid);
941: sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid);
942: sprintf(dblock.dbuf.size, "%11lo ", sp->st_size);
943: sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime);
944: }
945:
946: checksum()
947: {
948: register i;
949: register char *cp;
950:
951: for (cp = dblock.dbuf.chksum;
952: cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++)
953: *cp = ' ';
954: i = 0;
955: for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
956: i += *cp;
957: return (i);
958: }
959:
960: checkw(c, name)
961: char *name;
962: {
963: if (!wflag)
964: return (1);
965: printf("%c ", c);
966: if (vflag)
967: longt(&stbuf);
968: printf("%s: ", name);
969: return (response() == 'y');
970: }
971:
972: response()
973: {
974: char c;
975:
976: c = getchar();
977: if (c != '\n')
978: while (getchar() != '\n')
979: ;
980: else
981: c = 'n';
982: return (c);
983: }
984:
985: checkf(name, mode, howmuch)
986: char *name;
987: int mode, howmuch;
988: {
989: int l;
990:
991: if ((mode & S_IFMT) == S_IFDIR){
992: if ((strcmp(name, "SCCS")==0) || (strcmp(name, "RCS")==0))
993: return(0);
994: return(1);
995: }
996: if ((l = strlen(name)) < 3)
997: return (1);
998: if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o')
999: return (0);
1000: if (strcmp(name, "core") == 0 ||
1001: strcmp(name, "errs") == 0 ||
1002: (howmuch > 1 && strcmp(name, "a.out") == 0))
1003: return (0);
1004: /* SHOULD CHECK IF IT IS EXECUTABLE */
1005: return (1);
1006: }
1007:
1008: /* Is the current file a new file, or the newest one of the same name? */
1009: checkupdate(arg)
1010: char *arg;
1011: {
1012: char name[100];
1013: long mtime;
1014: daddr_t seekp;
1015: daddr_t lookup();
1016:
1017: rewind(tfile);
1018: for (;;) {
1019: if ((seekp = lookup(arg)) < 0)
1020: return (1);
1021: fseek(tfile, seekp, 0);
1022: fscanf(tfile, "%s %lo", name, &mtime);
1023: return (stbuf.st_mtime > mtime);
1024: }
1025: }
1026:
1027: done(n)
1028: {
1029: unlink(tname);
1030: exit(n);
1031: }
1032:
1033: /*
1034: * Do we want the next entry on the tape, i.e. is it selected? If
1035: * not, skip over the entire entry. Return -1 if reached end of tape.
1036: */
1037: wantit(argv)
1038: char *argv[];
1039: {
1040: register char **cp;
1041:
1042: getdir();
1043: if (endtape())
1044: return (-1);
1045: if (*argv == 0)
1046: return (1);
1047: for (cp = argv; *cp; cp++)
1048: if (prefix(*cp, dblock.dbuf.name))
1049: return (1);
1050: passtape();
1051: return (0);
1052: }
1053:
1054: /*
1055: * Does s2 begin with the string s1, on a directory boundary?
1056: */
1057: prefix(s1, s2)
1058: register char *s1, *s2;
1059: {
1060: while (*s1)
1061: if (*s1++ != *s2++)
1062: return (0);
1063: if (*s2)
1064: return (*s2 == '/');
1065: return (1);
1066: }
1067:
1068: #define N 200
1069: int njab;
1070:
1071: daddr_t
1072: lookup(s)
1073: char *s;
1074: {
1075: register i;
1076: daddr_t a;
1077:
1078: for(i=0; s[i]; i++)
1079: if (s[i] == ' ')
1080: break;
1081: a = bsrch(s, i, low, high);
1082: return (a);
1083: }
1084:
1085: daddr_t
1086: bsrch(s, n, l, h)
1087: daddr_t l, h;
1088: char *s;
1089: {
1090: register i, j;
1091: char b[N];
1092: daddr_t m, m1;
1093:
1094: njab = 0;
1095:
1096: loop:
1097: if (l >= h)
1098: return ((daddr_t) -1);
1099: m = l + (h-l)/2 - N/2;
1100: if (m < l)
1101: m = l;
1102: fseek(tfile, m, 0);
1103: fread(b, 1, N, tfile);
1104: njab++;
1105: for(i=0; i<N; i++) {
1106: if (b[i] == '\n')
1107: break;
1108: m++;
1109: }
1110: if (m >= h)
1111: return ((daddr_t) -1);
1112: m1 = m;
1113: j = i;
1114: for(i++; i<N; i++) {
1115: m1++;
1116: if (b[i] == '\n')
1117: break;
1118: }
1119: i = cmp(b+j, s, n);
1120: if (i < 0) {
1121: h = m;
1122: goto loop;
1123: }
1124: if (i > 0) {
1125: l = m1;
1126: goto loop;
1127: }
1128: return (m);
1129: }
1130:
1131: cmp(b, s, n)
1132: char *b, *s;
1133: {
1134: register i;
1135:
1136: if (b[0] != '\n')
1137: exit(2);
1138: for(i=0; i<n; i++) {
1139: if (b[i+1] > s[i])
1140: return (-1);
1141: if (b[i+1] < s[i])
1142: return (1);
1143: }
1144: return (b[i+1] == ' '? 0 : -1);
1145: }
1146:
1147: readtape(buffer)
1148: char *buffer;
1149: {
1150: char *bufp;
1151:
1152: if (first == 0)
1153: getbuf();
1154: (void) readtbuf(&bufp, TBLOCK);
1155: bcopy(bufp, buffer, TBLOCK);
1156: return(TBLOCK);
1157: }
1158:
1159: readtbuf(bufpp, size)
1160: char **bufpp;
1161: int size;
1162: {
1163: register int i;
1164:
1165: if (recno >= nblock || first == 0) {
1166: if ((i = bread(mt, (char *)tbuf, TBLOCK*nblock)) < 0)
1167: mterr("read", i, 3);
1168: if (first == 0) {
1169: if ((i % TBLOCK) != 0) {
1170: fprintf(stderr, "tar: tape blocksize error\n");
1171: done(3);
1172: }
1173: i /= TBLOCK;
1174: if (i != nblock) {
1175: fprintf(stderr, "tar: blocksize = %d\n", i);
1176: nblock = i;
1177: }
1178: first = 1;
1179: }
1180: recno = 0;
1181: }
1182: if (size > ((nblock-recno)*TBLOCK))
1183: size = (nblock-recno)*TBLOCK;
1184: *bufpp = (char *)&tbuf[recno];
1185: recno += (size/TBLOCK);
1186: return (size);
1187: }
1188:
1189: writetbuf(buffer, n)
1190: register char *buffer;
1191: register int n;
1192: {
1193: int i;
1194:
1195: if (first == 0) {
1196: getbuf();
1197: first = 1;
1198: }
1199: if (recno >= nblock) {
1200: i = write(mt, (char *)tbuf, TBLOCK*nblock);
1201: if (i != TBLOCK*nblock)
1202: mterr("write", i, 2);
1203: recno = 0;
1204: }
1205:
1206: /*
1207: * Special case: We have an empty tape buffer, and the
1208: * users data size is >= the tape block size: Avoid
1209: * the bcopy and dma direct to tape. BIG WIN. Add the
1210: * residual to the tape buffer.
1211: */
1212: while (recno == 0 && n >= nblock) {
1213: i = write(mt, buffer, TBLOCK*nblock);
1214: if (i != TBLOCK*nblock)
1215: mterr("write", i, 2);
1216: n -= nblock;
1217: buffer += (nblock * TBLOCK);
1218: }
1219:
1220: while (n-- > 0) {
1221: bcopy(buffer, (char *)&tbuf[recno++], TBLOCK);
1222: buffer += TBLOCK;
1223: if (recno >= nblock) {
1224: i = write(mt, (char *)tbuf, TBLOCK*nblock);
1225: if (i != TBLOCK*nblock)
1226: mterr("write", i, 2);
1227: recno = 0;
1228: }
1229: }
1230:
1231: /* Tell the user how much to write to get in sync */
1232: return (nblock - recno);
1233: }
1234:
1235: backtape()
1236: {
1237: static int mtdev = 1;
1238: static struct mtop mtop = {MTBSR, 1};
1239: struct mtget mtget;
1240:
1241: if (mtdev == 1)
1242: mtdev = ioctl(mt, MTIOCGET, (char *)&mtget);
1243: if (mtdev == 0) {
1244: if (ioctl(mt, MTIOCTOP, (char *)&mtop) < 0) {
1245: fprintf(stderr, "tar: tape backspace error: ");
1246: perror("");
1247: done(4);
1248: }
1249: } else
1250: lseek(mt, (daddr_t) -TBLOCK*nblock, 1);
1251: recno--;
1252: }
1253:
1254: flushtape()
1255: {
1256: int i;
1257:
1258: i = write(mt, (char *)tbuf, TBLOCK*nblock);
1259: if (i != TBLOCK*nblock)
1260: mterr("write", i, 2);
1261: }
1262:
1263: mterr(operation, i, exitcode)
1264: char *operation;
1265: int i;
1266: {
1267: fprintf(stderr, "tar: tape %s error: ", operation);
1268: if (i < 0)
1269: perror("");
1270: else
1271: fprintf(stderr, "unexpected EOF\n");
1272: done(exitcode);
1273: }
1274:
1275: bread(fd, buf, size)
1276: int fd;
1277: char *buf;
1278: int size;
1279: {
1280: int count;
1281: static int lastread = 0;
1282:
1283: if (!Bflag)
1284: return (read(fd, buf, size));
1285:
1286: for (count = 0; count < size; count += lastread) {
1287: lastread = read(fd, buf, size - count);
1288: if (lastread <= 0) {
1289: if (count > 0)
1290: return (count);
1291: return (lastread);
1292: }
1293: buf += lastread;
1294: }
1295: return (count);
1296: }
1297:
1298: char *
1299: getcwd(buf)
1300: char *buf;
1301: {
1302: if (getwd(buf) == NULL) {
1303: fprintf(stderr, "tar: %s\n", buf);
1304: exit(1);
1305: }
1306: return (buf);
1307: }
1308:
1309: getbuf()
1310: {
1311:
1312: if (nblock == 0) {
1313: fstat(mt, &stbuf);
1314: if ((stbuf.st_mode & S_IFMT) == S_IFCHR)
1315: nblock = NBLOCK;
1316: else {
1317: nblock = stbuf.st_blksize / TBLOCK;
1318: if (nblock == 0)
1319: nblock = NBLOCK;
1320: }
1321: }
1322: tbuf = (union hblock *)malloc((unsigned)nblock*TBLOCK);
1323: if (tbuf == NULL) {
1324: fprintf(stderr, "tar: blocksize %d too big, can't get memory\n",
1325: nblock);
1326: done(1);
1327: }
1328: }
1329:
1330: /*
1331: * Save this directory and its mtime on the stack, popping and setting
1332: * the mtimes of any stacked dirs which aren't parents of this one.
1333: * A null directory causes the entire stack to be unwound and set.
1334: *
1335: * Since all the elements of the directory "stack" share a common
1336: * prefix, we can make do with one string. We keep only the current
1337: * directory path, with an associated array of mtime's, one for each
1338: * '/' in the path. A negative mtime means no mtime. The mtime's are
1339: * offset by one (first index 1, not 0) because calling this with a null
1340: * directory causes mtime[0] to be set.
1341: *
1342: * This stack algorithm is not guaranteed to work for tapes created
1343: * with the 'r' option, but the vast majority of tapes with
1344: * directories are not. This avoids saving every directory record on
1345: * the tape and setting all the times at the end.
1346: */
1347: char dirstack[NAMSIZ];
1348: #define NTIM (NAMSIZ/2+1) /* a/b/c/d/... */
1349: time_t mtime[NTIM];
1350:
1351: dodirtimes(hp)
1352: union hblock *hp;
1353: {
1354: register char *p = dirstack;
1355: register char *q = hp->dbuf.name;
1356: register int ndir = 0;
1357: char *savp;
1358: int savndir;
1359:
1360: /* Find common prefix */
1361: while (*p == *q) {
1362: if (*p++ == '/')
1363: ++ndir;
1364: q++;
1365: }
1366:
1367: savp = p;
1368: savndir = ndir;
1369: while (*p) {
1370: /*
1371: * Not a child: unwind the stack, setting the times.
1372: * The order we do this doesn't matter, so we go "forward."
1373: */
1374: if (*p++ == '/')
1375: if (mtime[++ndir] >= 0) {
1376: *--p = '\0'; /* zap the slash */
1377: setimes(dirstack, mtime[ndir]);
1378: *p++ = '/';
1379: }
1380: }
1381: p = savp;
1382: ndir = savndir;
1383:
1384: /* Push this one on the "stack" */
1385: while (*p = *q++) /* append the rest of the new dir */
1386: if (*p++ == '/')
1387: mtime[++ndir] = -1;
1388: mtime[ndir] = stbuf.st_mtime; /* overwrite the last one */
1389: }
1390:
1391: setimes(path, mt)
1392: char *path;
1393: time_t mt;
1394: {
1395: struct timeval tv[2];
1396:
1397: tv[0].tv_sec = time((time_t *) 0);
1398: tv[1].tv_sec = mt;
1399: tv[0].tv_usec = tv[1].tv_usec = 0;
1400: if (utimes(path, tv) < 0) {
1401: fprintf(stderr, "tar: can't set time on %s: ", path);
1402: perror("");
1403: }
1404: }
1405:
1406: char *
1407: getmem(size)
1408: {
1409: char *p = malloc((unsigned) size);
1410:
1411: if (p == NULL && freemem) {
1412: fprintf(stderr,
1413: "tar: out of memory, link and directory modtime info lost\n");
1414: freemem = 0;
1415: }
1416: return (p);
1417: }