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