xref: /csrg-svn/old/tar/tar.c (revision 27442)
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.6 (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 char	*sprintf();
108 char	*strcat();
109 char	*strcpy();
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 		mt = openmt(usefile, 1);
258 		dorep(argv);
259 		done(0);
260 	}
261 	mt = openmt(usefile, 0);
262 	if (xflag)
263 		doxtract(argv);
264 	else
265 		dotable();
266 	done(0);
267 }
268 
269 usage()
270 {
271 	fprintf(stderr,
272 "tar: usage: tar -{txru}[cvfblmhopwBi] [tapefile] [blocksize] file1 file2...\n");
273 	done(1);
274 }
275 
276 int
277 openmt(tape, writing)
278 	char *tape;
279 	int writing;
280 {
281 	register char *rmtape;
282 	extern char *rmterr;
283 
284 	if (strcmp(tape, "-") == 0) {
285 		/*
286 		 * Read from standard input or write to standard output.
287 		 */
288 		if (writing) {
289 			if (cflag == 0) {
290 				fprintf(stderr,
291 			 "tar: can only create standard output archives\n");
292 				done(1);
293 			}
294 			vfile = stderr;
295 			setlinebuf(vfile);
296 			mt = dup(1);
297 		} else {
298 			mt = dup(0);
299 			Bflag++;
300 		}
301 	} else {
302 		/*
303 		 * Use file or tape on local machine.
304 		 */
305 		if (writing) {
306 			if (cflag)
307 				mt = open(tape, O_RDWR|O_CREAT|O_TRUNC,
308 				    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 		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 	int i;
460 	char newparent[NAMSIZ+64];
461 	extern int errno;
462 	int	maxread;
463 	int	hint;		/* amount to write to get "in sync" */
464 
465 	if (!hflag)
466 		i = lstat(shortname, &stbuf);
467 	else
468 		i = stat(shortname, &stbuf);
469 	if (i < 0) {
470 		fprintf(stderr, "tar: ");
471 		perror(longname);
472 		return;
473 	}
474 	if (tfile != NULL && checkupdate(longname) == 0)
475 		return;
476 	if (checkw('r', longname) == 0)
477 		return;
478 	if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0)
479 		return;
480 
481 	switch (stbuf.st_mode & S_IFMT) {
482 	case S_IFDIR:
483 		for (i = 0, cp = buf; *cp++ = longname[i++];)
484 			;
485 		*--cp = '/';
486 		*++cp = 0  ;
487 		if (!oflag) {
488 			if ((cp - buf) >= NAMSIZ) {
489 				fprintf(stderr, "tar: %s: file name too long\n",
490 				    longname);
491 				return;
492 			}
493 			stbuf.st_size = 0;
494 			tomodes(&stbuf);
495 			strcpy(dblock.dbuf.name,buf);
496 			sprintf(dblock.dbuf.chksum, "%6o", checksum());
497 			writetape((char *)&dblock);
498 		}
499 		sprintf(newparent, "%s/%s", parent, shortname);
500 		if (chdir(shortname) < 0) {
501 			perror(shortname);
502 			return;
503 		}
504 		if ((dirp = opendir(".")) == NULL) {
505 			fprintf(stderr, "tar: %s: directory read error\n",
506 			    longname);
507 			if (chdir(parent) < 0) {
508 				fprintf(stderr, "tar: cannot change back?: ");
509 				perror(parent);
510 			}
511 			return;
512 		}
513 		while ((dp = readdir(dirp)) != NULL && !term) {
514 			if (dp->d_ino == 0)
515 				continue;
516 			if (!strcmp(".", dp->d_name) ||
517 			    !strcmp("..", dp->d_name))
518 				continue;
519 			strcpy(cp, dp->d_name);
520 			i = telldir(dirp);
521 			closedir(dirp);
522 			putfile(buf, cp, newparent);
523 			dirp = opendir(".");
524 			seekdir(dirp, i);
525 		}
526 		closedir(dirp);
527 		if (chdir(parent) < 0) {
528 			fprintf(stderr, "tar: cannot change back?: ");
529 			perror(parent);
530 		}
531 		break;
532 
533 	case S_IFLNK:
534 		tomodes(&stbuf);
535 		if (strlen(longname) >= NAMSIZ) {
536 			fprintf(stderr, "tar: %s: file name too long\n",
537 			    longname);
538 			return;
539 		}
540 		strcpy(dblock.dbuf.name, longname);
541 		if (stbuf.st_size + 1 >= NAMSIZ) {
542 			fprintf(stderr, "tar: %s: symbolic link too long\n",
543 			    longname);
544 			return;
545 		}
546 		i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1);
547 		if (i < 0) {
548 			fprintf(stderr, "tar: can't read symbolic link ");
549 			perror(longname);
550 			return;
551 		}
552 		dblock.dbuf.linkname[i] = '\0';
553 		dblock.dbuf.linkflag = '2';
554 		if (vflag)
555 			fprintf(vfile, "a %s symbolic link to %s\n",
556 			    longname, dblock.dbuf.linkname);
557 		sprintf(dblock.dbuf.size, "%11lo", 0);
558 		sprintf(dblock.dbuf.chksum, "%6o", checksum());
559 		writetape((char *)&dblock);
560 		break;
561 
562 	case S_IFREG:
563 		if ((infile = open(shortname, 0)) < 0) {
564 			fprintf(stderr, "tar: ");
565 			perror(longname);
566 			return;
567 		}
568 		tomodes(&stbuf);
569 		if (strlen(longname) >= NAMSIZ) {
570 			fprintf(stderr, "tar: %s: file name too long\n",
571 			    longname);
572 			close(infile);
573 			return;
574 		}
575 		strcpy(dblock.dbuf.name, longname);
576 		if (stbuf.st_nlink > 1) {
577 			struct linkbuf *lp;
578 			int found = 0;
579 
580 			for (lp = ihead; lp != NULL; lp = lp->nextp)
581 				if (lp->inum == stbuf.st_ino &&
582 				    lp->devnum == stbuf.st_dev) {
583 					found++;
584 					break;
585 				}
586 			if (found) {
587 				strcpy(dblock.dbuf.linkname, lp->pathname);
588 				dblock.dbuf.linkflag = '1';
589 				sprintf(dblock.dbuf.chksum, "%6o", checksum());
590 				writetape( (char *) &dblock);
591 				if (vflag)
592 					fprintf(vfile, "a %s link to %s\n",
593 					    longname, lp->pathname);
594 				lp->count--;
595 				close(infile);
596 				return;
597 			}
598 			lp = (struct linkbuf *) getmem(sizeof(*lp));
599 			if (lp != NULL) {
600 				lp->nextp = ihead;
601 				ihead = lp;
602 				lp->inum = stbuf.st_ino;
603 				lp->devnum = stbuf.st_dev;
604 				lp->count = stbuf.st_nlink - 1;
605 				strcpy(lp->pathname, longname);
606 			}
607 		}
608 		blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK;
609 		if (vflag)
610 			fprintf(vfile, "a %s %ld blocks\n", longname, blocks);
611 		sprintf(dblock.dbuf.chksum, "%6o", checksum());
612 		hint = writetape((char *)&dblock);
613 		maxread = max(stbuf.st_blksize, (nblock * TBLOCK));
614 		if ((bigbuf = malloc(maxread)) == 0) {
615 			maxread = TBLOCK;
616 			bigbuf = buf;
617 		}
618 
619 		while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0
620 		  && blocks > 0) {
621 		  	register int nblks;
622 
623 			nblks = ((i-1)/TBLOCK)+1;
624 		  	if (nblks > blocks)
625 		  		nblks = blocks;
626 			hint = writetbuf(bigbuf, nblks);
627 			blocks -= nblks;
628 		}
629 		close(infile);
630 		if (bigbuf != buf)
631 			free(bigbuf);
632 		if (i < 0) {
633 			fprintf("tar: Read error on ");
634 			perror(longname);
635 		} else if (blocks != 0 || i != 0)
636 			fprintf(stderr, "tar: %s: file changed size\n",
637 			    longname);
638 		while (--blocks >=  0)
639 			putempty();
640 		break;
641 
642 	default:
643 		fprintf(stderr, "tar: %s is not a file. Not dumped\n",
644 		    longname);
645 		break;
646 	}
647 }
648 
649 doxtract(argv)
650 	char *argv[];
651 {
652 	long blocks, bytes;
653 	char **cp;
654 	int ofile;
655 
656 	for (;;) {
657 		getdir();
658 		if (endtape())
659 			break;
660 		if (*argv == 0)
661 			goto gotit;
662 		for (cp = argv; *cp; cp++)
663 			if (prefix(*cp, dblock.dbuf.name))
664 				goto gotit;
665 		passtape();
666 		continue;
667 
668 gotit:
669 		if (checkw('x', dblock.dbuf.name) == 0) {
670 			passtape();
671 			continue;
672 		}
673 		if (Fflag) {
674 			char *s;
675 
676 			if ((s = rindex(dblock.dbuf.name, '/')) == 0)
677 				s = dblock.dbuf.name;
678 			else
679 				s++;
680 			if (checkf(s, stbuf.st_mode, Fflag) == 0) {
681 				passtape();
682 				continue;
683 			}
684 		}
685 		if (checkdir(dblock.dbuf.name)) {	/* have a directory */
686 			if (mflag == 0)
687 				dodirtimes(&dblock);
688 			continue;
689 		}
690 		if (dblock.dbuf.linkflag == '2') {	/* symlink */
691 			/*
692 			 * only unlink non directories or empty
693 			 * directories
694 			 */
695 			if (rmdir(dblock.dbuf.name) < 0) {
696 				if (errno == ENOTDIR)
697 					unlink(dblock.dbuf.name);
698 			}
699 			if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) {
700 				fprintf(stderr, "tar: %s: symbolic link failed: ",
701 				    dblock.dbuf.name);
702 				perror("");
703 				continue;
704 			}
705 			if (vflag)
706 				fprintf(vfile, "x %s symbolic link to %s\n",
707 				    dblock.dbuf.name, dblock.dbuf.linkname);
708 #ifdef notdef
709 			/* ignore alien orders */
710 			chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
711 			if (mflag == 0)
712 				setimes(dblock.dbuf.name, stbuf.st_mtime);
713 			if (pflag)
714 				chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
715 #endif
716 			continue;
717 		}
718 		if (dblock.dbuf.linkflag == '1') {	/* regular link */
719 			/*
720 			 * only unlink non directories or empty
721 			 * directories
722 			 */
723 			if (rmdir(dblock.dbuf.name) < 0) {
724 				if (errno == ENOTDIR)
725 					unlink(dblock.dbuf.name);
726 			}
727 			if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) {
728 				fprintf(stderr, "tar: can't link %s to %s: ",
729 				    dblock.dbuf.name, dblock.dbuf.linkname);
730 				perror("");
731 				continue;
732 			}
733 			if (vflag)
734 				fprintf(vfile, "%s linked to %s\n",
735 				    dblock.dbuf.name, dblock.dbuf.linkname);
736 			continue;
737 		}
738 		if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) {
739 			fprintf(stderr, "tar: can't create %s: ",
740 			    dblock.dbuf.name);
741 			perror("");
742 			passtape();
743 			continue;
744 		}
745 		chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
746 		blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK;
747 		if (vflag)
748 			fprintf(vfile, "x %s, %ld bytes, %ld tape blocks\n",
749 			    dblock.dbuf.name, bytes, blocks);
750 		for (; blocks > 0;) {
751 			register int nread;
752 			char	*bufp;
753 			register int nwant;
754 
755 			nwant = NBLOCK*TBLOCK;
756 			if (nwant > (blocks*TBLOCK))
757 				nwant = (blocks*TBLOCK);
758 			nread = readtbuf(&bufp, nwant);
759 			if (write(ofile, bufp, (int)min(nread, bytes)) < 0) {
760 				fprintf(stderr,
761 				    "tar: %s: HELP - extract write error",
762 				    dblock.dbuf.name);
763 				perror("");
764 				done(2);
765 			}
766 			bytes -= nread;
767 			blocks -= (((nread-1)/TBLOCK)+1);
768 		}
769 		close(ofile);
770 		if (mflag == 0)
771 			setimes(dblock.dbuf.name, stbuf.st_mtime);
772 		if (pflag)
773 			chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
774 	}
775 	if (mflag == 0) {
776 		dblock.dbuf.name[0] = '\0';	/* process the whole stack */
777 		dodirtimes(&dblock);
778 	}
779 }
780 
781 dotable()
782 {
783 	for (;;) {
784 		getdir();
785 		if (endtape())
786 			break;
787 		if (vflag)
788 			longt(&stbuf);
789 		printf("%s", dblock.dbuf.name);
790 		if (dblock.dbuf.linkflag == '1')
791 			printf(" linked to %s", dblock.dbuf.linkname);
792 		if (dblock.dbuf.linkflag == '2')
793 			printf(" symbolic link to %s", dblock.dbuf.linkname);
794 		printf("\n");
795 		passtape();
796 	}
797 }
798 
799 putempty()
800 {
801 	char buf[TBLOCK];
802 
803 	bzero(buf, sizeof (buf));
804 	writetape(buf);
805 }
806 
807 longt(st)
808 	register struct stat *st;
809 {
810 	register char *cp;
811 	char *ctime();
812 
813 	pmode(st);
814 	printf("%3d/%1d", st->st_uid, st->st_gid);
815 	printf("%7D", st->st_size);
816 	cp = ctime(&st->st_mtime);
817 	printf(" %-12.12s %-4.4s ", cp+4, cp+20);
818 }
819 
820 #define	SUID	04000
821 #define	SGID	02000
822 #define	ROWN	0400
823 #define	WOWN	0200
824 #define	XOWN	0100
825 #define	RGRP	040
826 #define	WGRP	020
827 #define	XGRP	010
828 #define	ROTH	04
829 #define	WOTH	02
830 #define	XOTH	01
831 #define	STXT	01000
832 int	m1[] = { 1, ROWN, 'r', '-' };
833 int	m2[] = { 1, WOWN, 'w', '-' };
834 int	m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
835 int	m4[] = { 1, RGRP, 'r', '-' };
836 int	m5[] = { 1, WGRP, 'w', '-' };
837 int	m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
838 int	m7[] = { 1, ROTH, 'r', '-' };
839 int	m8[] = { 1, WOTH, 'w', '-' };
840 int	m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
841 
842 int	*m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
843 
844 pmode(st)
845 	register struct stat *st;
846 {
847 	register int **mp;
848 
849 	for (mp = &m[0]; mp < &m[9];)
850 		selectbits(*mp++, st);
851 }
852 
853 selectbits(pairp, st)
854 	int *pairp;
855 	struct stat *st;
856 {
857 	register int n, *ap;
858 
859 	ap = pairp;
860 	n = *ap++;
861 	while (--n>=0 && (st->st_mode&*ap++)==0)
862 		ap++;
863 	printf("%c", *ap);
864 }
865 
866 /*
867  * Make all directories needed by `name'.  If `name' is itself
868  * a directory on the tar tape (indicated by a trailing '/'),
869  * return 1; else 0.
870  */
871 checkdir(name)
872 	register char *name;
873 {
874 	register char *cp;
875 
876 	/*
877 	 * Quick check for existence of directory.
878 	 */
879 	if ((cp = rindex(name, '/')) == 0)
880 		return (0);
881 	*cp = '\0';
882 	if (access(name, 0) == 0) {	/* already exists */
883 		*cp = '/';
884 		return (cp[1] == '\0');	/* return (lastchar == '/') */
885 	}
886 	*cp = '/';
887 
888 	/*
889 	 * No luck, try to make all directories in path.
890 	 */
891 	for (cp = name; *cp; cp++) {
892 		if (*cp != '/')
893 			continue;
894 		*cp = '\0';
895 		if (access(name, 0) < 0) {
896 			if (mkdir(name, 0777) < 0) {
897 				perror(name);
898 				*cp = '/';
899 				return (0);
900 			}
901 			chown(name, stbuf.st_uid, stbuf.st_gid);
902 			if (pflag && cp[1] == '\0')	/* dir on the tape */
903 				chmod(name, stbuf.st_mode & 07777);
904 		}
905 		*cp = '/';
906 	}
907 	return (cp[-1]=='/');
908 }
909 
910 onintr()
911 {
912 	signal(SIGINT, SIG_IGN);
913 	term++;
914 }
915 
916 onquit()
917 {
918 	signal(SIGQUIT, SIG_IGN);
919 	term++;
920 }
921 
922 onhup()
923 {
924 	signal(SIGHUP, SIG_IGN);
925 	term++;
926 }
927 
928 #ifdef notdef
929 onterm()
930 {
931 	signal(SIGTERM, SIG_IGN);
932 	term++;
933 }
934 #endif
935 
936 tomodes(sp)
937 register struct stat *sp;
938 {
939 	register char *cp;
940 
941 	for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
942 		*cp = '\0';
943 	sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777);
944 	sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid);
945 	sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid);
946 	sprintf(dblock.dbuf.size, "%11lo ", sp->st_size);
947 	sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime);
948 }
949 
950 checksum()
951 {
952 	register i;
953 	register char *cp;
954 
955 	for (cp = dblock.dbuf.chksum;
956 	     cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++)
957 		*cp = ' ';
958 	i = 0;
959 	for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
960 		i += *cp;
961 	return (i);
962 }
963 
964 checkw(c, name)
965 	char *name;
966 {
967 	if (!wflag)
968 		return (1);
969 	printf("%c ", c);
970 	if (vflag)
971 		longt(&stbuf);
972 	printf("%s: ", name);
973 	return (response() == 'y');
974 }
975 
976 response()
977 {
978 	char c;
979 
980 	c = getchar();
981 	if (c != '\n')
982 		while (getchar() != '\n')
983 			;
984 	else
985 		c = 'n';
986 	return (c);
987 }
988 
989 checkf(name, mode, howmuch)
990 	char *name;
991 	int mode, howmuch;
992 {
993 	int l;
994 
995 	if ((mode & S_IFMT) == S_IFDIR){
996 		if ((strcmp(name, "SCCS")==0) || (strcmp(name, "RCS")==0))
997 			return(0);
998 		return(1);
999 	}
1000 	if ((l = strlen(name)) < 3)
1001 		return (1);
1002 	if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o')
1003 		return (0);
1004 	if (strcmp(name, "core") == 0 ||
1005 	    strcmp(name, "errs") == 0 ||
1006 	    (howmuch > 1 && strcmp(name, "a.out") == 0))
1007 		return (0);
1008 	/* SHOULD CHECK IF IT IS EXECUTABLE */
1009 	return (1);
1010 }
1011 
1012 /* Is the current file a new file, or the newest one of the same name? */
1013 checkupdate(arg)
1014 	char *arg;
1015 {
1016 	char name[100];
1017 	long mtime;
1018 	daddr_t seekp;
1019 	daddr_t	lookup();
1020 
1021 	rewind(tfile);
1022 	for (;;) {
1023 		if ((seekp = lookup(arg)) < 0)
1024 			return (1);
1025 		fseek(tfile, seekp, 0);
1026 		fscanf(tfile, "%s %lo", name, &mtime);
1027 		return (stbuf.st_mtime > mtime);
1028 	}
1029 }
1030 
1031 done(n)
1032 {
1033 	unlink(tname);
1034 	exit(n);
1035 }
1036 
1037 /*
1038  * Does s2 begin with the string s1, on a directory boundary?
1039  */
1040 prefix(s1, s2)
1041 	register char *s1, *s2;
1042 {
1043 	while (*s1)
1044 		if (*s1++ != *s2++)
1045 			return (0);
1046 	if (*s2)
1047 		return (*s2 == '/');
1048 	return (1);
1049 }
1050 
1051 #define	N	200
1052 int	njab;
1053 
1054 daddr_t
1055 lookup(s)
1056 	char *s;
1057 {
1058 	register i;
1059 	daddr_t a;
1060 
1061 	for(i=0; s[i]; i++)
1062 		if (s[i] == ' ')
1063 			break;
1064 	a = bsrch(s, i, low, high);
1065 	return (a);
1066 }
1067 
1068 daddr_t
1069 bsrch(s, n, l, h)
1070 	daddr_t l, h;
1071 	char *s;
1072 {
1073 	register i, j;
1074 	char b[N];
1075 	daddr_t m, m1;
1076 
1077 	njab = 0;
1078 
1079 loop:
1080 	if (l >= h)
1081 		return ((daddr_t) -1);
1082 	m = l + (h-l)/2 - N/2;
1083 	if (m < l)
1084 		m = l;
1085 	fseek(tfile, m, 0);
1086 	fread(b, 1, N, tfile);
1087 	njab++;
1088 	for(i=0; i<N; i++) {
1089 		if (b[i] == '\n')
1090 			break;
1091 		m++;
1092 	}
1093 	if (m >= h)
1094 		return ((daddr_t) -1);
1095 	m1 = m;
1096 	j = i;
1097 	for(i++; i<N; i++) {
1098 		m1++;
1099 		if (b[i] == '\n')
1100 			break;
1101 	}
1102 	i = cmp(b+j, s, n);
1103 	if (i < 0) {
1104 		h = m;
1105 		goto loop;
1106 	}
1107 	if (i > 0) {
1108 		l = m1;
1109 		goto loop;
1110 	}
1111 	return (m);
1112 }
1113 
1114 cmp(b, s, n)
1115 	char *b, *s;
1116 {
1117 	register i;
1118 
1119 	if (b[0] != '\n')
1120 		exit(2);
1121 	for(i=0; i<n; i++) {
1122 		if (b[i+1] > s[i])
1123 			return (-1);
1124 		if (b[i+1] < s[i])
1125 			return (1);
1126 	}
1127 	return (b[i+1] == ' '? 0 : -1);
1128 }
1129 
1130 readtape(buffer)
1131 	char *buffer;
1132 {
1133 	char *bufp;
1134 
1135 	if (first == 0)
1136 		getbuf();
1137 	readtbuf(&bufp, TBLOCK);
1138 	bcopy(bufp, buffer, TBLOCK);
1139 	return(TBLOCK);
1140 }
1141 
1142 readtbuf(bufpp, size)
1143 	char **bufpp;
1144 	int size;
1145 {
1146 	register int i;
1147 
1148 	if (recno >= nblock || first == 0) {
1149 		if ((i = bread(mt, tbuf, TBLOCK*nblock)) < 0)
1150 			mterr("read", i, 3);
1151 		if (first == 0) {
1152 			if ((i % TBLOCK) != 0) {
1153 				fprintf(stderr, "tar: tape blocksize error\n");
1154 				done(3);
1155 			}
1156 			i /= TBLOCK;
1157 			if (i != nblock) {
1158 				fprintf(stderr, "tar: blocksize = %d\n", i);
1159 				nblock = i;
1160 			}
1161 			first = 1;
1162 		}
1163 		recno = 0;
1164 	}
1165 	if (size > ((nblock-recno)*TBLOCK))
1166 		size = (nblock-recno)*TBLOCK;
1167 	*bufpp = (char *)&tbuf[recno];
1168 	recno += (size/TBLOCK);
1169 	return (size);
1170 }
1171 
1172 writetbuf(buffer, n)
1173 	register char *buffer;
1174 	register int n;
1175 {
1176 	int i;
1177 
1178 	if (first == 0) {
1179 		getbuf();
1180 		first = 1;
1181 	}
1182 	if (recno >= nblock) {
1183 		i = write(mt, tbuf, TBLOCK*nblock);
1184 		if (i != TBLOCK*nblock)
1185 			mterr("write", i, 2);
1186 		recno = 0;
1187 	}
1188 
1189 	/*
1190 	 *  Special case:  We have an empty tape buffer, and the
1191 	 *  users data size is >= the tape block size:  Avoid
1192 	 *  the bcopy and dma direct to tape.  BIG WIN.  Add the
1193 	 *  residual to the tape buffer.
1194 	 */
1195 	while (recno == 0 && n >= nblock) {
1196 		i = write(mt, buffer, TBLOCK*nblock);
1197 		if (i != TBLOCK*nblock)
1198 			mterr("write", i, 2);
1199 		n -= nblock;
1200 		buffer += (nblock * TBLOCK);
1201 	}
1202 
1203 	while (n-- > 0) {
1204 		bcopy(buffer, (char *)&tbuf[recno++], TBLOCK);
1205 		buffer += TBLOCK;
1206 		if (recno >= nblock) {
1207 			i = write(mt, tbuf, TBLOCK*nblock);
1208 			if (i != TBLOCK*nblock)
1209 				mterr("write", i, 2);
1210 			recno = 0;
1211 		}
1212 	}
1213 
1214 	/* Tell the user how much to write to get in sync */
1215 	return (nblock - recno);
1216 }
1217 
1218 backtape()
1219 {
1220 	static int mtdev = 1;
1221 	static struct mtop mtop = {MTBSR, 1};
1222 	struct mtget mtget;
1223 
1224 	if (mtdev == 1)
1225 		mtdev = ioctl(mt, MTIOCGET, &mtget);
1226 	if (mtdev == 0) {
1227 		if (ioctl(mt, MTIOCTOP, &mtop) < 0) {
1228 			fprintf(stderr, "tar: tape backspace error: ");
1229 			perror("");
1230 			done(4);
1231 		}
1232 	} else
1233 		lseek(mt, (daddr_t) -TBLOCK*nblock, 1);
1234 	recno--;
1235 }
1236 
1237 flushtape()
1238 {
1239 	int i;
1240 
1241 	i = write(mt, tbuf, TBLOCK*nblock);
1242 	if (i != TBLOCK*nblock)
1243 		mterr("write", i, 2);
1244 }
1245 
1246 mterr(operation, i, exitcode)
1247 	char *operation;
1248 	int i;
1249 {
1250 	fprintf(stderr, "tar: tape %s error: ", operation);
1251 	if (i < 0)
1252 		perror("");
1253 	else
1254 		fprintf(stderr, "unexpected EOF\n");
1255 	done(exitcode);
1256 }
1257 
1258 bread(fd, buf, size)
1259 	int fd;
1260 	char *buf;
1261 	int size;
1262 {
1263 	int count;
1264 	static int lastread = 0;
1265 
1266 	if (!Bflag)
1267 		return (read(fd, buf, size));
1268 
1269 	for (count = 0; count < size; count += lastread) {
1270 		lastread = read(fd, buf, size - count);
1271 		if (lastread <= 0) {
1272 			if (count > 0)
1273 				return (count);
1274 			return (lastread);
1275 		}
1276 		buf += lastread;
1277 	}
1278 	return (count);
1279 }
1280 
1281 char *
1282 getcwd(buf)
1283 	char *buf;
1284 {
1285 	if (getwd(buf) == NULL) {
1286 		fprintf(stderr, "tar: %s\n", buf);
1287 		exit(1);
1288 	}
1289 	return (buf);
1290 }
1291 
1292 getbuf()
1293 {
1294 
1295 	if (nblock == 0) {
1296 		fstat(mt, &stbuf);
1297 		if ((stbuf.st_mode & S_IFMT) == S_IFCHR)
1298 			nblock = NBLOCK;
1299 		else {
1300 			nblock = stbuf.st_blksize / TBLOCK;
1301 			if (nblock == 0)
1302 				nblock = NBLOCK;
1303 		}
1304 	}
1305 	tbuf = (union hblock *)malloc(nblock*TBLOCK);
1306 	if (tbuf == NULL) {
1307 		fprintf(stderr, "tar: blocksize %d too big, can't get memory\n",
1308 		    nblock);
1309 		done(1);
1310 	}
1311 }
1312 
1313 /*
1314  * Save this directory and its mtime on the stack, popping and setting
1315  * the mtimes of any stacked dirs which aren't parents of this one.
1316  * A null directory causes the entire stack to be unwound and set.
1317  *
1318  * Since all the elements of the directory "stack" share a common
1319  * prefix, we can make do with one string.  We keep only the current
1320  * directory path, with an associated array of mtime's, one for each
1321  * '/' in the path.  A negative mtime means no mtime.  The mtime's are
1322  * offset by one (first index 1, not 0) because calling this with a null
1323  * directory causes mtime[0] to be set.
1324  *
1325  * This stack algorithm is not guaranteed to work for tapes created
1326  * with the 'r' option, but the vast majority of tapes with
1327  * directories are not.  This avoids saving every directory record on
1328  * the tape and setting all the times at the end.
1329  */
1330 char dirstack[NAMSIZ];
1331 #define NTIM (NAMSIZ/2+1)		/* a/b/c/d/... */
1332 time_t mtime[NTIM];
1333 
1334 dodirtimes(hp)
1335 	union hblock *hp;
1336 {
1337 	register char *p = dirstack;
1338 	register char *q = hp->dbuf.name;
1339 	register int ndir = 0;
1340 	char *savp;
1341 	int savndir;
1342 
1343 	/* Find common prefix */
1344 	while (*p == *q) {
1345 		if (*p++ == '/')
1346 			++ndir;
1347 		q++;
1348 	}
1349 
1350 	savp = p;
1351 	savndir = ndir;
1352 	while (*p) {
1353 		/*
1354 		 * Not a child: unwind the stack, setting the times.
1355 		 * The order we do this doesn't matter, so we go "forward."
1356 		 */
1357 		if (*p++ == '/')
1358 			if (mtime[++ndir] >= 0) {
1359 				*--p = '\0';	/* zap the slash */
1360 				setimes(dirstack, mtime[ndir]);
1361 				*p++ = '/';
1362 			}
1363 	}
1364 	p = savp;
1365 	ndir = savndir;
1366 
1367 	/* Push this one on the "stack" */
1368 	while (*p = *q++)	/* append the rest of the new dir */
1369 		if (*p++ == '/')
1370 			mtime[++ndir] = -1;
1371 	mtime[ndir] = stbuf.st_mtime;	/* overwrite the last one */
1372 }
1373 
1374 setimes(path, mt)
1375 	char *path;
1376 	time_t mt;
1377 {
1378 	struct timeval tv[2];
1379 
1380 	tv[0].tv_sec = time((time_t *) 0);
1381 	tv[1].tv_sec = mt;
1382 	tv[0].tv_usec = tv[1].tv_usec = 0;
1383 	if (utimes(path, tv) < 0) {
1384 		fprintf(stderr, "tar: can't set time on %s: ", path);
1385 		perror("");
1386 	}
1387 }
1388 
1389 char *
1390 getmem(size)
1391 {
1392 	char *p = malloc((unsigned) size);
1393 
1394 	if (p == NULL && freemem) {
1395 		fprintf(stderr,
1396 		    "tar: out of memory, link and directory modtime info lost\n");
1397 		freemem = 0;
1398 	}
1399 	return (p);
1400 }
1401