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