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