xref: /original-bsd/old/tar/tar.c (revision 549425d7)
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.14 (Berkeley) 05/08/89";
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 #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 }
1427