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