xref: /csrg-svn/old/tar/tar.c (revision 24281)
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.3 (Berkeley) 08/13/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 			unlink(dblock.dbuf.name);
670 			if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) {
671 				fprintf(stderr, "tar: %s: symbolic link failed\n",
672 				    dblock.dbuf.name);
673 				continue;
674 			}
675 			if (vflag)
676 				fprintf(vfile, "x %s symbolic link to %s\n",
677 				    dblock.dbuf.name, dblock.dbuf.linkname);
678 #ifdef notdef
679 			/* ignore alien orders */
680 			chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
681 			if (mflag == 0)
682 				setimes(dblock.dbuf.name, stbuf.st_mtime);
683 			if (pflag)
684 				chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
685 #endif
686 			continue;
687 		}
688 		if (dblock.dbuf.linkflag == '1') {	/* regular link */
689 			unlink(dblock.dbuf.name);
690 			if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) {
691 				fprintf(stderr, "tar: %s: cannot link\n",
692 				    dblock.dbuf.name);
693 				continue;
694 			}
695 			if (vflag)
696 				fprintf(vfile, "%s linked to %s\n",
697 				    dblock.dbuf.name, dblock.dbuf.linkname);
698 			continue;
699 		}
700 		if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) {
701 			fprintf(stderr, "tar: %s - cannot create\n",
702 			    dblock.dbuf.name);
703 			passtape();
704 			continue;
705 		}
706 		chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
707 		blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK;
708 		if (vflag)
709 			fprintf(vfile, "x %s, %ld bytes, %ld tape blocks\n",
710 			    dblock.dbuf.name, bytes, blocks);
711 		for (; blocks > 0;) {
712 			register int nread;
713 			char	*bufp;
714 			register int nwant;
715 
716 			nwant = NBLOCK*TBLOCK;
717 			if (nwant > (blocks*TBLOCK))
718 				nwant = (blocks*TBLOCK);
719 			nread = readtbuf(&bufp, nwant);
720 			if (write(ofile, bufp, (int)min(nread, bytes)) < 0) {
721 				fprintf(stderr,
722 				    "tar: %s: HELP - extract write error\n",
723 				    dblock.dbuf.name);
724 				done(2);
725 			}
726 			bytes -= nread;
727 			blocks -= (((nread-1)/TBLOCK)+1);
728 		}
729 		close(ofile);
730 		if (mflag == 0)
731 			setimes(dblock.dbuf.name, stbuf.st_mtime);
732 		if (pflag)
733 			chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
734 	}
735 	if (mflag == 0) {
736 		dblock.dbuf.name[0] = '\0';	/* process the whole stack */
737 		dodirtimes(&dblock);
738 	}
739 }
740 
741 dotable()
742 {
743 	for (;;) {
744 		getdir();
745 		if (endtape())
746 			break;
747 		if (vflag)
748 			longt(&stbuf);
749 		printf("%s", dblock.dbuf.name);
750 		if (dblock.dbuf.linkflag == '1')
751 			printf(" linked to %s", dblock.dbuf.linkname);
752 		if (dblock.dbuf.linkflag == '2')
753 			printf(" symbolic link to %s", dblock.dbuf.linkname);
754 		printf("\n");
755 		passtape();
756 	}
757 }
758 
759 putempty()
760 {
761 	char buf[TBLOCK];
762 
763 	bzero(buf, sizeof (buf));
764 	writetape(buf);
765 }
766 
767 longt(st)
768 	register struct stat *st;
769 {
770 	register char *cp;
771 	char *ctime();
772 
773 	pmode(st);
774 	printf("%3d/%1d", st->st_uid, st->st_gid);
775 	printf("%7D", st->st_size);
776 	cp = ctime(&st->st_mtime);
777 	printf(" %-12.12s %-4.4s ", cp+4, cp+20);
778 }
779 
780 #define	SUID	04000
781 #define	SGID	02000
782 #define	ROWN	0400
783 #define	WOWN	0200
784 #define	XOWN	0100
785 #define	RGRP	040
786 #define	WGRP	020
787 #define	XGRP	010
788 #define	ROTH	04
789 #define	WOTH	02
790 #define	XOTH	01
791 #define	STXT	01000
792 int	m1[] = { 1, ROWN, 'r', '-' };
793 int	m2[] = { 1, WOWN, 'w', '-' };
794 int	m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
795 int	m4[] = { 1, RGRP, 'r', '-' };
796 int	m5[] = { 1, WGRP, 'w', '-' };
797 int	m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
798 int	m7[] = { 1, ROTH, 'r', '-' };
799 int	m8[] = { 1, WOTH, 'w', '-' };
800 int	m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
801 
802 int	*m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
803 
804 pmode(st)
805 	register struct stat *st;
806 {
807 	register int **mp;
808 
809 	for (mp = &m[0]; mp < &m[9];)
810 		select(*mp++, st);
811 }
812 
813 select(pairp, st)
814 	int *pairp;
815 	struct stat *st;
816 {
817 	register int n, *ap;
818 
819 	ap = pairp;
820 	n = *ap++;
821 	while (--n>=0 && (st->st_mode&*ap++)==0)
822 		ap++;
823 	printf("%c", *ap);
824 }
825 
826 /*
827  * Make all directories needed by `name'.  If `name' is a
828  * directory itself on the tar tape (indicated by a trailing '/'),
829  * return 1; else 0.
830  */
831 checkdir(name)
832 	register char *name;
833 {
834 	register char *cp;
835 
836 	/*
837 	 * Quick check for existence of directory.
838 	 */
839 	if ((cp = rindex(name, '/')) == 0)
840 		return (0);
841 	*cp = '\0';
842 	if (access(name, 0) == 0) {	/* already exists */
843 		*cp = '/';
844 		return (cp[1] == '\0');	/* return (lastchar == '/') */
845 	}
846 	*cp = '/';
847 
848 	/*
849 	 * No luck, try to make all directories in path.
850 	 */
851 	for (cp = name; *cp; cp++) {
852 		if (*cp != '/')
853 			continue;
854 		*cp = '\0';
855 		if (access(name, 0) < 0) {
856 			if (mkdir(name, 0777) < 0) {
857 				perror(name);
858 				*cp = '/';
859 				return (0);
860 			}
861 			chown(name, stbuf.st_uid, stbuf.st_gid);
862 			if (pflag && cp[1] == '\0')
863 				chmod(name, stbuf.st_mode & 0777);
864 		}
865 		*cp = '/';
866 	}
867 	return (cp[-1]=='/');
868 }
869 
870 onintr()
871 {
872 	signal(SIGINT, SIG_IGN);
873 	term++;
874 }
875 
876 onquit()
877 {
878 	signal(SIGQUIT, SIG_IGN);
879 	term++;
880 }
881 
882 onhup()
883 {
884 	signal(SIGHUP, SIG_IGN);
885 	term++;
886 }
887 
888 #ifdef notdef
889 onterm()
890 {
891 	signal(SIGTERM, SIG_IGN);
892 	term++;
893 }
894 #endif
895 
896 tomodes(sp)
897 register struct stat *sp;
898 {
899 	register char *cp;
900 
901 	for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
902 		*cp = '\0';
903 	sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777);
904 	sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid);
905 	sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid);
906 	sprintf(dblock.dbuf.size, "%11lo ", sp->st_size);
907 	sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime);
908 }
909 
910 checksum()
911 {
912 	register i;
913 	register char *cp;
914 
915 	for (cp = dblock.dbuf.chksum;
916 	     cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++)
917 		*cp = ' ';
918 	i = 0;
919 	for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
920 		i += *cp;
921 	return (i);
922 }
923 
924 checkw(c, name)
925 	char *name;
926 {
927 	if (!wflag)
928 		return (1);
929 	printf("%c ", c);
930 	if (vflag)
931 		longt(&stbuf);
932 	printf("%s: ", name);
933 	return (response() == 'y');
934 }
935 
936 response()
937 {
938 	char c;
939 
940 	c = getchar();
941 	if (c != '\n')
942 		while (getchar() != '\n')
943 			;
944 	else
945 		c = 'n';
946 	return (c);
947 }
948 
949 checkf(name, mode, howmuch)
950 	char *name;
951 	int mode, howmuch;
952 {
953 	int l;
954 
955 	if ((mode & S_IFMT) == S_IFDIR){
956 		if ((strcmp(name, "SCCS")==0) || (strcmp(name, "RCS")==0))
957 			return(0);
958 		return(1);
959 	}
960 	if ((l = strlen(name)) < 3)
961 		return (1);
962 	if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o')
963 		return (0);
964 	if (strcmp(name, "core") == 0 ||
965 	    strcmp(name, "errs") == 0 ||
966 	    (howmuch > 1 && strcmp(name, "a.out") == 0))
967 		return (0);
968 	/* SHOULD CHECK IF IT IS EXECUTABLE */
969 	return (1);
970 }
971 
972 /* Is the current file a new file, or the newest one of the same name? */
973 checkupdate(arg)
974 	char *arg;
975 {
976 	char name[100];
977 	long mtime;
978 	daddr_t seekp;
979 	daddr_t	lookup();
980 
981 	rewind(tfile);
982 	for (;;) {
983 		if ((seekp = lookup(arg)) < 0)
984 			return (1);
985 		fseek(tfile, seekp, 0);
986 		fscanf(tfile, "%s %lo", name, &mtime);
987 		return (stbuf.st_mtime > mtime);
988 	}
989 }
990 
991 done(n)
992 {
993 	unlink(tname);
994 	exit(n);
995 }
996 
997 /*
998  * Does s2 begin with the string s1, on a directory boundary?
999  */
1000 prefix(s1, s2)
1001 	register char *s1, *s2;
1002 {
1003 	while (*s1)
1004 		if (*s1++ != *s2++)
1005 			return (0);
1006 	if (*s2)
1007 		return (*s2 == '/');
1008 	return (1);
1009 }
1010 
1011 #define	N	200
1012 int	njab;
1013 
1014 daddr_t
1015 lookup(s)
1016 	char *s;
1017 {
1018 	register i;
1019 	daddr_t a;
1020 
1021 	for(i=0; s[i]; i++)
1022 		if (s[i] == ' ')
1023 			break;
1024 	a = bsrch(s, i, low, high);
1025 	return (a);
1026 }
1027 
1028 daddr_t
1029 bsrch(s, n, l, h)
1030 	daddr_t l, h;
1031 	char *s;
1032 {
1033 	register i, j;
1034 	char b[N];
1035 	daddr_t m, m1;
1036 
1037 	njab = 0;
1038 
1039 loop:
1040 	if (l >= h)
1041 		return ((daddr_t) -1);
1042 	m = l + (h-l)/2 - N/2;
1043 	if (m < l)
1044 		m = l;
1045 	fseek(tfile, m, 0);
1046 	fread(b, 1, N, tfile);
1047 	njab++;
1048 	for(i=0; i<N; i++) {
1049 		if (b[i] == '\n')
1050 			break;
1051 		m++;
1052 	}
1053 	if (m >= h)
1054 		return ((daddr_t) -1);
1055 	m1 = m;
1056 	j = i;
1057 	for(i++; i<N; i++) {
1058 		m1++;
1059 		if (b[i] == '\n')
1060 			break;
1061 	}
1062 	i = cmp(b+j, s, n);
1063 	if (i < 0) {
1064 		h = m;
1065 		goto loop;
1066 	}
1067 	if (i > 0) {
1068 		l = m1;
1069 		goto loop;
1070 	}
1071 	return (m);
1072 }
1073 
1074 cmp(b, s, n)
1075 	char *b, *s;
1076 {
1077 	register i;
1078 
1079 	if (b[0] != '\n')
1080 		exit(2);
1081 	for(i=0; i<n; i++) {
1082 		if (b[i+1] > s[i])
1083 			return (-1);
1084 		if (b[i+1] < s[i])
1085 			return (1);
1086 	}
1087 	return (b[i+1] == ' '? 0 : -1);
1088 }
1089 
1090 readtape(buffer)
1091 	char *buffer;
1092 {
1093 	char *bufp;
1094 
1095 	if (first == 0)
1096 		getbuf();
1097 	readtbuf(&bufp, TBLOCK);
1098 	bcopy(bufp, buffer, TBLOCK);
1099 	return(TBLOCK);
1100 }
1101 
1102 readtbuf(bufpp, size)
1103 	char **bufpp;
1104 	int size;
1105 {
1106 	register int i;
1107 
1108 	if (recno >= nblock || first == 0) {
1109 		if ((i = bread(mt, tbuf, TBLOCK*nblock)) < 0) {
1110 			fprintf(stderr, "tar: tape read error\n");
1111 			done(3);
1112 		}
1113 		if (first == 0) {
1114 			if ((i % TBLOCK) != 0) {
1115 				fprintf(stderr, "tar: tape blocksize error\n");
1116 				done(3);
1117 			}
1118 			i /= TBLOCK;
1119 			if (i != nblock) {
1120 				fprintf(stderr, "tar: blocksize = %d\n", i);
1121 				nblock = i;
1122 			}
1123 			first = 1;
1124 		}
1125 		recno = 0;
1126 	}
1127 	if (size > ((nblock-recno)*TBLOCK))
1128 		size = (nblock-recno)*TBLOCK;
1129 	*bufpp = (char *)&tbuf[recno];
1130 	recno += (size/TBLOCK);
1131 	return (size);
1132 }
1133 
1134 writetbuf(buffer, n)
1135 	register char *buffer;
1136 	register int n;
1137 {
1138 
1139 	if (first == 0) {
1140 		getbuf();
1141 		first = 1;
1142 	}
1143 	if (recno >= nblock) {
1144 		if (write(mt, tbuf, TBLOCK*nblock) < 0) {
1145 			fprintf(stderr,"tar: tape write error\n");
1146 			done(2);
1147 		}
1148 		recno = 0;
1149 	}
1150 
1151 	/*
1152 	 *  Special case:  We have an empty tape buffer, and the
1153 	 *  users data size is >= the tape block size:  Avoid
1154 	 *  the bcopy and dma direct to tape.  BIG WIN.  Add the
1155 	 *  residual to the tape buffer.
1156 	 */
1157 	while (recno == 0 && n >= nblock) {
1158 		if (write(mt, buffer, TBLOCK*nblock) < 0) {
1159 			fprintf(stderr,"tar: tape write error\n");
1160 			done(2);
1161 		}
1162 		n -= nblock;
1163 		buffer += (nblock * TBLOCK);
1164 	}
1165 
1166 	while (n-- > 0) {
1167 		bcopy(buffer, (char *)&tbuf[recno++], TBLOCK);
1168 		buffer += TBLOCK;
1169 		if (recno >= nblock) {
1170 			if (write(mt, tbuf, TBLOCK*nblock) < 0) {
1171 					fprintf(stderr,"tar: tape write error\n");
1172 					done(2);
1173 			}
1174 			recno = 0;
1175 		}
1176 	}
1177 
1178 	/* Tell the user how much to write to get in sync */
1179 	return (nblock - recno);
1180 }
1181 
1182 backtape()
1183 {
1184 	static struct mtop mtop = {MTBSR, 1};
1185 
1186 	if (mtdev == 0) {
1187 		if (ioctl(mt, MTIOCTOP, &mtop) < 0) {
1188 			fprintf(stderr, "tar: tape backspace error\n");
1189 			done(4);
1190 		}
1191 	} else
1192 		lseek(mt, (daddr_t) -TBLOCK*nblock, 1);
1193 	recno--;
1194 }
1195 
1196 flushtape()
1197 {
1198 	write(mt, tbuf, TBLOCK*nblock);
1199 }
1200 
1201 bread(fd, buf, size)
1202 	int fd;
1203 	char *buf;
1204 	int size;
1205 {
1206 	int count;
1207 	static int lastread = 0;
1208 
1209 	if (!Bflag)
1210 		return (read(fd, buf, size));
1211 
1212 	for (count = 0; count < size; count += lastread) {
1213 		lastread = read(fd, buf, size - count);
1214 		if (lastread <= 0) {
1215 			if (count > 0)
1216 				return (count);
1217 			return (lastread);
1218 		}
1219 		buf += lastread;
1220 	}
1221 	return (count);
1222 }
1223 
1224 char *
1225 getcwd(buf)
1226 	char *buf;
1227 {
1228 	if (getwd(buf) == NULL) {
1229 		fprintf(stderr, "tar: %s\n", buf);
1230 		exit(1);
1231 	}
1232 	return (buf);
1233 }
1234 
1235 getbuf()
1236 {
1237 
1238 	if (mtdev == 1) {
1239 		fstat(mt, &stbuf);
1240 		if ((stbuf.st_mode & S_IFMT) == S_IFCHR)
1241 			mtdev = 0;
1242 		else
1243 			mtdev = -1;
1244 	}
1245 	if (nblock == 0) {
1246 		if (mtdev == 0)
1247 			nblock = FILEBLOCK;
1248 		else {
1249 			fstat(mt, &stbuf);
1250 			nblock = stbuf.st_blocks / TBLOCK;
1251 		}
1252 	}
1253 	if (nblock == 0)
1254 		nblock = FILEBLOCK;
1255 	tbuf = (union hblock *)malloc(nblock*TBLOCK);
1256 	if (tbuf == NULL) {
1257 		fprintf(stderr, "tar: blocksize %d too big, can't get memory\n",
1258 		    nblock);
1259 		done(1);
1260 	}
1261 }
1262 
1263 /*
1264  * We are really keeping a directory stack, but since all the
1265  * elements of it share a common prefix, we can make do with one
1266  * string.  We keep only the current directory path, with an associated
1267  * array of mtime's, one for each '/' in the path.  A negative mtime
1268  * means no mtime.  The mtime's are offset by one (first index 1, not
1269  * 0) because calling this with the null string causes mtime[0] to be set.
1270  *
1271  * This stack algorithm is not guaranteed to work for tapes created
1272  * with the 'r' option, but the vast majority of tapes with
1273  * directories are not.  This avoids saving every directory record on
1274  * the tape and setting all the times at the end.
1275  */
1276 char dirstack[NAMSIZ];
1277 #define NTIM (NAMSIZ/2+1)		/* a/b/c/d/... */
1278 time_t mtime[NTIM];
1279 
1280 dodirtimes(hp)
1281 	union hblock *hp;
1282 {
1283 	register char *p = dirstack;
1284 	register char *q = hp->dbuf.name;
1285 	register int ndir = 0;
1286 	char *savp;
1287 	int savndir;
1288 
1289 	/* Find common prefix */
1290 	while (*p == *q) {
1291 		if (*p++ == '/')
1292 			++ndir;
1293 		q++;
1294 	}
1295 
1296 	savp = p;
1297 	savndir = ndir;
1298 	while (*p) {
1299 		/*
1300 		 * Not a child: unwind the stack, setting the times.
1301 		 * The order we do this doesn't matter, so we go "forward."
1302 		 */
1303 		if (*p++ == '/')
1304 			if (mtime[++ndir] >= 0) {
1305 				*--p = '\0';	/* zap the slash */
1306 				setimes(dirstack, mtime[ndir]);
1307 				*p++ = '/';
1308 			}
1309 	}
1310 	p = savp;
1311 	ndir = savndir;
1312 
1313 	/* Push this one on the "stack" */
1314 	while (*p = *q++)	/* append the rest of the new dir */
1315 		if (*p++ == '/')
1316 			mtime[++ndir] = -1;
1317 	mtime[ndir] = stbuf.st_mtime;	/* overwrite the last one */
1318 }
1319 
1320 setimes(path, mt)
1321 	char *path;
1322 	time_t mt;
1323 {
1324 	struct timeval tv[2];
1325 
1326 	tv[0].tv_sec = time((time_t *) 0);
1327 	tv[1].tv_sec = mt;
1328 	tv[0].tv_usec = tv[1].tv_usec = 0;
1329 	if (utimes(path, tv) < 0)
1330 		fprintf(stderr, "tar: can't set time on %s\n", path);
1331 }
1332 
1333 char *
1334 getmem(size)
1335 {
1336 	char *p = malloc((unsigned) size);
1337 
1338 	if (p == NULL && freemem) {
1339 		fprintf(stderr,
1340 		    "tar: out of memory, link and directory modtime info lost\n");
1341 		freemem = 0;
1342 	}
1343 	return (p);
1344 }
1345