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