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