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