xref: /plan9/sys/src/cmd/tar.c (revision 9b943567965ba040fd275927fbe088656eb8ce4f)
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 #include <bio.h>
6 
7 #define TBLOCK	512
8 #define NBLOCK	40	/* maximum blocksize */
9 #define DBLOCK	20	/* default blocksize */
10 #define NAMSIZ	100
11 
12 enum {
13 	Maxpfx = 155,		/* from POSIX */
14 	Maxname = NAMSIZ + 1 + Maxpfx,
15 };
16 
17 /* POSIX link flags */
18 enum {
19 	LF_PLAIN1 =	'\0',
20 	LF_PLAIN2 =	'0',
21 	LF_LINK =	'1',
22 	LF_SYMLINK1 =	'2',
23 	LF_SYMLINK2 =	's',
24 	LF_CHR =	'3',
25 	LF_BLK =	'4',
26 	LF_DIR =	'5',
27 	LF_FIFO =	'6',
28 	LF_CONTIG =	'7',
29 	/* 'A' - 'Z' are reserved for custom implementations */
30 };
31 
32 #define islink(lf)	(isreallink(lf) || issymlink(lf))
33 #define isreallink(lf)	((lf) == LF_LINK)
34 #define issymlink(lf)	((lf) == LF_SYMLINK1 || (lf) == LF_SYMLINK2)
35 union	hblock
36 {
37 	char	dummy[TBLOCK];
38 	struct	header
39 	{
40 		char	name[NAMSIZ];
41 		char	mode[8];
42 		char	uid[8];
43 		char	gid[8];
44 		char	size[12];
45 		char	mtime[12];
46 		char	chksum[8];
47 		char	linkflag;
48 		char	linkname[NAMSIZ];
49 		/* rest are defined by POSIX's ustar format; see p1003.2b */
50 		char	magic[6];	/* "ustar" */
51 		char	version[2];
52 		char	uname[32];
53 		char	gname[32];
54 		char	devmajor[8];
55 		char	devminor[8];
56 		char	prefix[155];  /* if non-null, path = prefix "/" name */
57 	} dbuf;
58 } dblock, tbuf[NBLOCK];
59 
60 Dir *stbuf;
61 Biobuf bout;
62 static int ustar;		/* flag: tape block just read is ustar format */
63 static char *fullname;			/* if non-nil, prefix "/" name */
64 
65 int	rflag, xflag, vflag, tflag, mt, cflag, fflag, Tflag, Rflag;
66 int	uflag, gflag;
67 static int posix;		/* flag: we're writing ustar format archive */
68 int	chksum, recno, first;
69 int	nblock = DBLOCK;
70 
71 void	usage(void);
72 void	dorep(char **);
73 int	endtar(void);
74 void	getdir(void);
75 void	passtar(void);
76 void	putfile(char*, char *, char *);
77 void	doxtract(char **);
78 void	dotable(void);
79 void	putempty(void);
80 void	longt(Dir *);
81 int	checkdir(char *, int, Qid*);
82 void	tomodes(Dir *);
83 int	checksum(void);
84 int	checkupdate(char *);
85 int	prefix(char *, char *);
86 int	readtar(char *);
87 int	writetar(char *);
88 void	backtar(void);
89 void	flushtar(void);
90 void	affix(int, char *);
91 int	volprompt(void);
92 
93 static int
94 isustar(struct header *hp)
95 {
96 	return strcmp(hp->magic, "ustar") == 0;
97 }
98 
99 static void
100 setustar(struct header *hp)
101 {
102 	strncpy(hp->magic, "ustar", sizeof hp->magic);
103 	strncpy(hp->version, "00", sizeof hp->version);
104 }
105 
106 /*
107  * s is at most n bytes long, but need not be NUL-terminated.
108  * if shorter than n bytes, all bytes after the first NUL must also
109  * be NUL.
110  */
111 static int
112 strnlen(char *s, int n)
113 {
114 	if (s[n - 1] != '\0')
115 		return n;
116 	else
117 		return strlen(s);
118 }
119 
120 /* set fullname from header; called from getdir() */
121 static void
122 getfullname(struct header *hp)
123 {
124 	int pfxlen, namlen;
125 
126 	if (fullname != nil)
127 		free(fullname);
128 	namlen = strnlen(hp->name, sizeof hp->name);
129 	if (hp->prefix[0] == '\0' || !ustar) {
130 		fullname = malloc(namlen + 1);
131 		if (fullname == nil)
132 			sysfatal("out of memory: %r");
133 		memmove(fullname, hp->name, namlen);
134 		fullname[namlen] = '\0';
135 		return;
136 	}
137 	pfxlen = strnlen(hp->prefix, sizeof hp->prefix);
138 	fullname = malloc(pfxlen + 1 + namlen + 1);
139 	if (fullname == nil)
140 		sysfatal("out of memory: %r");
141 	memmove(fullname, hp->prefix, pfxlen);
142 	fullname[pfxlen] = '/';
143 	memmove(fullname + pfxlen + 1, hp->name, namlen);
144 	fullname[pfxlen + 1 + namlen] = '\0';
145 }
146 
147 /*
148  * if name is longer than NAMSIZ bytes, try to split it at a slash and fit the
149  * pieces into hp->prefix and hp->name.
150  */
151 static int
152 putfullname(struct header *hp, char *name)
153 {
154 	int namlen, pfxlen;
155 	char *sl, *osl;
156 
157 	namlen = strlen(name);
158 	if (namlen <= NAMSIZ) {
159 		strncpy(hp->name, name, NAMSIZ);
160 		hp->prefix[0] = '\0';		/* ustar paranoia */
161 		return 0;
162 	}
163 	if (!posix || namlen > NAMSIZ + 1 + sizeof hp->prefix) {
164 		fprint(2, "tar: name too long for tar header: %s\n", name);
165 		return -1;
166 	}
167 	/*
168 	 * try various splits until one results in pieces that fit into the
169 	 * appropriate fields of the header.  look for slashes from right
170 	 * to left, in the hopes of putting the largest part of the name into
171 	 * hp->prefix, which is larger than hp->name.
172 	 */
173 	sl = strrchr(name, '/');
174 	while (sl != nil) {
175 		pfxlen = sl - name;
176 		if (pfxlen <= sizeof hp->prefix && namlen-1 - pfxlen <= NAMSIZ)
177 			break;
178 		osl = sl;
179 		*osl = '\0';
180 		sl = strrchr(name, '/');
181 		*osl = '/';
182 	}
183 	if (sl == nil) {
184 		fprint(2, "tar: name can't be split to fit tar header: %s\n",
185 			name);
186 		return -1;
187 	}
188 	*sl = '\0';
189 	strncpy(hp->prefix, name, sizeof hp->prefix);
190 	*sl = '/';
191 	strncpy(hp->name, sl + 1, sizeof hp->name);
192 	return 0;
193 }
194 
195 void
196 main(int argc, char **argv)
197 {
198 	char *usefile;
199 	char *cp, *ap;
200 
201 	if (argc < 2)
202 		usage();
203 
204 	Binit(&bout, 1, OWRITE);
205 	usefile =  0;
206 	argv[argc] = 0;
207 	argv++;
208 	for (cp = *argv++; *cp; cp++)
209 		switch(*cp) {
210 		case 'f':
211 			usefile = *argv++;
212 			if(!usefile)
213 				usage();
214 			fflag++;
215 			break;
216 		case 'u':
217 			ap = *argv++;
218 			if(!ap)
219 				usage();
220 			uflag = strtoul(ap, 0, 0);
221 			break;
222 		case 'g':
223 			ap = *argv++;
224 			if(!ap)
225 				usage();
226 			gflag = strtoul(ap, 0, 0);
227 			break;
228 		case 'c':
229 			cflag++;
230 			rflag++;
231 			break;
232 		case 'p':
233 			posix++;
234 			break;
235 		case 'r':
236 			rflag++;
237 			break;
238 		case 'v':
239 			vflag++;
240 			break;
241 		case 'x':
242 			xflag++;
243 			break;
244 		case 'T':
245 			Tflag++;
246 			break;
247 		case 't':
248 			tflag++;
249 			break;
250 		case 'R':
251 			Rflag++;
252 			break;
253 		case '-':
254 			break;
255 		default:
256 			fprint(2, "tar: %c: unknown option\n", *cp);
257 			usage();
258 		}
259 
260 	fmtinstall('M', dirmodefmt);
261 
262 	if (rflag) {
263 		if (!usefile) {
264 			if (cflag == 0) {
265 				fprint(2, "tar: can only create standard output archives\n");
266 				exits("arg error");
267 			}
268 			mt = dup(1, -1);
269 			nblock = 1;
270 		}
271 		else if ((mt = open(usefile, ORDWR)) < 0) {
272 			if (cflag == 0 || (mt = create(usefile, OWRITE, 0666)) < 0) {
273 				fprint(2, "tar: cannot open %s: %r\n", usefile);
274 				exits("open");
275 			}
276 		}
277 		dorep(argv);
278 	}
279 	else if (xflag)  {
280 		if (!usefile) {
281 			mt = dup(0, -1);
282 			nblock = 1;
283 		}
284 		else if ((mt = open(usefile, OREAD)) < 0) {
285 			fprint(2, "tar: cannot open %s: %r\n", usefile);
286 			exits("open");
287 		}
288 		doxtract(argv);
289 	}
290 	else if (tflag) {
291 		if (!usefile) {
292 			mt = dup(0, -1);
293 			nblock = 1;
294 		}
295 		else if ((mt = open(usefile, OREAD)) < 0) {
296 			fprint(2, "tar: cannot open %s: %r\n", usefile);
297 			exits("open");
298 		}
299 		dotable();
300 	}
301 	else
302 		usage();
303 	exits(0);
304 }
305 
306 void
307 usage(void)
308 {
309 	fprint(2, "tar: usage  tar {txrc}[Rvf] [tarfile] file1 file2...\n");
310 	exits("usage");
311 }
312 
313 void
314 dorep(char **argv)
315 {
316 	char cwdbuf[2048], *cwd, thisdir[2048];
317 	char *cp, *cp2;
318 	int cd;
319 
320 	if (getwd(cwdbuf, sizeof(cwdbuf)) == 0) {
321 		fprint(2, "tar: can't find current directory: %r\n");
322 		exits("cwd");
323 	}
324 	cwd = cwdbuf;
325 
326 	if (!cflag) {
327 		getdir();
328 		do {
329 			passtar();
330 			getdir();
331 		} while (!endtar());
332 	}
333 
334 	while (*argv) {
335 		cp2 = *argv;
336 		if (!strcmp(cp2, "-C") && argv[1]) {
337 			argv++;
338 			if (chdir(*argv) < 0)
339 				perror(*argv);
340 			cwd = *argv;
341 			argv++;
342 			continue;
343 		}
344 		cd = 0;
345 		for (cp = *argv; *cp; cp++)
346 			if (*cp == '/')
347 				cp2 = cp;
348 		if (cp2 != *argv) {
349 			*cp2 = '\0';
350 			chdir(*argv);
351 			if(**argv == '/')
352 				strncpy(thisdir, *argv, sizeof(thisdir));
353 			else
354 				snprint(thisdir, sizeof(thisdir), "%s/%s", cwd, *argv);
355 			*cp2 = '/';
356 			cp2++;
357 			cd = 1;
358 		} else
359 			strncpy(thisdir, cwd, sizeof(thisdir));
360 		putfile(thisdir, *argv++, cp2);
361 		if(cd && chdir(cwd) < 0) {
362 			fprint(2, "tar: can't cd back to %s: %r\n", cwd);
363 			exits("cwd");
364 		}
365 	}
366 	putempty();
367 	putempty();
368 	flushtar();
369 }
370 
371 int
372 endtar(void)
373 {
374 	if (dblock.dbuf.name[0] == '\0') {
375 		backtar();
376 		return(1);
377 	}
378 	else
379 		return(0);
380 }
381 
382 void
383 getdir(void)
384 {
385 	Dir *sp;
386 
387 	readtar((char*)&dblock);
388 	if (dblock.dbuf.name[0] == '\0')
389 		return;
390 	if(stbuf == nil){
391 		stbuf = malloc(sizeof(Dir));
392 		if(stbuf == nil)
393 			sysfatal("out of memory: %r");
394 	}
395 	sp = stbuf;
396 	sp->mode = strtol(dblock.dbuf.mode, 0, 8);
397 	sp->uid = "adm";
398 	sp->gid = "adm";
399 	sp->length = strtol(dblock.dbuf.size, 0, 8);
400 	sp->mtime = strtol(dblock.dbuf.mtime, 0, 8);
401 	chksum = strtol(dblock.dbuf.chksum, 0, 8);
402 	if (chksum != checksum())
403 		sysfatal("header checksum error");
404 	sp->qid.type = 0;
405 	ustar = isustar(&dblock.dbuf);
406 	getfullname(&dblock.dbuf);
407 	/* the mode test is ugly but sometimes necessary */
408 	if (dblock.dbuf.linkflag == LF_DIR || (sp->mode&0170000) == 040000 ||
409 	    strrchr(fullname, '\0')[-1] == '/') {
410 		sp->qid.type |= QTDIR;
411 		sp->mode |= DMDIR;
412 	}
413 }
414 
415 void
416 passtar(void)
417 {
418 	long blocks;
419 	char buf[TBLOCK];
420 
421 	switch (dblock.dbuf.linkflag) {
422 	case LF_LINK:
423 	case LF_SYMLINK1:
424 	case LF_SYMLINK2:
425 	case LF_FIFO:
426 		return;
427 	}
428 	blocks = stbuf->length;
429 	blocks += TBLOCK-1;
430 	blocks /= TBLOCK;
431 
432 	while (blocks-- > 0)
433 		readtar(buf);
434 }
435 
436 void
437 putfile(char *dir, char *longname, char *sname)
438 {
439 	int infile;
440 	long blocks;
441 	char buf[TBLOCK];
442 	char curdir[4096];
443 	char shortname[4096];
444 	char *cp;
445 	Dir *db;
446 	int i, n;
447 
448 	if(strlen(sname) > sizeof shortname - 3){
449 		fprint(2, "tar: %s: name too long (max %d)\n", sname, sizeof shortname - 3);
450 		return;
451 	}
452 
453 	snprint(shortname, sizeof shortname, "./%s", sname);
454 	infile = open(shortname, OREAD);
455 	if (infile < 0) {
456 		fprint(2, "tar: %s: cannot open file - %r\n", longname);
457 		return;
458 	}
459 
460 	if(stbuf != nil)
461 		free(stbuf);
462 	stbuf = dirfstat(infile);
463 
464 	if (stbuf->qid.type & QTDIR) {
465 		/* Directory */
466 		for (i = 0, cp = buf; *cp++ = longname[i++];);
467 		*--cp = '/';
468 		*++cp = 0;
469 		stbuf->length = 0;
470 
471 		tomodes(stbuf);
472 		if (putfullname(&dblock.dbuf, buf) < 0) {
473 			close(infile);
474 			return;		/* putfullname already complained */
475 		}
476 		dblock.dbuf.linkflag = LF_DIR;
477 		sprint(dblock.dbuf.chksum, "%6o", checksum());
478 		writetar( (char *) &dblock);
479 
480 		if (chdir(shortname) < 0) {
481 			fprint(2, "tar: can't cd to %s: %r\n", shortname);
482 			snprint(curdir, sizeof(curdir), "cd %s", shortname);
483 			exits(curdir);
484 		}
485 		sprint(curdir, "%s/%s", dir, sname);
486 		while ((n = dirread(infile, &db)) > 0) {
487 			for(i = 0; i < n; i++){
488 				strncpy(cp, db[i].name, sizeof buf - (cp-buf));
489 				putfile(curdir, buf, db[i].name);
490 			}
491 			free(db);
492 		}
493 		close(infile);
494 		if (chdir(dir) < 0 && chdir("..") < 0) {
495 			fprint(2, "tar: can't cd to ..(%s): %r\n", dir);
496 			snprint(curdir, sizeof(curdir), "cd ..(%s)", dir);
497 			exits(curdir);
498 		}
499 		return;
500 	}
501 
502 	/* plain file; write header block first */
503 	tomodes(stbuf);
504 	if (putfullname(&dblock.dbuf, longname) < 0) {
505 		close(infile);
506 		return;		/* putfullname already complained */
507 	}
508 	blocks = (stbuf->length + (TBLOCK-1)) / TBLOCK;
509 	if (vflag) {
510 		fprint(2, "a %s ", longname);
511 		fprint(2, "%ld blocks\n", blocks);
512 	}
513 	dblock.dbuf.linkflag = LF_PLAIN1;
514 	sprint(dblock.dbuf.chksum, "%6o", checksum());
515 	writetar( (char *) &dblock);
516 
517 	/* then copy contents */
518 	while ((i = readn(infile, buf, TBLOCK)) > 0 && blocks > 0) {
519 		writetar(buf);
520 		blocks--;
521 	}
522 	close(infile);
523 	if (blocks != 0 || i != 0)
524 		fprint(2, "%s: file changed size\n", longname);
525 	while (blocks-- >  0)
526 		putempty();
527 }
528 
529 
530 void
531 doxtract(char **argv)
532 {
533 	Dir null;
534 	int wrsize;
535 	long blocks, bytes;
536 	char buf[TBLOCK], outname[Maxname+3+1];
537 	char **cp;
538 	int ofile;
539 
540 	for (;;) {
541 		getdir();
542 		if (endtar())
543 			break;
544 
545 		if (*argv == 0)
546 			goto gotit;
547 
548 		for (cp = argv; *cp; cp++)
549 			if (prefix(*cp, fullname))
550 				goto gotit;
551 		passtar();
552 		continue;
553 
554 gotit:
555 		if(checkdir(fullname, stbuf->mode, &stbuf->qid))
556 			continue;
557 
558 		if (dblock.dbuf.linkflag == LF_LINK) {
559 			fprint(2, "tar: can't link %s %s\n",
560 				dblock.dbuf.linkname, fullname);
561 			remove(fullname);
562 			continue;
563 		}
564 		if (dblock.dbuf.linkflag == LF_SYMLINK1 ||
565 		    dblock.dbuf.linkflag == LF_SYMLINK2) {
566 			fprint(2, "tar: %s: cannot symlink\n", fullname);
567 			continue;
568 		}
569 		if(fullname[0] != '/' || Rflag)
570 			sprint(outname, "./%s", fullname);
571 		else
572 			strcpy(outname, fullname);
573 		if ((ofile = create(outname, OWRITE, stbuf->mode & 0777)) < 0) {
574 			fprint(2, "tar: %s - cannot create: %r\n", outname);
575 			passtar();
576 			continue;
577 		}
578 
579 		blocks = ((bytes = stbuf->length) + TBLOCK-1)/TBLOCK;
580 		if (vflag)
581 			fprint(2, "x %s, %ld bytes\n", fullname, bytes);
582 		while (blocks-- > 0) {
583 			readtar(buf);
584 			wrsize = (bytes > TBLOCK? TBLOCK: bytes);
585 			if (write(ofile, buf, wrsize) != wrsize) {
586 				fprint(2,
587 				    "tar: %s: HELP - extract write error: %r\n",
588 					fullname);
589 				exits("extract write");
590 			}
591 			bytes -= TBLOCK;
592 		}
593 		if(Tflag){
594 			nulldir(&null);
595 			null.mtime = stbuf->mtime;
596 			dirfwstat(ofile, &null);
597 		}
598 		close(ofile);
599 	}
600 }
601 
602 void
603 dotable(void)
604 {
605 	for (;;) {
606 		getdir();
607 		if (endtar())
608 			break;
609 		if (vflag)
610 			longt(stbuf);
611 		Bprint(&bout, "%s", fullname);
612 		if (dblock.dbuf.linkflag == '1')
613 			Bprint(&bout, " linked to %s", dblock.dbuf.linkname);
614 		if (dblock.dbuf.linkflag == 's')
615 			Bprint(&bout, " -> %s", dblock.dbuf.linkname);
616 		Bprint(&bout, "\n");
617 		passtar();
618 	}
619 }
620 
621 void
622 putempty(void)
623 {
624 	char buf[TBLOCK];
625 
626 	memset(buf, 0, TBLOCK);
627 	writetar(buf);
628 }
629 
630 void
631 longt(Dir *st)
632 {
633 	char *cp;
634 
635 	Bprint(&bout, "%M %4d/%1d ", st->mode, 0, 0);	/* 0/0 uid/gid */
636 	Bprint(&bout, "%8lld", st->length);
637 	cp = ctime(st->mtime);
638 	Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24);
639 }
640 
641 int
642 checkdir(char *name, int mode, Qid *qid)
643 {
644 	char *cp;
645 	int f;
646 	Dir *d, null;
647 
648 	if(Rflag && *name == '/')
649 		name++;
650 	cp = name;
651 	if(*cp == '/')
652 		cp++;
653 	for (; *cp; cp++) {
654 		if (*cp == '/') {
655 			*cp = '\0';
656 			if (access(name, 0) < 0) {
657 				f = create(name, OREAD, DMDIR + 0775L);
658 				if(f < 0)
659 					fprint(2, "tar: mkdir %s failed: %r\n", name);
660 				close(f);
661 			}
662 			*cp = '/';
663 		}
664 	}
665 
666 	/* if this is a directory, chmod it to the mode in the tar plus 700 */
667 	if(cp[-1] == '/' || (qid->type&QTDIR)){
668 		if((d=dirstat(name)) != 0){
669 			nulldir(&null);
670 			null.mode = DMDIR | (mode & 0777) | 0700;
671 			dirwstat(name, &null);
672 			free(d);
673 		}
674 		return 1;
675 	} else
676 		return 0;
677 }
678 
679 void
680 tomodes(Dir *sp)
681 {
682 	memset(dblock.dummy, 0, sizeof(dblock.dummy));
683 	sprint(dblock.dbuf.mode, "%6lo ", sp->mode & 0777);
684 	sprint(dblock.dbuf.uid, "%6o ", uflag);
685 	sprint(dblock.dbuf.gid, "%6o ", gflag);
686 	sprint(dblock.dbuf.size, "%11llo ", sp->length);
687 	sprint(dblock.dbuf.mtime, "%11lo ", sp->mtime);
688 	if (posix) {
689 		setustar(&dblock.dbuf);
690 		strncpy(dblock.dbuf.uname, sp->uid, sizeof dblock.dbuf.uname);
691 		strncpy(dblock.dbuf.gname, sp->gid, sizeof dblock.dbuf.gname);
692 	}
693 }
694 
695 int
696 checksum(void)
697 {
698 	int i;
699 	char *cp;
700 
701 	for (cp = dblock.dbuf.chksum; cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++)
702 		*cp = ' ';
703 	i = 0;
704 	for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
705 		i += *cp & 0xff;
706 	return(i);
707 }
708 
709 int
710 prefix(char *s1, char *s2)
711 {
712 	while (*s1)
713 		if (*s1++ != *s2++)
714 			return(0);
715 	if (*s2)
716 		return(*s2 == '/');
717 	return(1);
718 }
719 
720 int
721 readtar(char *buffer)
722 {
723 	int i;
724 
725 	if (recno >= nblock || first == 0) {
726 		if ((i = readn(mt, tbuf, TBLOCK*nblock)) <= 0) {
727 			fprint(2, "tar: archive read error: %r\n");
728 			exits("archive read");
729 		}
730 		if (first == 0) {
731 			if ((i % TBLOCK) != 0) {
732 				fprint(2, "tar: archive blocksize error: %r\n");
733 				exits("blocksize");
734 			}
735 			i /= TBLOCK;
736 			if (i != nblock) {
737 				fprint(2, "tar: blocksize = %d\n", i);
738 				nblock = i;
739 			}
740 		}
741 		recno = 0;
742 	}
743 	first = 1;
744 	memmove(buffer, &tbuf[recno++], TBLOCK);
745 	return(TBLOCK);
746 }
747 
748 int
749 writetar(char *buffer)
750 {
751 	first = 1;
752 	if (recno >= nblock) {
753 		if (write(mt, tbuf, TBLOCK*nblock) != TBLOCK*nblock) {
754 			fprint(2, "tar: archive write error: %r\n");
755 			exits("write");
756 		}
757 		recno = 0;
758 	}
759 	memmove(&tbuf[recno++], buffer, TBLOCK);
760 	if (recno >= nblock) {
761 		if (write(mt, tbuf, TBLOCK*nblock) != TBLOCK*nblock) {
762 			fprint(2, "tar: archive write error: %r\n");
763 			exits("write");
764 		}
765 		recno = 0;
766 	}
767 	return(TBLOCK);
768 }
769 
770 /*
771  * backup over last tar block
772  */
773 void
774 backtar(void)
775 {
776 	seek(mt, -TBLOCK*nblock, 1);
777 	recno--;
778 }
779 
780 void
781 flushtar(void)
782 {
783 	write(mt, tbuf, TBLOCK*nblock);
784 }
785