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