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