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