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