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