xref: /plan9/sys/src/cmd/tar.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
1 /*
2  * tar - `tape archiver', actually usable on any medium.
3  *	POSIX "ustar" compliant when extracting, and by default when creating.
4  *	this tar attempts to read and write multiple Tblock-byte blocks
5  *	at once to and from the filesystem, and does not copy blocks
6  *	around internally.
7  */
8 
9 #include <u.h>
10 #include <libc.h>
11 #include <fcall.h>		/* for %M */
12 #include <String.h>
13 
14 /*
15  * modified versions of those in libc.h; scans only the first arg for
16  * keyletters and options.
17  */
18 #define	TARGBEGIN {\
19 	(argv0 || (argv0 = *argv)), argv++, argc--;\
20 	if (argv[0]) {\
21 		char *_args, *_argt;\
22 		Rune _argc;\
23 		_args = &argv[0][0];\
24 		_argc = 0;\
25 		while(*_args && (_args += chartorune(&_argc, _args)))\
26 			switch(_argc)
27 #define	TARGEND	SET(_argt); USED(_argt);USED(_argc);USED(_args); \
28 	argc--, argv++; } \
29 	USED(argv); USED(argc); }
30 #define	TARGC() (_argc)
31 
32 #define ROUNDUP(a, b)	(((a) + (b) - 1)/(b))
33 #define BYTES2TBLKS(bytes) ROUNDUP(bytes, Tblock)
34 
35 /* read big-endian binary integers; args must be (uchar *) */
36 #define	G2BEBYTE(x)	(((x)[0]<<8)  |  (x)[1])
37 #define	G3BEBYTE(x)	(((x)[0]<<16) | ((x)[1]<<8)  |  (x)[2])
38 #define	G4BEBYTE(x)	(((x)[0]<<24) | ((x)[1]<<16) | ((x)[2]<<8) | (x)[3])
39 #define	G8BEBYTE(x)	(((vlong)G4BEBYTE(x)<<32) | (u32int)G4BEBYTE((x)+4))
40 
41 typedef vlong Off;
42 typedef char *(*Refill)(int ar, char *bufs, int justhdr);
43 
44 enum { Stdin, Stdout, Stderr };
45 enum { Rd, Wr };			/* pipe fd-array indices */
46 enum { Output, Input };
47 enum { None, Toc, Xtract, Replace };
48 enum { Alldata, Justnxthdr };
49 enum {
50 	Tblock = 512,
51 	Namsiz = 100,
52 	Maxpfx = 155,		/* from POSIX */
53 	Maxname = Namsiz + 1 + Maxpfx,
54 	Binsize = 0x80,		/* flag in size[0], from gnu: positive binary size */
55 	Binnegsz = 0xff,	/* flag in size[0]: negative binary size */
56 
57 	Nblock = 40,		/* maximum blocksize */
58 	Dblock = 20,		/* default blocksize */
59 	DEBUG = 0,
60 };
61 
62 /* POSIX link flags */
63 enum {
64 	LF_PLAIN1 =	'\0',
65 	LF_PLAIN2 =	'0',
66 	LF_LINK =	'1',
67 	LF_SYMLINK1 =	'2',
68 	LF_SYMLINK2 =	's',		/* 4BSD used this */
69 	LF_CHR =	'3',
70 	LF_BLK =	'4',
71 	LF_DIR =	'5',
72 	LF_FIFO =	'6',
73 	LF_CONTIG =	'7',
74 	/* 'A' - 'Z' are reserved for custom implementations */
75 };
76 
77 #define islink(lf)	(isreallink(lf) || issymlink(lf))
78 #define isreallink(lf)	((lf) == LF_LINK)
79 #define issymlink(lf)	((lf) == LF_SYMLINK1 || (lf) == LF_SYMLINK2)
80 
81 typedef union {
82 	uchar	data[Tblock];
83 	struct {
84 		char	name[Namsiz];
85 		char	mode[8];
86 		char	uid[8];
87 		char	gid[8];
88 		char	size[12];
89 		char	mtime[12];
90 		char	chksum[8];
91 		char	linkflag;
92 		char	linkname[Namsiz];
93 
94 		/* rest are defined by POSIX's ustar format; see p1003.2b */
95 		char	magic[6];	/* "ustar" */
96 		char	version[2];
97 		char	uname[32];
98 		char	gname[32];
99 		char	devmajor[8];
100 		char	devminor[8];
101 		char	prefix[Maxpfx]; /* if non-null, path= prefix "/" name */
102 	};
103 } Hdr;
104 
105 typedef struct {
106 	char	*comp;
107 	char	*decomp;
108 	char	*sfx[4];
109 } Compress;
110 
111 static Compress comps[] = {
112 	"gzip",		"gunzip",	{ ".tar.gz", ".tgz" },	/* default */
113 	"compress",	"uncompress",	{ ".tar.Z",  ".tz" },
114 	"bzip2",	"bunzip2",	{ ".tar.bz", ".tbz",
115 					  ".tar.bz2",".tbz2" },
116 };
117 
118 typedef struct {
119 	int	kid;
120 	int	fd;	/* original fd */
121 	int	rfd;	/* replacement fd */
122 	int	input;
123 	int	open;
124 } Pushstate;
125 
126 #define OTHER(rdwr) (rdwr == Rd? Wr: Rd)
127 
128 static int debug;
129 static int verb;
130 static int posix = 1;
131 static int docreate;
132 static int aruid;
133 static int argid;
134 static int relative = 1;
135 static int settime;
136 static int verbose;
137 static int docompress;
138 static int keepexisting;
139 static Off blkoff;	/* offset of the current archive block (not Tblock) */
140 static Off nexthdr;
141 
142 static int nblock = Dblock;
143 static char *usefile;
144 static char origdir[Maxname*2];
145 static Hdr *tpblk, *endblk;
146 static Hdr *curblk;
147 
148 static void
149 usage(void)
150 {
151 	fprint(2, "usage: %s {crtx}[PRTfgkmpuvz] [archive] file1 file2...\n",
152 		argv0);
153 	exits("usage");
154 }
155 
156 /* compression */
157 
158 static Compress *
159 compmethod(char *name)
160 {
161 	int i, nmlen = strlen(name), sfxlen;
162 	Compress *cp;
163 
164 	for (cp = comps; cp < comps + nelem(comps); cp++)
165 		for (i = 0; i < nelem(cp->sfx) && cp->sfx[i]; i++) {
166 			sfxlen = strlen(cp->sfx[i]);
167 			if (nmlen > sfxlen &&
168 			    strcmp(cp->sfx[i], name + nmlen - sfxlen) == 0)
169 				return cp;
170 		}
171 	return docompress? comps: nil;
172 }
173 
174 /*
175  * push a filter, cmd, onto fd.  if input, it's an input descriptor.
176  * returns a descriptor to replace fd, or -1 on error.
177  */
178 static int
179 push(int fd, char *cmd, int input, Pushstate *ps)
180 {
181 	int nfd, pifds[2];
182 	String *s;
183 
184 	ps->open = 0;
185 	ps->fd = fd;
186 	ps->input = input;
187 	if (fd < 0 || pipe(pifds) < 0)
188 		return -1;
189 	ps->kid = fork();
190 	switch (ps->kid) {
191 	case -1:
192 		return -1;
193 	case 0:
194 		if (input)
195 			dup(pifds[Wr], Stdout);
196 		else
197 			dup(pifds[Rd], Stdin);
198 		close(pifds[input? Rd: Wr]);
199 		dup(fd, (input? Stdin: Stdout));
200 		s = s_new();
201 		if (cmd[0] != '/')
202 			s_append(s, "/bin/");
203 		s_append(s, cmd);
204 		execl(s_to_c(s), cmd, nil);
205 		sysfatal("can't exec %s: %r", cmd);
206 	default:
207 		nfd = pifds[input? Rd: Wr];
208 		close(pifds[input? Wr: Rd]);
209 		break;
210 	}
211 	ps->rfd = nfd;
212 	ps->open = 1;
213 	return nfd;
214 }
215 
216 static char *
217 pushclose(Pushstate *ps)
218 {
219 	Waitmsg *wm;
220 
221 	if (ps->fd < 0 || ps->rfd < 0 || !ps->open)
222 		return "not open";
223 	close(ps->rfd);
224 	ps->rfd = -1;
225 	ps->open = 0;
226 	while ((wm = wait()) != nil && wm->pid != ps->kid)
227 		continue;
228 	return wm? wm->msg: nil;
229 }
230 
231 /*
232  * block-buffer management
233  */
234 
235 static void
236 initblks(void)
237 {
238 	free(tpblk);
239 	tpblk = malloc(Tblock * nblock);
240 	assert(tpblk != nil);
241 	endblk = tpblk + nblock;
242 }
243 
244 /*
245  * (re)fill block buffers from archive.  `justhdr' means we don't care
246  * about the data before the next header block.
247  */
248 static char *
249 refill(int ar, char *bufs, int justhdr)
250 {
251 	int i, n;
252 	unsigned bytes = Tblock * nblock;
253 	static int done, first = 1, seekable;
254 
255 	if (done)
256 		return nil;
257 
258 	if (first)
259 		seekable = seek(ar, 0, 1) >= 0;
260 	blkoff = seek(ar, 0, 1);		/* note position for `tar r' */
261 	/* try to size non-pipe input at first read */
262 	if (first && usefile) {
263 		n = read(ar, bufs, bytes);
264 		if (n <= 0)
265 			sysfatal("error reading archive: %r");
266 		i = n;
267 		if (i % Tblock != 0) {
268 			fprint(2, "%s: archive block size (%d) error\n",
269 				argv0, i);
270 			exits("blocksize");
271 		}
272 		i /= Tblock;
273 		if (i != nblock) {
274 			nblock = i;
275 			fprint(2, "%s: blocking = %d\n", argv0, nblock);
276 			endblk = (Hdr *)bufs + nblock;
277 			bytes = n;
278 		}
279 	} else if (justhdr && seekable && nexthdr - seek(ar, 0, 1) >= bytes) {
280 		/* optimisation for huge archive members on seekable media */
281 		if (seek(ar, bytes, 1) < 0)
282 			sysfatal("can't seek on archive: %r");
283 		n = bytes;
284 	} else
285 		n = readn(ar, bufs, bytes);
286 	first = 0;
287 
288 	if (n == 0)
289 		sysfatal("unexpected EOF reading archive");
290 	else if (n < 0)
291 		sysfatal("error reading archive: %r");
292 	else if (n%Tblock != 0)
293 		sysfatal("partial block read from archive");
294 	if (n != bytes) {
295 		done = 1;
296 		memset(bufs + n, 0, bytes - n);
297 	}
298 	return bufs;
299 }
300 
301 static Hdr *
302 getblk(int ar, Refill rfp, int justhdr)
303 {
304 	if (curblk == nil || curblk >= endblk) {  /* input block exhausted? */
305 		if (rfp != nil && (*rfp)(ar, (char *)tpblk, justhdr) == nil)
306 			return nil;
307 		curblk = tpblk;
308 	}
309 	return curblk++;
310 }
311 
312 static Hdr *
313 getblkrd(int ar, int justhdr)
314 {
315 	return getblk(ar, refill, justhdr);
316 }
317 
318 static Hdr *
319 getblke(int ar)
320 {
321 	return getblk(ar, nil, Alldata);
322 }
323 
324 static Hdr *
325 getblkz(int ar)
326 {
327 	Hdr *hp = getblke(ar);
328 
329 	if (hp != nil)
330 		memset(hp->data, 0, Tblock);
331 	return hp;
332 }
333 
334 /*
335  * how many block buffers are available, starting at the address
336  * just returned by getblk*?
337  */
338 static int
339 gothowmany(int max)
340 {
341 	int n = endblk - (curblk - 1);
342 
343 	return n > max? max: n;
344 }
345 
346 /*
347  * indicate that one is done with the last block obtained from getblke
348  * and it is now available to be written into the archive.
349  */
350 static void
351 putlastblk(int ar)
352 {
353 	unsigned bytes = Tblock * nblock;
354 
355 	/* if writing end-of-archive, aid compression (good hygiene too) */
356 	if (curblk < endblk)
357 		memset(curblk, 0, (char *)endblk - (char *)curblk);
358 	if (write(ar, tpblk, bytes) != bytes)
359 		sysfatal("error writing archive: %r");
360 }
361 
362 static void
363 putblk(int ar)
364 {
365 	if (curblk >= endblk)
366 		putlastblk(ar);
367 }
368 
369 static void
370 putbackblk(int ar)
371 {
372 	curblk--;
373 	USED(ar);
374 }
375 
376 static void
377 putreadblks(int ar, int blks)
378 {
379 	curblk += blks - 1;
380 	USED(ar);
381 }
382 
383 static void
384 putblkmany(int ar, int blks)
385 {
386 	curblk += blks - 1;
387 	putblk(ar);
388 }
389 
390 /*
391  * common routines
392  */
393 
394 /*
395  * modifies hp->chksum but restores it; important for the last block of the
396  * old archive when updating with `tar rf archive'
397  */
398 static long
399 chksum(Hdr *hp)
400 {
401 	int n = Tblock;
402 	long i = 0;
403 	uchar *cp = hp->data;
404 	char oldsum[sizeof hp->chksum];
405 
406 	memmove(oldsum, hp->chksum, sizeof oldsum);
407 	memset(hp->chksum, ' ', sizeof hp->chksum);
408 	while (n-- > 0)
409 		i += *cp++;
410 	memmove(hp->chksum, oldsum, sizeof oldsum);
411 	return i;
412 }
413 
414 static int
415 isustar(Hdr *hp)
416 {
417 	return strcmp(hp->magic, "ustar") == 0;
418 }
419 
420 /*
421  * s is at most n bytes long, but need not be NUL-terminated.
422  * if shorter than n bytes, all bytes after the first NUL must also
423  * be NUL.
424  */
425 static int
426 strnlen(char *s, int n)
427 {
428 	return s[n - 1] != '\0'? n: strlen(s);
429 }
430 
431 /* set fullname from header */
432 static char *
433 name(Hdr *hp)
434 {
435 	int pfxlen, namlen;
436 	static char fullnamebuf[2 + Maxname + 1];	/* 2 at beginning for ./ on relative names */
437 	char *fullname;
438 
439 	fullname = fullnamebuf+2;
440 	namlen = strnlen(hp->name, sizeof hp->name);
441 	if (hp->prefix[0] == '\0' || !isustar(hp)) {	/* old-style name? */
442 		memmove(fullname, hp->name, namlen);
443 		fullname[namlen] = '\0';
444 		return fullname;
445 	}
446 
447 	/* name is in two pieces */
448 	pfxlen = strnlen(hp->prefix, sizeof hp->prefix);
449 	memmove(fullname, hp->prefix, pfxlen);
450 	fullname[pfxlen] = '/';
451 	memmove(fullname + pfxlen + 1, hp->name, namlen);
452 	fullname[pfxlen + 1 + namlen] = '\0';
453 	return fullname;
454 }
455 
456 static int
457 isdir(Hdr *hp)
458 {
459 	/* the mode test is ugly but sometimes necessary */
460 	return hp->linkflag == LF_DIR ||
461 		strrchr(name(hp), '\0')[-1] == '/' ||
462 		(strtoul(hp->mode, nil, 8)&0170000) == 040000;
463 }
464 
465 static int
466 eotar(Hdr *hp)
467 {
468 	return name(hp)[0] == '\0';
469 }
470 
471 /*
472 static uvlong
473 getbe(uchar *src, int size)
474 {
475 	uvlong vl = 0;
476 
477 	while (size-- > 0) {
478 		vl <<= 8;
479 		vl |= *src++;
480 	}
481 	return vl;
482 }
483  */
484 
485 static void
486 putbe(uchar *dest, uvlong vl, int size)
487 {
488 	for (dest += size; size-- > 0; vl >>= 8)
489 		*--dest = vl;
490 }
491 
492 /*
493  * return the nominal size from the header block, which is not always the
494  * size in the archive (the archive size may be zero for some file types
495  * regardless of the nominal size).
496  *
497  * gnu and freebsd tars are now recording vlongs as big-endian binary
498  * with a flag in byte 0 to indicate this, which permits file sizes up to
499  * 2^64-1 (actually 2^80-1 but our file sizes are vlongs) rather than 2^33-1.
500  */
501 static Off
502 hdrsize(Hdr *hp)
503 {
504 	uchar *p;
505 
506 	if((uchar)hp->size[0] == Binnegsz) {
507 		fprint(2, "%s: %s: negative length, which is insane\n",
508 			argv0, name(hp));
509 		return 0;
510 	} else if((uchar)hp->size[0] == Binsize) {
511 		p = (uchar *)hp->size + sizeof hp->size - 1 -
512 			sizeof(vlong);		/* -1 for terminating space */
513 		return G8BEBYTE(p);
514 	} else
515 		return strtoull(hp->size, nil, 8);
516 }
517 
518 /*
519  * return the number of bytes recorded in the archive.
520  */
521 static Off
522 arsize(Hdr *hp)
523 {
524 	if(isdir(hp) || islink(hp->linkflag))
525 		return 0;
526 	return hdrsize(hp);
527 }
528 
529 static Hdr *
530 readhdr(int ar)
531 {
532 	long hdrcksum;
533 	Hdr *hp;
534 
535 	hp = getblkrd(ar, Alldata);
536 	if (hp == nil)
537 		sysfatal("unexpected EOF instead of archive header");
538 	if (eotar(hp))			/* end-of-archive block? */
539 		return nil;
540 	hdrcksum = strtoul(hp->chksum, nil, 8);
541 	if (chksum(hp) != hdrcksum)
542 		sysfatal("bad archive header checksum: name %.64s...",
543 			hp->name);
544 	nexthdr += Tblock*(1 + BYTES2TBLKS(arsize(hp)));
545 	return hp;
546 }
547 
548 /*
549  * tar r[c]
550  */
551 
552 /*
553  * if name is longer than Namsiz bytes, try to split it at a slash and fit the
554  * pieces into hp->prefix and hp->name.
555  */
556 static int
557 putfullname(Hdr *hp, char *name)
558 {
559 	int namlen, pfxlen;
560 	char *sl, *osl;
561 	String *slname = nil;
562 
563 	if (isdir(hp)) {
564 		slname = s_new();
565 		s_append(slname, name);
566 		s_append(slname, "/");		/* posix requires this */
567 		name = s_to_c(slname);
568 	}
569 
570 	namlen = strlen(name);
571 	if (namlen <= Namsiz) {
572 		strncpy(hp->name, name, Namsiz);
573 		hp->prefix[0] = '\0';		/* ustar paranoia */
574 		return 0;
575 	}
576 
577 	if (!posix || namlen > Maxname) {
578 		fprint(2, "%s: name too long for tar header: %s\n",
579 			argv0, name);
580 		return -1;
581 	}
582 	/*
583 	 * try various splits until one results in pieces that fit into the
584 	 * appropriate fields of the header.  look for slashes from right
585 	 * to left, in the hopes of putting the largest part of the name into
586 	 * hp->prefix, which is larger than hp->name.
587 	 */
588 	sl = strrchr(name, '/');
589 	while (sl != nil) {
590 		pfxlen = sl - name;
591 		if (pfxlen <= sizeof hp->prefix && namlen-1 - pfxlen <= Namsiz)
592 			break;
593 		osl = sl;
594 		*osl = '\0';
595 		sl = strrchr(name, '/');
596 		*osl = '/';
597 	}
598 	if (sl == nil) {
599 		fprint(2, "%s: name can't be split to fit tar header: %s\n",
600 			argv0, name);
601 		return -1;
602 	}
603 	*sl = '\0';
604 	strncpy(hp->prefix, name, sizeof hp->prefix);
605 	*sl++ = '/';
606 	strncpy(hp->name, sl, sizeof hp->name);
607 	if (slname)
608 		s_free(slname);
609 	return 0;
610 }
611 
612 static int
613 mkhdr(Hdr *hp, Dir *dir, char *file)
614 {
615 	/*
616 	 * these fields run together, so we format them in order and don't use
617 	 * snprint.
618 	 */
619 	sprint(hp->mode, "%6lo ", dir->mode & 0777);
620 	sprint(hp->uid, "%6o ", aruid);
621 	sprint(hp->gid, "%6o ", argid);
622 	if (dir->length >= (Off)1<<32) {
623 		static int printed;
624 
625 		if (!printed) {
626 			printed = 1;
627 			fprint(2, "%s: storing large sizes in \"base 256\"\n", argv0);
628 		}
629 		hp->size[0] = Binsize;
630 		/* emit so-called `base 256' representation of size */
631 		putbe((uchar *)hp->size+1, dir->length, sizeof hp->size - 2);
632 		hp->size[sizeof hp->size - 1] = ' ';
633 	} else
634 		sprint(hp->size, "%11lluo ", dir->length);
635 	sprint(hp->mtime, "%11luo ", dir->mtime);
636 	hp->linkflag = (dir->mode&DMDIR? LF_DIR: LF_PLAIN1);
637 	putfullname(hp, file);
638 	if (posix) {
639 		strncpy(hp->magic, "ustar", sizeof hp->magic);
640 		strncpy(hp->version, "00", sizeof hp->version);
641 		strncpy(hp->uname, dir->uid, sizeof hp->uname);
642 		strncpy(hp->gname, dir->gid, sizeof hp->gname);
643 	}
644 	sprint(hp->chksum, "%6luo", chksum(hp));
645 	return 0;
646 }
647 
648 static void addtoar(int ar, char *file, char *shortf);
649 
650 static void
651 addtreetoar(int ar, char *file, char *shortf, int fd)
652 {
653 	int n;
654 	Dir *dent, *dirents;
655 	String *name = s_new();
656 
657 	n = dirreadall(fd, &dirents);
658 	close(fd);
659 	if (n == 0)
660 		return;
661 
662 	if (chdir(shortf) < 0)
663 		sysfatal("chdir %s: %r", file);
664 	if (DEBUG)
665 		fprint(2, "chdir %s\t# %s\n", shortf, file);
666 
667 	for (dent = dirents; dent < dirents + n; dent++) {
668 		s_reset(name);
669 		s_append(name, file);
670 		s_append(name, "/");
671 		s_append(name, dent->name);
672 		addtoar(ar, s_to_c(name), dent->name);
673 	}
674 	s_free(name);
675 	free(dirents);
676 
677 	/*
678 	 * this assumes that shortf is just one component, which is true
679 	 * during directory descent, but not necessarily true of command-line
680 	 * arguments.  Our caller (or addtoar's) must reset the working
681 	 * directory if necessary.
682 	 */
683 	if (chdir("..") < 0)
684 		sysfatal("chdir %s/..: %r", file);
685 	if (DEBUG)
686 		fprint(2, "chdir ..\n");
687 }
688 
689 static void
690 addtoar(int ar, char *file, char *shortf)
691 {
692 	int n, fd, isdir;
693 	long bytes;
694 	ulong blksleft, blksread;
695 	Hdr *hbp;
696 	Dir *dir;
697 	String *name = nil;
698 
699 	if (shortf[0] == '#') {
700 		name = s_new();
701 		s_append(name, "./");
702 		s_append(name, shortf);
703 		shortf = s_to_c(name);
704 	}
705 
706 	fd = open(shortf, OREAD);
707 	if (fd < 0) {
708 		fprint(2, "%s: can't open %s: %r\n", argv0, file);
709 		if (name)
710 			s_free(name);
711 		return;
712 	}
713 	dir = dirfstat(fd);
714 	if (dir == nil)
715 		sysfatal("can't fstat %s: %r", file);
716 
717 	hbp = getblkz(ar);
718 	isdir = !!(dir->qid.type&QTDIR);
719 	if (mkhdr(hbp, dir, file) < 0) {
720 		putbackblk(ar);
721 		free(dir);
722 		close(fd);
723 		if (name)
724 			s_free(name);
725 		return;
726 	}
727 	putblk(ar);
728 
729 	blksleft = BYTES2TBLKS(dir->length);
730 	free(dir);
731 
732 	if (isdir)
733 		addtreetoar(ar, file, shortf, fd);
734 	else {
735 		for (; blksleft > 0; blksleft -= blksread) {
736 			hbp = getblke(ar);
737 			blksread = gothowmany(blksleft);
738 			bytes = blksread * Tblock;
739 			n = readn(fd, hbp->data, bytes);
740 			if (n < 0)
741 				sysfatal("error reading %s: %r", file);
742 			/*
743 			 * ignore EOF.  zero any partial block to aid
744 			 * compression and emergency recovery of data.
745 			 */
746 			if (n < Tblock)
747 				memset(hbp->data + n, 0, bytes - n);
748 			putblkmany(ar, blksread);
749 		}
750 		close(fd);
751 		if (verbose)
752 			fprint(2, "%s\n", file);
753 	}
754 	if (name)
755 		s_free(name);
756 }
757 
758 static char *
759 replace(char **argv)
760 {
761 	int i, ar;
762 	ulong blksleft, blksread;
763 	Off bytes;
764 	Hdr *hp;
765 	Compress *comp = nil;
766 	Pushstate ps;
767 
768 	if (usefile && docreate) {
769 		ar = create(usefile, OWRITE, 0666);
770 		if (docompress)
771 			comp = compmethod(usefile);
772 	} else if (usefile)
773 		ar = open(usefile, ORDWR);
774 	else
775 		ar = Stdout;
776 	if (comp)
777 		ar = push(ar, comp->comp, Output, &ps);
778 	if (ar < 0)
779 		sysfatal("can't open archive %s: %r", usefile);
780 
781 	if (usefile && !docreate) {
782 		/* skip quickly to the end */
783 		while ((hp = readhdr(ar)) != nil) {
784 			bytes = arsize(hp);
785 			for (blksleft = BYTES2TBLKS(bytes);
786 			     blksleft > 0 && getblkrd(ar, Justnxthdr) != nil;
787 			     blksleft -= blksread) {
788 				blksread = gothowmany(blksleft);
789 				putreadblks(ar, blksread);
790 			}
791 		}
792 		/*
793 		 * we have just read the end-of-archive Tblock.
794 		 * now seek back over the (big) archive block containing it,
795 		 * and back up curblk ptr over end-of-archive Tblock in memory.
796 		 */
797 		if (seek(ar, blkoff, 0) < 0)
798 			sysfatal("can't seek back over end-of-archive: %r");
799 		curblk--;
800 	}
801 
802 	for (i = 0; argv[i] != nil; i++) {
803 		addtoar(ar, argv[i], argv[i]);
804 		chdir(origdir);		/* for correctness & profiling */
805 	}
806 
807 	/* write end-of-archive marker */
808 	getblkz(ar);
809 	putblk(ar);
810 	getblkz(ar);
811 	putlastblk(ar);
812 
813 	if (comp)
814 		return pushclose(&ps);
815 	if (ar > Stderr)
816 		close(ar);
817 	return nil;
818 }
819 
820 /*
821  * tar [xt]
822  */
823 
824 /* is pfx a file-name prefix of name? */
825 static int
826 prefix(char *name, char *pfx)
827 {
828 	int pfxlen = strlen(pfx);
829 	char clpfx[Maxname+1];
830 
831 	if (pfxlen > Maxname)
832 		return 0;
833 	strcpy(clpfx, pfx);
834 	cleanname(clpfx);
835 	return strncmp(pfx, name, pfxlen) == 0 &&
836 		(name[pfxlen] == '\0' || name[pfxlen] == '/');
837 }
838 
839 static int
840 match(char *name, char **argv)
841 {
842 	int i;
843 	char clname[Maxname+1];
844 
845 	if (argv[0] == nil)
846 		return 1;
847 	strcpy(clname, name);
848 	cleanname(clname);
849 	for (i = 0; argv[i] != nil; i++)
850 		if (prefix(clname, argv[i]))
851 			return 1;
852 	return 0;
853 }
854 
855 static void
856 cantcreate(char *s, int mode)
857 {
858 	int len;
859 	static char *last;
860 
861 	/*
862 	 * Always print about files.  Only print about directories
863 	 * we haven't printed about.  (Assumes archive is ordered
864 	 * nicely.)
865 	 */
866 	if(mode&DMDIR){
867 		if(last){
868 			/* already printed this directory */
869 			if(strcmp(s, last) == 0)
870 				return;
871 			/* printed a higher directory, so printed this one */
872 			len = strlen(s);
873 			if(memcmp(s, last, len) == 0 && last[len] == '/')
874 				return;
875 		}
876 		/* save */
877 		free(last);
878 		last = strdup(s);
879 	}
880 	fprint(2, "%s: can't create %s: %r\n", argv0, s);
881 }
882 
883 static int
884 makedir(char *s)
885 {
886 	int f;
887 
888 	if (access(s, AEXIST) == 0)
889 		return -1;
890 	f = create(s, OREAD, DMDIR | 0777);
891 	if (f >= 0)
892 		close(f);
893 	else
894 		cantcreate(s, DMDIR);
895 	return f;
896 }
897 
898 static int
899 mkpdirs(char *s)
900 {
901 	int err;
902 	char *p;
903 
904 	p = s;
905 	err = 0;
906 	while (!err && (p = strchr(p+1, '/')) != nil) {
907 		*p = '\0';
908 		err = (access(s, AEXIST) < 0 && makedir(s) < 0);
909 		*p = '/';
910 	}
911 	return -err;
912 }
913 
914 /* Call access but preserve the error string. */
915 static int
916 xaccess(char *name, int mode)
917 {
918 	char err[ERRMAX];
919 	int rv;
920 
921 	err[0] = 0;
922 	errstr(err, sizeof err);
923 	rv = access(name, mode);
924 	errstr(err, sizeof err);
925 	return rv;
926 }
927 
928 /* copy a file from the archive into the filesystem */
929 /* fname is result of name(), so has two extra bytes at beginning */
930 static void
931 extract1(int ar, Hdr *hp, char *fname)
932 {
933 	int wrbytes, fd = -1, dir = 0;
934 	long mtime = strtol(hp->mtime, nil, 8);
935 	ulong mode = strtoul(hp->mode, nil, 8) & 0777;
936 	Off bytes = hdrsize(hp);		/* for printing */
937 	ulong blksread, blksleft = BYTES2TBLKS(arsize(hp));
938 	Hdr *hbp;
939 
940 	if (isdir(hp)) {
941 		mode |= DMDIR|0700;
942 		dir = 1;
943 	}
944 	switch (hp->linkflag) {
945 	case LF_LINK:
946 	case LF_SYMLINK1:
947 	case LF_SYMLINK2:
948 	case LF_FIFO:
949 		blksleft = 0;
950 		break;
951 	}
952 	if (relative) {
953 		if(fname[0] == '/')
954 			*--fname = '.';
955 		else if(fname[0] == '#'){
956 			*--fname = '/';
957 			*--fname = '.';
958 		}
959 	}
960 	if (verb == Xtract) {
961 		cleanname(fname);
962 		switch (hp->linkflag) {
963 		case LF_LINK:
964 		case LF_SYMLINK1:
965 		case LF_SYMLINK2:
966 			fprint(2, "%s: can't make (sym)link %s\n",
967 				argv0, fname);
968 			break;
969 		case LF_FIFO:
970 			fprint(2, "%s: can't make fifo %s\n", argv0, fname);
971 			break;
972 		default:
973 			if (!keepexisting || access(fname, AEXIST) < 0) {
974 				int rw = (dir? OREAD: OWRITE);
975 
976 				fd = create(fname, rw, mode);
977 				if (fd < 0) {
978 					mkpdirs(fname);
979 					fd = create(fname, rw, mode);
980 				}
981 				if (fd < 0 &&
982 				    (!dir || xaccess(fname, AEXIST) < 0))
983 				    	cantcreate(fname, mode);
984 			}
985 			if (fd >= 0 && verbose)
986 				fprint(2, "%s\n", fname);
987 			break;
988 		}
989 	} else if (verbose) {
990 		char *cp = ctime(mtime);
991 
992 		print("%M %8lld %-12.12s %-4.4s %s\n",
993 			mode, bytes, cp+4, cp+24, fname);
994 	} else
995 		print("%s\n", fname);
996 
997 	if (blksleft == 0)
998 		bytes = 0;
999 	for (; blksleft > 0; blksleft -= blksread) {
1000 		hbp = getblkrd(ar, (fd >= 0? Alldata: Justnxthdr));
1001 		if (hbp == nil)
1002 			sysfatal("unexpected EOF on archive extracting %s",
1003 				fname);
1004 		blksread = gothowmany(blksleft);
1005 		if (blksread <= 0)
1006 			fprint(2, "%s: got %ld blocks reading %s!\n",
1007 				argv0, blksread, fname);
1008 		wrbytes = Tblock*blksread;
1009 		if(wrbytes > bytes)
1010 			wrbytes = bytes;
1011 		if (fd >= 0 && write(fd, hbp->data, wrbytes) != wrbytes)
1012 			sysfatal("write error on %s: %r", fname);
1013 		putreadblks(ar, blksread);
1014 		bytes -= wrbytes;
1015 	}
1016 	if (bytes > 0)
1017 		fprint(2,
1018 		    "%s: %lld bytes uncopied at eof; %s not fully extracted\n",
1019 			argv0, bytes, fname);
1020 	if (fd >= 0) {
1021 		/*
1022 		 * directories should be wstated after we're done
1023 		 * creating files in them.
1024 		 */
1025 		if (settime) {
1026 			Dir nd;
1027 
1028 			nulldir(&nd);
1029 			nd.mtime = mtime;
1030 			dirfwstat(fd, &nd);
1031 			if (isustar(hp)) {
1032 				nulldir(&nd);
1033 				nd.gid = hp->gname;
1034 				dirfwstat(fd, &nd);
1035 			}
1036 		}
1037 		close(fd);
1038 	}
1039 }
1040 
1041 static void
1042 skip(int ar, Hdr *hp, char *fname)
1043 {
1044 	ulong blksleft, blksread;
1045 	Hdr *hbp;
1046 
1047 	for (blksleft = BYTES2TBLKS(arsize(hp)); blksleft > 0;
1048 	     blksleft -= blksread) {
1049 		hbp = getblkrd(ar, Justnxthdr);
1050 		if (hbp == nil)
1051 			sysfatal("unexpected EOF on archive extracting %s",
1052 				fname);
1053 		blksread = gothowmany(blksleft);
1054 		putreadblks(ar, blksread);
1055 	}
1056 }
1057 
1058 static char *
1059 extract(char **argv)
1060 {
1061 	int ar;
1062 	char *longname;
1063 	Hdr *hp;
1064 	Compress *comp = nil;
1065 	Pushstate ps;
1066 
1067 	if (usefile) {
1068 		ar = open(usefile, OREAD);
1069 		comp = compmethod(usefile);
1070 	} else
1071 		ar = Stdin;
1072 	if (comp)
1073 		ar = push(ar, comp->decomp, Input, &ps);
1074 	if (ar < 0)
1075 		sysfatal("can't open archive %s: %r", usefile);
1076 
1077 	while ((hp = readhdr(ar)) != nil) {
1078 		longname = name(hp);
1079 		if (match(longname, argv))
1080 			extract1(ar, hp, longname);
1081 		else
1082 			skip(ar, hp, longname);
1083 	}
1084 
1085 	if (comp)
1086 		return pushclose(&ps);
1087 	if (ar > Stderr)
1088 		close(ar);
1089 	return nil;
1090 }
1091 
1092 void
1093 main(int argc, char *argv[])
1094 {
1095 	int errflg = 0;
1096 	char *ret = nil;
1097 
1098 	fmtinstall('M', dirmodefmt);
1099 
1100 	TARGBEGIN {
1101 	case 'c':
1102 		docreate++;
1103 		verb = Replace;
1104 		break;
1105 	case 'f':
1106 		usefile = EARGF(usage());
1107 		break;
1108 	case 'g':
1109 		argid = strtoul(EARGF(usage()), 0, 0);
1110 		break;
1111 	case 'k':
1112 		keepexisting++;
1113 		break;
1114 	case 'm':	/* compatibility */
1115 		settime = 0;
1116 		break;
1117 	case 'p':
1118 		posix++;
1119 		break;
1120 	case 'P':
1121 		posix = 0;
1122 		break;
1123 	case 'r':
1124 		verb = Replace;
1125 		break;
1126 	case 'R':
1127 		relative = 0;
1128 		break;
1129 	case 't':
1130 		verb = Toc;
1131 		break;
1132 	case 'T':
1133 		settime++;
1134 		break;
1135 	case 'u':
1136 		aruid = strtoul(EARGF(usage()), 0, 0);
1137 		break;
1138 	case 'v':
1139 		verbose++;
1140 		break;
1141 	case 'x':
1142 		verb = Xtract;
1143 		break;
1144 	case 'z':
1145 		docompress++;
1146 		break;
1147 	case '-':
1148 		break;
1149 	default:
1150 		fprint(2, "tar: unknown letter %C\n", TARGC());
1151 		errflg++;
1152 		break;
1153 	} TARGEND
1154 
1155 	if (argc < 0 || errflg)
1156 		usage();
1157 
1158 	initblks();
1159 	switch (verb) {
1160 	case Toc:
1161 	case Xtract:
1162 		ret = extract(argv);
1163 		break;
1164 	case Replace:
1165 		if (getwd(origdir, sizeof origdir) == nil)
1166 			strcpy(origdir, "/tmp");
1167 		ret = replace(argv);
1168 		break;
1169 	default:
1170 		usage();
1171 		break;
1172 	}
1173 	exits(ret);
1174 }
1175