xref: /original-bsd/old/tar/tar.c (revision f0fd5f8a)
1 static	char *sccsid = "@(#)tar.c	4.13 (Berkeley) 82/12/19";
2 
3 /*
4  * Tape Archival Program
5  */
6 #include <stdio.h>
7 #include <sys/param.h>
8 #include <sys/stat.h>
9 #include <dir.h>
10 #include <sys/ioctl.h>
11 #include <sys/mtio.h>
12 #include <signal.h>
13 
14 #define TBLOCK	512
15 #define NBLOCK	20
16 #define NAMSIZ	100
17 
18 union hblock {
19 	char dummy[TBLOCK];
20 	struct header {
21 		char name[NAMSIZ];
22 		char mode[8];
23 		char uid[8];
24 		char gid[8];
25 		char size[12];
26 		char mtime[12];
27 		char chksum[8];
28 		char linkflag;
29 		char linkname[NAMSIZ];
30 	} dbuf;
31 };
32 
33 struct linkbuf {
34 	ino_t	inum;
35 	dev_t	devnum;
36 	int	count;
37 	char	pathname[NAMSIZ];
38 	struct	linkbuf *nextp;
39 };
40 
41 union	hblock dblock;
42 union	hblock tbuf[NBLOCK];
43 struct	linkbuf *ihead;
44 struct	stat stbuf;
45 
46 int	rflag;
47 int	xflag;
48 int	vflag;
49 int	tflag;
50 int	cflag;
51 int	mflag;
52 int	fflag;
53 int	oflag;
54 int	pflag;
55 int	wflag;
56 int	hflag;
57 int	Bflag;
58 
59 int	mt;
60 int	term;
61 int	chksum;
62 int	recno;
63 int	first;
64 int	linkerrok;
65 int	freemem = 1;
66 int	nblock = NBLOCK;
67 int	onintr();
68 int	onquit();
69 int	onhup();
70 int	onterm();
71 
72 daddr_t	low;
73 daddr_t	high;
74 daddr_t	bsrch();
75 
76 FILE	*tfile;
77 char	tname[] = "/tmp/tarXXXXXX";
78 char	*usefile;
79 char	magtape[] = "/dev/rmt8";
80 char	*malloc();
81 char	*sprintf();
82 char	*strcat();
83 char	*getwd();
84 
85 main(argc, argv)
86 int	argc;
87 char	*argv[];
88 {
89 	char *cp;
90 
91 	if (argc < 2)
92 		usage();
93 
94 	tfile = NULL;
95 	usefile =  magtape;
96 	argv[argc] = 0;
97 	argv++;
98 	for (cp = *argv++; *cp; cp++)
99 		switch(*cp) {
100 
101 		case 'f':
102 			usefile = *argv++;
103 			fflag++;
104 			break;
105 
106 		case 'c':
107 			cflag++;
108 			rflag++;
109 			break;
110 
111 		case 'o':
112 			oflag++;
113 			break;
114 
115 		case 'p':
116 			pflag++;
117 			break;
118 
119 		case 'u':
120 			mktemp(tname);
121 			if ((tfile = fopen(tname, "w")) == NULL) {
122 				fprintf(stderr,
123 				 "Tar: cannot create temporary file (%s)\n",
124 				 tname);
125 				done(1);
126 			}
127 			fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n");
128 			/*FALL THRU*/
129 
130 		case 'r':
131 			rflag++;
132 			break;
133 
134 		case 'v':
135 			vflag++;
136 			break;
137 
138 		case 'w':
139 			wflag++;
140 			break;
141 
142 		case 'x':
143 			xflag++;
144 			break;
145 
146 		case 't':
147 			tflag++;
148 			break;
149 
150 		case 'm':
151 			mflag++;
152 			break;
153 
154 		case '-':
155 			break;
156 
157 		case '0':
158 		case '1':
159 		case '4':
160 		case '5':
161 		case '7':
162 		case '8':
163 			magtape[8] = *cp;
164 			usefile = magtape;
165 			break;
166 
167 		case 'b':
168 			nblock = atoi(*argv++);
169 			if (nblock > NBLOCK || nblock <= 0) {
170 				fprintf(stderr, "Invalid blocksize. (Max %d)\n",
171 					NBLOCK);
172 				done(1);
173 			}
174 			break;
175 
176 		case 'l':
177 			linkerrok++;
178 			break;
179 
180 		case 'h':
181 			hflag++;
182 			break;
183 
184 		case 'B':
185 			Bflag++;
186 			break;
187 
188 		default:
189 			fprintf(stderr, "tar: %c: unknown option\n", *cp);
190 			usage();
191 		}
192 
193 	if (!rflag && !xflag && !tflag)
194 		usage();
195 	if (rflag) {
196 		if (cflag && tfile != NULL)
197 			usage();
198 		if (signal(SIGINT, SIG_IGN) != SIG_IGN)
199 			signal(SIGINT, onintr);
200 		if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
201 			signal(SIGHUP, onhup);
202 		if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
203 			signal(SIGQUIT, onquit);
204 #ifdef notdef
205 		if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
206 			signal(SIGTERM, onterm);
207 #endif
208 		if (strcmp(usefile, "-") == 0) {
209 			if (cflag == 0) {
210 				fprintf(stderr,
211 				 "Can only create standard output archives\n");
212 				done(1);
213 			}
214 			mt = dup(1);
215 			nblock = 1;
216 		} else if ((mt = open(usefile, 2)) < 0) {
217 			if (cflag == 0 || (mt =  creat(usefile, 0666)) < 0) {
218 				fprintf(stderr,
219 					"tar: cannot open %s\n", usefile);
220 				done(1);
221 			}
222 		}
223 		dorep(argv);
224 		done(0);
225 	}
226 	if (strcmp(usefile, "-") == 0) {
227 		mt = dup(0);
228 		nblock = 1;
229 	} else if ((mt = open(usefile, 0)) < 0) {
230 		fprintf(stderr, "tar: cannot open %s\n", usefile);
231 		done(1);
232 	}
233 	if (xflag)
234 		doxtract(argv);
235 	else
236 		dotable();
237 	done(0);
238 }
239 
240 usage()
241 {
242 	fprintf(stderr,
243 "tar: usage  tar -{txruB}[cvfblmh] [tapefile] [blocksize] file1 file2...\n");
244 	done(1);
245 }
246 
247 dorep(argv)
248 	char *argv[];
249 {
250 	register char *cp, *cp2;
251 	char wdir[MAXPATHLEN], tempdir[MAXPATHLEN], *parent;
252 
253 	if (!cflag) {
254 		getdir();
255 		do {
256 			passtape();
257 			if (term)
258 				done(0);
259 			getdir();
260 		} while (!endtape());
261 		if (tfile != NULL) {
262 			char buf[200];
263 
264 			sprintf(buf,
265 "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s",
266 				tname, tname, tname, tname, tname, tname);
267 			fflush(tfile);
268 			system(buf);
269 			freopen(tname, "r", tfile);
270 			fstat(fileno(tfile), &stbuf);
271 			high = stbuf.st_size;
272 		}
273 	}
274 
275 	(void) getwd(wdir);
276 	while (*argv && ! term) {
277 		cp2 = *argv;
278 		if (!strcmp(cp2, "-C") && argv[1]) {
279 			argv++;
280 			if (chdir(*argv) < 0)
281 				perror(*argv);
282 			else
283 				(void) getwd(wdir);
284 			argv++;
285 			continue;
286 		}
287 		parent = wdir;
288 		for (cp = *argv; *cp; cp++)
289 			if (*cp == '/')
290 				cp2 = cp;
291 		if (cp2 != *argv) {
292 			*cp2 = '\0';
293 			if (chdir(*argv) < 0) {
294 				perror(*argv);
295 				continue;
296 			}
297 			parent = getwd(tempdir);
298 			*cp2 = '/';
299 			cp2++;
300 		}
301 		putfile(*argv++, cp2, parent);
302 		chdir(wdir);
303 	}
304 	putempty();
305 	putempty();
306 	flushtape();
307 	if (linkerrok == 0)
308 		return;
309 	for (; ihead != NULL; ihead = ihead->nextp) {
310 		if (ihead->count == 0)
311 			continue;
312 		fprintf(stderr, "Missing links to %s\n", ihead->pathname);
313 	}
314 }
315 
316 endtape()
317 {
318 	if (dblock.dbuf.name[0] != '\0')
319 		return (0);
320 	backtape();
321 	return (1);
322 }
323 
324 getdir()
325 {
326 	register struct stat *sp;
327 	int i;
328 
329 	readtape((char *)&dblock);
330 	if (dblock.dbuf.name[0] == '\0')
331 		return;
332 	sp = &stbuf;
333 	sscanf(dblock.dbuf.mode, "%o", &i);
334 	sp->st_mode = i;
335 	sscanf(dblock.dbuf.uid, "%o", &i);
336 	sp->st_uid = i;
337 	sscanf(dblock.dbuf.gid, "%o", &i);
338 	sp->st_gid = i;
339 	sscanf(dblock.dbuf.size, "%lo", &sp->st_size);
340 	sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime);
341 	sscanf(dblock.dbuf.chksum, "%o", &chksum);
342 	if (chksum != checksum()) {
343 		fprintf(stderr, "directory checksum error\n");
344 		done(2);
345 	}
346 	if (tfile != NULL)
347 		fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime);
348 }
349 
350 passtape()
351 {
352 	long blocks;
353 	char buf[TBLOCK];
354 
355 	if (dblock.dbuf.linkflag == '1')
356 		return;
357 	blocks = stbuf.st_size;
358 	blocks += TBLOCK-1;
359 	blocks /= TBLOCK;
360 
361 	while (blocks-- > 0)
362 		readtape(buf);
363 }
364 
365 putfile(longname, shortname, parent)
366 	char *longname;
367 	char *shortname;
368 	char *parent;
369 {
370 	int infile;
371 	long blocks;
372 	char buf[TBLOCK];
373 	register char *cp, *cp2;
374 	struct direct *dp;
375 	DIR *dirp;
376 	int i, j;
377 	char newparent[NAMSIZ+64];
378 
379 	infile = open(shortname, 0);
380 	if (infile < 0) {
381 		fprintf(stderr, "tar: %s: cannot open file\n", longname);
382 		return;
383 	}
384 	if (!hflag)
385 		lstat(shortname, &stbuf);
386 	else if (stat(shortname, &stbuf) < 0) {
387 		perror(longname);
388 		close(infile);
389 		return;
390 	}
391 	if (tfile != NULL && checkupdate(longname) == 0) {
392 		close(infile);
393 		return;
394 	}
395 	if (checkw('r', longname) == 0) {
396 		close(infile);
397 		return;
398 	}
399 
400 	if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
401 		for (i = 0, cp = buf; *cp++ = longname[i++];)
402 			;
403 		*--cp = '/';
404 		*++cp = 0  ;
405 		if (!oflag) {
406 			if ((cp - buf) >= NAMSIZ) {
407 				fprintf(stderr, "%s: file name too long\n",
408 					longname);
409 				close(infile);
410 				return;
411 			}
412 			stbuf.st_size = 0;
413 			tomodes(&stbuf);
414 			strcpy(dblock.dbuf.name,buf);
415 			sprintf(dblock.dbuf.chksum, "%6o", checksum());
416 			writetape((char *)&dblock);
417 		}
418 		sprintf(newparent, "%s/%s", parent, shortname);
419 		chdir(shortname);
420 		close(infile);
421 		if ((dirp = opendir(".")) == NULL) {
422 			fprintf(stderr, "%s: directory read error\n", longname);
423 			chdir(parent);
424 			return;
425 		}
426 		while ((dp = readdir(dirp)) != NULL && !term) {
427 			if (dp->d_ino == 0)
428 				continue;
429 			if (!strcmp(".", dp->d_name) ||
430 			    !strcmp("..", dp->d_name))
431 				continue;
432 			strcpy(cp, dp->d_name);
433 			i = telldir(dirp);
434 			closedir(dirp);
435 			putfile(buf, cp, newparent);
436 			dirp = opendir(".");
437 			seekdir(dirp, i);
438 		}
439 		closedir(dirp);
440 		chdir(parent);
441 		return;
442 	}
443 	i = stbuf.st_mode & S_IFMT;
444 	if (i != S_IFREG && i != S_IFLNK) {
445 		fprintf(stderr, "tar: %s is not a file. Not dumped\n",
446 			longname);
447 		return;
448 	}
449 	tomodes(&stbuf);
450 	cp2 = longname; cp = dblock.dbuf.name; i = 0;
451 	while ((*cp++ = *cp2++) && i < NAMSIZ)
452 		i++;
453 	if (i >= NAMSIZ) {
454 		fprintf(stderr, "%s: file name too long\n", longname);
455 		close(infile);
456 		return;
457 	}
458 	if ((stbuf.st_mode & S_IFMT) == S_IFLNK) {
459 		if (stbuf.st_size + 1 >= NAMSIZ) {
460 			fprintf(stderr, "%s: symbolic link too long\n",
461 				longname);
462 			close(infile);
463 			return;
464 		}
465 		i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1);
466 		if (i < 0) {
467 			perror(longname);
468 			close(infile);
469 			return;
470 		}
471 		dblock.dbuf.linkname[i] = '\0';
472 		dblock.dbuf.linkflag = '2';
473 		if (vflag) {
474 			fprintf(stderr, "a %s ", longname);
475 			fprintf(stderr, "symbolic link to %s\n",
476 				dblock.dbuf.linkname);
477 		}
478 		sprintf(dblock.dbuf.size, "%11lo", 0);
479 		sprintf(dblock.dbuf.chksum, "%6o", checksum());
480 		writetape((char *)&dblock);
481 		close(infile);
482 		return;
483 	}
484 	if (stbuf.st_nlink > 1) {
485 		struct linkbuf *lp;
486 		int found = 0;
487 
488 		for (lp = ihead; lp != NULL; lp = lp->nextp)
489 			if (lp->inum == stbuf.st_ino &&
490 			    lp->devnum == stbuf.st_dev) {
491 				found++;
492 				break;
493 			}
494 		if (found) {
495 			strcpy(dblock.dbuf.linkname, lp->pathname);
496 			dblock.dbuf.linkflag = '1';
497 			sprintf(dblock.dbuf.chksum, "%6o", checksum());
498 			writetape( (char *) &dblock);
499 			if (vflag) {
500 				fprintf(stderr, "a %s ", longname);
501 				fprintf(stderr, "link to %s\n", lp->pathname);
502 			}
503 			lp->count--;
504 			close(infile);
505 			return;
506 		}
507 		lp = (struct linkbuf *) malloc(sizeof(*lp));
508 		if (lp == NULL) {
509 			if (freemem) {
510 				fprintf(stderr,
511 				  "Out of memory. Link information lost\n");
512 				freemem = 0;
513 			}
514 		} else {
515 			lp->nextp = ihead;
516 			ihead = lp;
517 			lp->inum = stbuf.st_ino;
518 			lp->devnum = stbuf.st_dev;
519 			lp->count = stbuf.st_nlink - 1;
520 			strcpy(lp->pathname, longname);
521 		}
522 	}
523 	blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK;
524 	if (vflag) {
525 		fprintf(stderr, "a %s ", longname);
526 		fprintf(stderr, "%ld blocks\n", blocks);
527 	}
528 	sprintf(dblock.dbuf.chksum, "%6o", checksum());
529 	writetape((char *)&dblock);
530 
531 	while ((i = read(infile, buf, TBLOCK)) > 0 && blocks > 0) {
532 		writetape(buf);
533 		blocks--;
534 	}
535 	close(infile);
536 	if (blocks != 0 || i != 0)
537 		fprintf(stderr, "%s: file changed size\n", longname);
538 	while (--blocks >=  0)
539 		putempty();
540 }
541 
542 doxtract(argv)
543 	char *argv[];
544 {
545 	long blocks, bytes;
546 	char buf[TBLOCK];
547 	char **cp;
548 	int ofile;
549 
550 	for (;;) {
551 		getdir();
552 		if (endtape())
553 			break;
554 		if (*argv == 0)
555 			goto gotit;
556 		for (cp = argv; *cp; cp++)
557 			if (prefix(*cp, dblock.dbuf.name))
558 				goto gotit;
559 		passtape();
560 		continue;
561 
562 gotit:
563 		if (checkw('x', dblock.dbuf.name) == 0) {
564 			passtape();
565 			continue;
566 		}
567 		if (checkdir(dblock.dbuf.name))
568 			continue;
569 		if (dblock.dbuf.linkflag == '2') {
570 			unlink(dblock.dbuf.name);
571 			if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) {
572 				fprintf(stderr, "%s: symbolic link failed\n",
573 					dblock.dbuf.name);
574 				continue;
575 			}
576 			if (vflag)
577 				fprintf(stderr, "x %s symbolic link to %s\n",
578 				  dblock.dbuf.name, dblock.dbuf.linkname);
579 #ifdef notdef
580 			/* ignore alien orders */
581 			chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
582 			if (mflag == 0) {
583 				time_t timep[2];
584 
585 				timep[0] = time(0);
586 				timep[1] = stbuf.st_mtime;
587 				utime(dblock.dbuf.name, timep);
588 			}
589 			if (pflag)
590 				chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
591 #endif
592 			continue;
593 		}
594 		if (dblock.dbuf.linkflag == '1') {
595 			unlink(dblock.dbuf.name);
596 			if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) {
597 				fprintf(stderr, "%s: cannot link\n",
598 					dblock.dbuf.name);
599 				continue;
600 			}
601 			if (vflag)
602 				fprintf(stderr, "%s linked to %s\n",
603 					dblock.dbuf.name, dblock.dbuf.linkname);
604 			continue;
605 		}
606 		if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) {
607 			fprintf(stderr, "tar: %s - cannot create\n",
608 				dblock.dbuf.name);
609 			passtape();
610 			continue;
611 		}
612 		chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
613 		blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK;
614 		if (vflag)
615 			fprintf(stderr, "x %s, %ld bytes, %ld tape blocks\n",
616 				dblock.dbuf.name, bytes, blocks);
617 		for (; blocks-- > 0; bytes -= TBLOCK) {
618 			readtape(buf);
619 			if (bytes > TBLOCK) {
620 				if (write(ofile, buf, TBLOCK) < 0) {
621 					fprintf(stderr,
622 					"tar: %s: HELP - extract write error\n",
623 					 dblock.dbuf.name);
624 					done(2);
625 				}
626 				continue;
627 			}
628 			if (write(ofile, buf, (int) bytes) < 0) {
629 				fprintf(stderr,
630 					"tar: %s: HELP - extract write error\n",
631 					dblock.dbuf.name);
632 				done(2);
633 			}
634 		}
635 		close(ofile);
636 		if (mflag == 0) {
637 			time_t timep[2];
638 
639 			timep[0] = time(NULL);
640 			timep[1] = stbuf.st_mtime;
641 			utime(dblock.dbuf.name, timep);
642 		}
643 		if (pflag)
644 			chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
645 	}
646 }
647 
648 dotable()
649 {
650 	for (;;) {
651 		getdir();
652 		if (endtape())
653 			break;
654 		if (vflag)
655 			longt(&stbuf);
656 		printf("%s", dblock.dbuf.name);
657 		if (dblock.dbuf.linkflag == '1')
658 			printf(" linked to %s", dblock.dbuf.linkname);
659 		if (dblock.dbuf.linkflag == '2')
660 			printf(" symbolic link to %s", dblock.dbuf.linkname);
661 		printf("\n");
662 		passtape();
663 	}
664 }
665 
666 putempty()
667 {
668 	char buf[TBLOCK];
669 	char *cp;
670 
671 	for (cp = buf; cp < &buf[TBLOCK]; )
672 		*cp++ = '\0';
673 	writetape(buf);
674 }
675 
676 longt(st)
677 	register struct stat *st;
678 {
679 	register char *cp;
680 	char *ctime();
681 
682 	pmode(st);
683 	printf("%3d/%1d", st->st_uid, st->st_gid);
684 	printf("%7D", st->st_size);
685 	cp = ctime(&st->st_mtime);
686 	printf(" %-12.12s %-4.4s ", cp+4, cp+20);
687 }
688 
689 #define	SUID	04000
690 #define	SGID	02000
691 #define	ROWN	0400
692 #define	WOWN	0200
693 #define	XOWN	0100
694 #define	RGRP	040
695 #define	WGRP	020
696 #define	XGRP	010
697 #define	ROTH	04
698 #define	WOTH	02
699 #define	XOTH	01
700 #define	STXT	01000
701 int	m1[] = { 1, ROWN, 'r', '-' };
702 int	m2[] = { 1, WOWN, 'w', '-' };
703 int	m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
704 int	m4[] = { 1, RGRP, 'r', '-' };
705 int	m5[] = { 1, WGRP, 'w', '-' };
706 int	m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
707 int	m7[] = { 1, ROTH, 'r', '-' };
708 int	m8[] = { 1, WOTH, 'w', '-' };
709 int	m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
710 
711 int	*m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
712 
713 pmode(st)
714 	register struct stat *st;
715 {
716 	register int **mp;
717 
718 	for (mp = &m[0]; mp < &m[9];)
719 		select(*mp++, st);
720 }
721 
722 select(pairp, st)
723 	int *pairp;
724 	struct stat *st;
725 {
726 	register int n, *ap;
727 
728 	ap = pairp;
729 	n = *ap++;
730 	while (--n>=0 && (st->st_mode&*ap++)==0)
731 		ap++;
732 	printf("%c", *ap);
733 }
734 
735 checkdir(name)
736 	register char *name;
737 {
738 	register char *cp;
739 
740 	for (cp = name; *cp; cp++) {
741 		if (*cp != '/')
742 			continue;
743 		*cp = '\0';
744 		if (access(name, 1) < 0) {
745 			if (mkdir(name, 0777) < 0) {
746 				perror(name);
747 				done(0);
748 			}
749 			chown(name, stbuf.st_uid, stbuf.st_gid);
750 			if (pflag)
751 				chmod(name, stbuf.st_mode & 0777);
752 		}
753 		*cp = '/';
754 	}
755 	return (cp[-1]=='/');
756 }
757 
758 onintr()
759 {
760 	signal(SIGINT, SIG_IGN);
761 	term++;
762 }
763 
764 onquit()
765 {
766 	signal(SIGQUIT, SIG_IGN);
767 	term++;
768 }
769 
770 onhup()
771 {
772 	signal(SIGHUP, SIG_IGN);
773 	term++;
774 }
775 
776 onterm()
777 {
778 	signal(SIGTERM, SIG_IGN);
779 	term++;
780 }
781 
782 tomodes(sp)
783 register struct stat *sp;
784 {
785 	register char *cp;
786 
787 	for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
788 		*cp = '\0';
789 	sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777);
790 	sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid);
791 	sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid);
792 	sprintf(dblock.dbuf.size, "%11lo ", sp->st_size);
793 	sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime);
794 }
795 
796 checksum()
797 {
798 	register i;
799 	register char *cp;
800 
801 	for (cp = dblock.dbuf.chksum;
802 	     cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++)
803 		*cp = ' ';
804 	i = 0;
805 	for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
806 		i += *cp;
807 	return (i);
808 }
809 
810 checkw(c, name)
811 	char *name;
812 {
813 	if (!wflag)
814 		return (1);
815 	printf("%c ", c);
816 	if (vflag)
817 		longt(&stbuf);
818 	printf("%s: ", name);
819 	return (response() == 'y');
820 }
821 
822 response()
823 {
824 	char c;
825 
826 	c = getchar();
827 	if (c != '\n')
828 		while (getchar() != '\n')
829 			;
830 	else
831 		c = 'n';
832 	return (c);
833 }
834 
835 checkupdate(arg)
836 	char *arg;
837 {
838 	char name[100];
839 	long mtime;
840 	daddr_t seekp;
841 	daddr_t	lookup();
842 
843 	rewind(tfile);
844 	for (;;) {
845 		if ((seekp = lookup(arg)) < 0)
846 			return (1);
847 		fseek(tfile, seekp, 0);
848 		fscanf(tfile, "%s %lo", name, &mtime);
849 		return (stbuf.st_mtime > mtime);
850 	}
851 }
852 
853 done(n)
854 {
855 	unlink(tname);
856 	exit(n);
857 }
858 
859 prefix(s1, s2)
860 	register char *s1, *s2;
861 {
862 	while (*s1)
863 		if (*s1++ != *s2++)
864 			return (0);
865 	if (*s2)
866 		return (*s2 == '/');
867 	return (1);
868 }
869 
870 #define	N	200
871 int	njab;
872 
873 daddr_t
874 lookup(s)
875 	char *s;
876 {
877 	register i;
878 	daddr_t a;
879 
880 	for(i=0; s[i]; i++)
881 		if (s[i] == ' ')
882 			break;
883 	a = bsrch(s, i, low, high);
884 	return (a);
885 }
886 
887 daddr_t
888 bsrch(s, n, l, h)
889 	daddr_t l, h;
890 	char *s;
891 {
892 	register i, j;
893 	char b[N];
894 	daddr_t m, m1;
895 
896 	njab = 0;
897 
898 loop:
899 	if (l >= h)
900 		return (-1L);
901 	m = l + (h-l)/2 - N/2;
902 	if (m < l)
903 		m = l;
904 	fseek(tfile, m, 0);
905 	fread(b, 1, N, tfile);
906 	njab++;
907 	for(i=0; i<N; i++) {
908 		if (b[i] == '\n')
909 			break;
910 		m++;
911 	}
912 	if (m >= h)
913 		return (-1L);
914 	m1 = m;
915 	j = i;
916 	for(i++; i<N; i++) {
917 		m1++;
918 		if (b[i] == '\n')
919 			break;
920 	}
921 	i = cmp(b+j, s, n);
922 	if (i < 0) {
923 		h = m;
924 		goto loop;
925 	}
926 	if (i > 0) {
927 		l = m1;
928 		goto loop;
929 	}
930 	return (m);
931 }
932 
933 cmp(b, s, n)
934 	char *b, *s;
935 {
936 	register i;
937 
938 	if (b[0] != '\n')
939 		exit(2);
940 	for(i=0; i<n; i++) {
941 		if (b[i+1] > s[i])
942 			return (-1);
943 		if (b[i+1] < s[i])
944 			return (1);
945 	}
946 	return (b[i+1] == ' '? 0 : -1);
947 }
948 
949 readtape(buffer)
950 	char *buffer;
951 {
952 	register int i;
953 
954 	if (recno >= nblock || first == 0) {
955 		if ((i = bread(mt, tbuf, TBLOCK*nblock)) < 0) {
956 			fprintf(stderr, "Tar: tape read error\n");
957 			done(3);
958 		}
959 		if (first == 0) {
960 			if ((i % TBLOCK) != 0) {
961 				fprintf(stderr, "Tar: tape blocksize error\n");
962 				done(3);
963 			}
964 			i /= TBLOCK;
965 			if (i != nblock) {
966 				fprintf(stderr, "Tar: blocksize = %d\n", i);
967 				nblock = i;
968 			}
969 		}
970 		recno = 0;
971 	}
972 	first = 1;
973 	copy(buffer, &tbuf[recno++]);
974 	return (TBLOCK);
975 }
976 
977 writetape(buffer)
978 	char *buffer;
979 {
980 	first = 1;
981 	if (recno >= nblock) {
982 		if (write(mt, tbuf, TBLOCK*nblock) < 0) {
983 			fprintf(stderr, "Tar: tape write error\n");
984 			done(2);
985 		}
986 		recno = 0;
987 	}
988 	copy(&tbuf[recno++], buffer);
989 	if (recno >= nblock) {
990 		if (write(mt, tbuf, TBLOCK*nblock) < 0) {
991 			fprintf(stderr, "Tar: tape write error\n");
992 			done(2);
993 		}
994 		recno = 0;
995 	}
996 	return (TBLOCK);
997 }
998 
999 backtape()
1000 {
1001 	static int mtdev = 1;
1002 	static struct mtop mtop = {MTBSR, 1};
1003 	struct mtget mtget;
1004 
1005 	if (mtdev == 1)
1006 		mtdev = ioctl(mt, MTIOCGET, &mtget);
1007 	if (mtdev == 0) {
1008 		if (ioctl(mt, MTIOCTOP, &mtop) < 0) {
1009 			fprintf(stderr, "Tar: tape backspace error\n");
1010 			done(4);
1011 		}
1012 	} else
1013 		lseek(mt, (long) -TBLOCK*nblock, 1);
1014 	recno--;
1015 }
1016 
1017 flushtape()
1018 {
1019 	write(mt, tbuf, TBLOCK*nblock);
1020 }
1021 
1022 copy(to, from)
1023 	register char *to, *from;
1024 {
1025 	register i;
1026 
1027 	i = TBLOCK;
1028 	do {
1029 		*to++ = *from++;
1030 	} while (--i);
1031 }
1032 
1033 bread(fd, buf, size)
1034 	int fd;
1035 	char *buf;
1036 	int size;
1037 {
1038 	int count;
1039 	static int lastread = 0;
1040 
1041 	if (!Bflag)
1042 		return (read(fd, buf, size));
1043 	for (count = 0; count < size; count += lastread) {
1044 		if (lastread < 0) {
1045 			if (count > 0)
1046 				return (count);
1047 			return (lastread);
1048 		}
1049 		lastread = read(fd, buf, size - count);
1050 		buf += lastread;
1051 	}
1052 	return (count);
1053 }
1054