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