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