xref: /freebsd/sys/fs/tarfs/tarfs_vfsops.c (revision 7ef62cebc2f965b0f640263e179276928885e33d)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2013 Juniper Networks, Inc.
5  * Copyright (c) 2022-2023 Klara, Inc.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include "opt_tarfs.h"
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/buf.h>
34 #include <sys/conf.h>
35 #include <sys/fcntl.h>
36 #include <sys/libkern.h>
37 #include <sys/limits.h>
38 #include <sys/lock.h>
39 #include <sys/malloc.h>
40 #include <sys/mount.h>
41 #include <sys/mutex.h>
42 #include <sys/namei.h>
43 #include <sys/priv.h>
44 #include <sys/proc.h>
45 #include <sys/queue.h>
46 #include <sys/sbuf.h>
47 #include <sys/stat.h>
48 #include <sys/uio.h>
49 #include <sys/vnode.h>
50 
51 #include <vm/vm_param.h>
52 
53 #include <geom/geom.h>
54 #include <geom/geom_vfs.h>
55 
56 #include <fs/tarfs/tarfs.h>
57 #include <fs/tarfs/tarfs_dbg.h>
58 
59 CTASSERT(ZERO_REGION_SIZE > TARFS_BLOCKSIZE);
60 
61 struct ustar_header {
62 	char	name[100];		/* File name */
63 	char	mode[8];		/* Mode flags */
64 	char	uid[8];			/* User id */
65 	char	gid[8];			/* Group id */
66 	char	size[12];		/* Size */
67 	char	mtime[12];		/* Modified time */
68 	char	checksum[8];		/* Checksum */
69 	char	typeflag[1];		/* Type */
70 	char	linkname[100];		/* "old format" stops here */
71 	char	magic[6];		/* POSIX UStar "ustar\0" indicator */
72 	char	version[2];		/* POSIX UStar version "00" */
73 	char	uname[32];		/* User name */
74 	char	gname[32];		/* Group name */
75 	char	major[8];		/* Device major number */
76 	char	minor[8];		/* Device minor number */
77 	char	prefix[155];		/* Path prefix */
78 };
79 
80 #define	TAR_EOF			((off_t)-1)
81 
82 #define	TAR_TYPE_FILE		'0'
83 #define	TAR_TYPE_HARDLINK	'1'
84 #define	TAR_TYPE_SYMLINK	'2'
85 #define	TAR_TYPE_CHAR		'3'
86 #define	TAR_TYPE_BLOCK		'4'
87 #define	TAR_TYPE_DIRECTORY	'5'
88 #define	TAR_TYPE_FIFO		'6'
89 #define	TAR_TYPE_CONTIG		'7'
90 #define	TAR_TYPE_GLOBAL_EXTHDR	'g'
91 #define	TAR_TYPE_EXTHDR		'x'
92 #define	TAR_TYPE_GNU_SPARSE	'S'
93 
94 #define	USTAR_MAGIC		(uint8_t []){ 'u', 's', 't', 'a', 'r', 0 }
95 #define	USTAR_VERSION		(uint8_t []){ '0', '0' }
96 #define	GNUTAR_MAGIC		(uint8_t []){ 'u', 's', 't', 'a', 'r', ' ' }
97 #define	GNUTAR_VERSION		(uint8_t []){ ' ', '\x0' }
98 
99 #define	DEFDIRMODE	(S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
100 
101 MALLOC_DEFINE(M_TARFSMNT, "tarfs mount", "tarfs mount structures");
102 MALLOC_DEFINE(M_TARFSNODE, "tarfs node", "tarfs node structures");
103 
104 static vfs_mount_t	tarfs_mount;
105 static vfs_unmount_t	tarfs_unmount;
106 static vfs_root_t	tarfs_root;
107 static vfs_statfs_t	tarfs_statfs;
108 static vfs_fhtovp_t	tarfs_fhtovp;
109 
110 static const char *tarfs_opts[] = {
111 	"as", "from", "gid", "mode", "uid", "verify",
112 	NULL
113 };
114 
115 /*
116  * Reads a len-width signed octal number from strp.  Returns the value.
117  * XXX Does not report errors.
118  */
119 static int64_t
120 tarfs_str2octal(const char *strp, size_t len)
121 {
122 	int64_t val;
123 	size_t idx;
124 	int sign;
125 
126 	/*
127 	 * Skip leading spaces or tabs.
128 	 * XXX why?  POSIX requires numeric fields to be 0-padded.
129 	 */
130 	for (idx = 0; idx < len; idx++)
131 		if (strp[idx] != ' ' && strp[idx] != '\t')
132 			break;
133 
134 	if (idx == len)
135 		return (0);
136 
137 	if (strp[idx] == '-') {
138 		sign = -1;
139 		idx++;
140 	} else
141 		sign = 1;
142 
143 	val = 0;
144 	for (; idx < len; idx++) {
145 		if (strp[idx] < '0' || strp[idx] > '7')
146 			break;
147 		val <<= 3;
148 		val += (strp[idx] - '0');
149 
150 		/* Truncate on overflow */
151 		if (val > INT64_MAX / 8) {
152 			val = INT64_MAX;
153 			break;
154 		}
155 	}
156 
157 	return (sign > 0) ? val : -val;
158 }
159 
160 /*
161  * Reads a len-byte extended numeric value from strp.  The first byte has
162  * bit 7 set to indicate the format; the remaining 7 bits + the (len - 1)
163  * bytes that follow form a big-endian signed two's complement binary
164  * number.  Returns the value.  XXX Does not report errors.
165  */
166 static int64_t
167 tarfs_str2base256(const char *strp, size_t len)
168 {
169 	int64_t val;
170 	size_t idx;
171 
172 	KASSERT(strp[0] & 0x80, ("not an extended numeric value"));
173 
174 	/* Sign-extend the first byte */
175 	if ((strp[0] & 0x40) != 0)
176 		val = (int64_t)-1;
177 	else
178 		val = 0;
179 	val <<= 6;
180 	val |= (strp[0] & 0x3f);
181 
182 	/* Read subsequent bytes */
183 	for (idx = 1; idx < len; idx++) {
184 		val <<= 8;
185 		val |= (0xff & (int64_t)strp[idx]);
186 
187 		/* Truncate on overflow and underflow */
188 		if (val > INT64_MAX / 256) {
189 			val = INT64_MAX;
190 			break;
191 		} else if (val < INT64_MAX / 256) {
192 			val = INT64_MIN;
193 			break;
194 		}
195 	}
196 
197 	return (val);
198 }
199 
200 /*
201  * Read a len-byte numeric field from strp.  If bit 7 of the first byte it
202  * set, assume an extended numeric value (signed two's complement);
203  * otherwise, assume a signed octal value.
204  *
205  * XXX practically no error checking or handling
206  */
207 static int64_t
208 tarfs_str2int64(const char *strp, size_t len)
209 {
210 
211 	if (len < 1)
212 		return (0);
213 
214 	if ((strp[0] & 0x80) != 0)
215 		return (tarfs_str2base256(strp, len));
216 	return (tarfs_str2octal(strp, len));
217 }
218 
219 /*
220  * Verifies the checksum of a header.  Returns true if the checksum is
221  * valid, false otherwise.
222  */
223 static boolean_t
224 tarfs_checksum(struct ustar_header *hdrp)
225 {
226 	const unsigned char *ptr;
227 	int64_t checksum, hdrsum;
228 	size_t idx;
229 
230 	hdrsum = tarfs_str2int64(hdrp->checksum, sizeof(hdrp->checksum));
231 	TARFS_DPF(CHECKSUM, "%s: header checksum %lx\n", __func__, hdrsum);
232 
233 	checksum = 0;
234 	for (ptr = (const unsigned char *)hdrp;
235 	     ptr < (const unsigned char *)hdrp->checksum; ptr++)
236 		checksum += *ptr;
237 	for (idx = 0; idx < sizeof(hdrp->checksum); idx++)
238 		checksum += 0x20;
239 	for (ptr = (const unsigned char *)hdrp->typeflag;
240 	     ptr < (const unsigned char *)(hdrp + 1); ptr++)
241 		checksum += *ptr;
242 	TARFS_DPF(CHECKSUM, "%s: calc unsigned checksum %lx\n", __func__,
243 	    checksum);
244 	if (hdrsum == checksum)
245 		return (true);
246 
247 	/*
248 	 * Repeat test with signed bytes, some older formats use a broken
249 	 * form of the calculation
250 	 */
251 	checksum = 0;
252 	for (ptr = (const unsigned char *)hdrp;
253 	     ptr < (const unsigned char *)&hdrp->checksum; ptr++)
254 		checksum += *((const signed char *)ptr);
255 	for (idx = 0; idx < sizeof(hdrp->checksum); idx++)
256 		checksum += 0x20;
257 	for (ptr = (const unsigned char *)&hdrp->typeflag;
258 	     ptr < (const unsigned char *)(hdrp + 1); ptr++)
259 		checksum += *((const signed char *)ptr);
260 	TARFS_DPF(CHECKSUM, "%s: calc signed checksum %lx\n", __func__,
261 	    checksum);
262 	if (hdrsum == checksum)
263 		return (true);
264 
265 	return (false);
266 }
267 
268 
269 /*
270  * Looks up a path in the tarfs node tree.
271  *
272  * - If the path exists, stores a pointer to the corresponding tarfs_node
273  *   in retnode and a pointer to its parent in retparent.
274  *
275  * - If the path does not exist, but create_dirs is true, creates ancestor
276  *   directories and returns NULL in retnode and the parent in retparent.
277  *
278  * - If the path does not exist and create_dirs is false, stops at the
279  *   first missing path name component.
280  *
281  * - In all cases, on return, endp and sepp point to the beginning and
282  *   end, respectively, of the last-processed path name component.
283  *
284  * - Returns 0 if the node was found, ENOENT if it was not, and some other
285  *   positive errno value on failure.
286  */
287 static int
288 tarfs_lookup_path(struct tarfs_mount *tmp, char *name, size_t namelen,
289     char **endp, char **sepp, struct tarfs_node **retparent,
290     struct tarfs_node **retnode, boolean_t create_dirs)
291 {
292 	struct componentname cn = { };
293 	struct tarfs_node *parent, *tnp;
294 	char *sep;
295 	size_t len;
296 	int error;
297 	boolean_t do_lookup;
298 
299 	MPASS(name != NULL && namelen != 0);
300 
301 	do_lookup = true;
302 	error = 0;
303 	parent = tnp = tmp->root;
304 	if (tnp == NULL)
305 		panic("%s: root node not yet created", __func__);
306 
307 	TARFS_DPF(LOOKUP, "%s: full path: %.*s\n", __func__,
308 	    (int)namelen, name);
309 
310 	sep = NULL;
311 	for (;;) {
312 		/* skip leading slash(es) */
313 		while (name[0] == '/' && namelen > 0)
314 			name++, namelen--;
315 
316 		/* did we reach the end? */
317 		if (namelen == 0 || name[0] == '\0') {
318 			name = do_lookup ? NULL : cn.cn_nameptr;
319 			namelen = do_lookup ? 0 : cn.cn_namelen;
320 			break;
321 		}
322 
323 		/* we're not at the end, so we must be in a directory */
324 		if (tnp != NULL && tnp->type != VDIR) {
325 			TARFS_DPF(LOOKUP, "%s: %.*s is not a directory\n", __func__,
326 			    (int)tnp->namelen, tnp->name);
327 			error = ENOTDIR;
328 			break;
329 		}
330 
331 		/* locate the next separator */
332 		for (sep = name, len = 0;
333 		     *sep != '\0' && *sep != '/' && len < namelen;
334 		     sep++, len++)
335 			/* nothing */ ;
336 
337 		/* check for . and .. */
338 		if (name[0] == '.' && len == 1) {
339 			name += len;
340 			namelen -= len;
341 			continue;
342 		}
343 		if (name[0] == '.' && name[1] == '.' && len == 2) {
344 			if (tnp == tmp->root) {
345 				error = EINVAL;
346 				break;
347 			}
348 			tnp = parent;
349 			parent = tnp->parent;
350 			cn.cn_nameptr = tnp->name;
351 			cn.cn_namelen = tnp->namelen;
352 			do_lookup = true;
353 			TARFS_DPF(LOOKUP, "%s: back to %.*s/\n", __func__,
354 			    (int)tnp->namelen, tnp->name);
355 			name += len;
356 			namelen -= len;
357 			continue;
358 		}
359 
360 		/* create parent if necessary */
361 		if (!do_lookup) {
362 			TARFS_DPF(ALLOC, "%s: creating %.*s\n", __func__,
363 			    (int)cn.cn_namelen, cn.cn_nameptr);
364 			error = tarfs_alloc_node(tmp, cn.cn_nameptr,
365 			    cn.cn_namelen, VDIR, -1, 0, tmp->mtime, 0, 0,
366 			    DEFDIRMODE, 0, NULL, NODEV, parent, &tnp);
367 			if (error != 0)
368 				break;
369 		}
370 
371 		parent = tnp;
372 		tnp = NULL;
373 		cn.cn_nameptr = name;
374 		cn.cn_namelen = len;
375 		TARFS_DPF(LOOKUP, "%s: looking up %.*s in %.*s/\n", __func__,
376 		    (int)cn.cn_namelen, cn.cn_nameptr,
377 		    (int)parent->namelen, parent->name);
378 		if (do_lookup) {
379 			tnp = tarfs_lookup_node(parent, NULL, &cn);
380 			if (tnp == NULL) {
381 				do_lookup = false;
382 				if (!create_dirs)
383 					break;
384 			}
385 		}
386 		name += cn.cn_namelen;
387 		namelen -= cn.cn_namelen;
388 	}
389 
390 	TARFS_DPF(LOOKUP, "%s: parent %p node %p\n", __func__, parent, tnp);
391 
392 	if (retparent)
393 		*retparent = parent;
394 	if (retnode)
395 		*retnode = tnp;
396 	if (endp) {
397 		if (namelen > 0)
398 			*endp = name;
399 		else
400 			*endp = NULL;
401 	}
402 	if (sepp)
403 		*sepp = sep;
404 	return (error);
405 }
406 
407 /*
408  * Frees a tarfs_mount structure and everything it references.
409  */
410 static void
411 tarfs_free_mount(struct tarfs_mount *tmp)
412 {
413 	struct mount *mp;
414 	struct tarfs_node *tnp, *tnp_next;
415 
416 	MPASS(tmp != NULL);
417 
418 	TARFS_DPF(ALLOC, "%s: Freeing mount structure %p\n", __func__, tmp);
419 
420 	TARFS_DPF(ALLOC, "%s: freeing tarfs_node structures\n", __func__);
421 	TAILQ_FOREACH_SAFE(tnp, &tmp->allnodes, entries, tnp_next) {
422 		tarfs_free_node(tnp);
423 	}
424 
425 	(void)tarfs_io_fini(tmp);
426 
427 	TARFS_DPF(ALLOC, "%s: deleting unr header\n", __func__);
428 	delete_unrhdr(tmp->ino_unr);
429 	mp = tmp->vfs;
430 	mp->mnt_data = NULL;
431 
432 	TARFS_DPF(ALLOC, "%s: freeing structure\n", __func__);
433 	free(tmp, M_TARFSMNT);
434 }
435 
436 /*
437  * Processes the tar file header at block offset blknump and allocates and
438  * populates a tarfs_node structure for the file it describes.  Updated
439  * blknump to point to the next unread tar file block, or TAR_EOF if EOF
440  * is reached.  Returns 0 on success or EOF and a positive errno value on
441  * failure.
442  */
443 static int
444 tarfs_alloc_one(struct tarfs_mount *tmp, off_t *blknump)
445 {
446 	char block[TARFS_BLOCKSIZE];
447 	struct ustar_header *hdrp = (struct ustar_header *)block;
448 	struct sbuf *namebuf = NULL;
449 	char *exthdr = NULL, *name = NULL, *link = NULL;
450 	off_t blknum = *blknump;
451 	int64_t num;
452 	int endmarker = 0;
453 	char *namep, *sep;
454 	struct tarfs_node *parent, *tnp;
455 	size_t namelen = 0, linklen = 0, realsize = 0, sz;
456 	ssize_t res;
457 	dev_t rdev;
458 	gid_t gid;
459 	mode_t mode;
460 	time_t mtime;
461 	uid_t uid;
462 	long major = -1, minor = -1;
463 	unsigned int flags = 0;
464 	int error;
465 	boolean_t sparse = false;
466 
467 again:
468 	/* read next header */
469 	res = tarfs_io_read_buf(tmp, false, block,
470 	    TARFS_BLOCKSIZE * blknum, TARFS_BLOCKSIZE);
471 	if (res < 0) {
472 		error = -res;
473 		goto bad;
474 	} else if (res < TARFS_BLOCKSIZE) {
475 		goto eof;
476 	}
477 	blknum++;
478 
479 	/* check for end marker */
480 	if (memcmp(block, zero_region, TARFS_BLOCKSIZE) == 0) {
481 		if (endmarker++) {
482 			if (exthdr != NULL) {
483 				TARFS_DPF(IO, "%s: orphaned extended header at %zu\n",
484 				    __func__, TARFS_BLOCKSIZE * (blknum - 1));
485 				free(exthdr, M_TEMP);
486 			}
487 			TARFS_DPF(IO, "%s: end of archive at %zu\n", __func__,
488 			    TARFS_BLOCKSIZE * blknum);
489 			tmp->nblocks = blknum;
490 			*blknump = TAR_EOF;
491 			return (0);
492 		}
493 		goto again;
494 	}
495 
496 	/* verify magic */
497 	if (memcmp(hdrp->magic, USTAR_MAGIC, sizeof(USTAR_MAGIC)) == 0 &&
498 	    memcmp(hdrp->version, USTAR_VERSION, sizeof(USTAR_VERSION)) == 0) {
499 		/* POSIX */
500 	} else if (memcmp(hdrp->magic, GNUTAR_MAGIC, sizeof(GNUTAR_MAGIC)) == 0 &&
501 	    memcmp(hdrp->magic, GNUTAR_MAGIC, sizeof(GNUTAR_MAGIC)) == 0) {
502 		TARFS_DPF(ALLOC, "%s: GNU tar format at %zu\n", __func__,
503 		    TARFS_BLOCKSIZE * (blknum - 1));
504 		error = EFTYPE;
505 		goto bad;
506 	} else {
507 		TARFS_DPF(ALLOC, "%s: unsupported TAR format at %zu\n",
508 		    __func__, TARFS_BLOCKSIZE * (blknum - 1));
509 		error = EINVAL;
510 		goto bad;
511 	}
512 
513 	/* verify checksum */
514 	if (!tarfs_checksum(hdrp)) {
515 		TARFS_DPF(ALLOC, "%s: header checksum failed at %zu\n",
516 		    __func__, TARFS_BLOCKSIZE * (blknum - 1));
517 		error = EINVAL;
518 		goto bad;
519 	}
520 
521 	/* get standard attributes */
522 	num = tarfs_str2int64(hdrp->mode, sizeof(hdrp->mode));
523 	if (num < 0 || num > (S_IFMT|ALLPERMS)) {
524 		TARFS_DPF(ALLOC, "%s: invalid file mode at %zu\n",
525 		    __func__, TARFS_BLOCKSIZE * (blknum - 1));
526 		mode = S_IRUSR;
527 	} else {
528 		mode = num & ALLPERMS;
529 	}
530 	num = tarfs_str2int64(hdrp->uid, sizeof(hdrp->uid));
531 	if (num < 0 || num > UID_MAX) {
532 		TARFS_DPF(ALLOC, "%s: UID out of range at %zu\n",
533 		    __func__, TARFS_BLOCKSIZE * (blknum - 1));
534 		uid = tmp->root->uid;
535 		mode &= ~S_ISUID;
536 	} else {
537 		uid = num;
538 	}
539 	num = tarfs_str2int64(hdrp->gid, sizeof(hdrp->gid));
540 	if (num < 0 || num > GID_MAX) {
541 		TARFS_DPF(ALLOC, "%s: GID out of range at %zu\n",
542 		    __func__, TARFS_BLOCKSIZE * (blknum - 1));
543 		gid = tmp->root->gid;
544 		mode &= ~S_ISGID;
545 	} else {
546 		gid = num;
547 	}
548 	num = tarfs_str2int64(hdrp->size, sizeof(hdrp->size));
549 	if (num < 0) {
550 		TARFS_DPF(ALLOC, "%s: negative size at %zu\n",
551 		    __func__, TARFS_BLOCKSIZE * (blknum - 1));
552 		error = EINVAL;
553 		goto bad;
554 	} else {
555 		sz = num;
556 	}
557 	mtime = tarfs_str2int64(hdrp->mtime, sizeof(hdrp->mtime));
558 	rdev = NODEV;
559 	TARFS_DPF(ALLOC, "%s: [%c] %zu @%jd %o %d:%d\n", __func__,
560 	    hdrp->typeflag[0], sz, (intmax_t)mtime, mode, uid, gid);
561 
562 	/* extended header? */
563 	if (hdrp->typeflag[0] == TAR_TYPE_GLOBAL_EXTHDR) {
564 		printf("%s: unsupported global extended header at %zu\n",
565 		    __func__, (size_t)(TARFS_BLOCKSIZE * (blknum - 1)));
566 		error = EFTYPE;
567 		goto bad;
568 	}
569 	if (hdrp->typeflag[0] == TAR_TYPE_EXTHDR) {
570 		if (exthdr != NULL) {
571 			TARFS_DPF(IO, "%s: multiple extended headers at %zu\n",
572 			    __func__, TARFS_BLOCKSIZE * (blknum - 1));
573 			error = EFTYPE;
574 			goto bad;
575 		}
576 		/* read the contents of the exthdr */
577 		TARFS_DPF(ALLOC, "%s: %zu-byte extended header at %zd\n",
578 		    __func__, sz, TARFS_BLOCKSIZE * (blknum - 1));
579 		exthdr = malloc(sz, M_TEMP, M_WAITOK);
580 		res = tarfs_io_read_buf(tmp, false, exthdr,
581 		    TARFS_BLOCKSIZE * blknum, sz);
582 		if (res < 0) {
583 			error = -res;
584 			goto bad;
585 		}
586 		if (res < sz) {
587 			goto eof;
588 		}
589 		blknum += TARFS_SZ2BLKS(res);
590 		/* XXX TODO: refactor this parser */
591 		char *line = exthdr;
592 		while (line < exthdr + sz) {
593 			char *eol, *key, *value, *sep;
594 			size_t len = strtoul(line, &sep, 10);
595 			if (len == 0 || sep == line || *sep != ' ') {
596 				TARFS_DPF(ALLOC, "%s: exthdr syntax error\n",
597 				    __func__);
598 				error = EINVAL;
599 				goto bad;
600 			}
601 			if (line + len > exthdr + sz) {
602 				TARFS_DPF(ALLOC, "%s: exthdr overflow\n",
603 				    __func__);
604 				error = EINVAL;
605 				goto bad;
606 			}
607 			eol = line + len - 1;
608 			*eol = '\0';
609 			line += len;
610 			key = sep + 1;
611 			sep = strchr(key, '=');
612 			if (sep == NULL) {
613 				TARFS_DPF(ALLOC, "%s: exthdr syntax error\n",
614 				    __func__);
615 				error = EINVAL;
616 				goto bad;
617 			}
618 			*sep = '\0';
619 			value = sep + 1;
620 			TARFS_DPF(ALLOC, "%s: exthdr %s=%s\n", __func__,
621 			    key, value);
622 			if (strcmp(key, "linkpath") == 0) {
623 				link = value;
624 				linklen = eol - value;
625 			} else if (strcmp(key, "GNU.sparse.major") == 0) {
626 				sparse = true;
627 				major = strtol(value, &sep, 10);
628 				if (sep != eol) {
629 					printf("exthdr syntax error\n");
630 					error = EINVAL;
631 					goto bad;
632 				}
633 			} else if (strcmp(key, "GNU.sparse.minor") == 0) {
634 				sparse = true;
635 				minor = strtol(value, &sep, 10);
636 				if (sep != eol) {
637 					printf("exthdr syntax error\n");
638 					error = EINVAL;
639 					goto bad;
640 				}
641 			} else if (strcmp(key, "GNU.sparse.name") == 0) {
642 				sparse = true;
643 				name = value;
644 				namelen = eol - value;
645 				if (namelen == 0) {
646 					printf("exthdr syntax error\n");
647 					error = EINVAL;
648 					goto bad;
649 				}
650 			} else if (strcmp(key, "GNU.sparse.realsize") == 0) {
651 				sparse = true;
652 				realsize = strtoul(value, &sep, 10);
653 				if (sep != eol) {
654 					printf("exthdr syntax error\n");
655 					error = EINVAL;
656 					goto bad;
657 				}
658 			} else if (strcmp(key, "SCHILY.fflags") == 0) {
659 				flags |= tarfs_strtofflags(value, &sep);
660 				if (sep != eol) {
661 					printf("exthdr syntax error\n");
662 					error = EINVAL;
663 					goto bad;
664 				}
665 			}
666 		}
667 		goto again;
668 	}
669 
670 	/* sparse file consistency checks */
671 	if (sparse) {
672 		TARFS_DPF(ALLOC, "%s: %s: sparse %ld.%ld (%zu bytes)\n", __func__,
673 		    name, major, minor, realsize);
674 		if (major != 1 || minor != 0 || name == NULL || realsize == 0 ||
675 		    hdrp->typeflag[0] != TAR_TYPE_FILE) {
676 			TARFS_DPF(ALLOC, "%s: invalid sparse format\n", __func__);
677 			error = EINVAL;
678 			goto bad;
679 		}
680 	}
681 
682 	/* file name */
683 	if (name == NULL) {
684 		if (hdrp->prefix[0] != '\0') {
685 			namebuf = sbuf_new_auto();
686 			sbuf_printf(namebuf, "%.*s/%.*s",
687 			    (int)sizeof(hdrp->prefix), hdrp->prefix,
688 			    (int)sizeof(hdrp->name), hdrp->name);
689 			sbuf_finish(namebuf);
690 			name = sbuf_data(namebuf);
691 			namelen = sbuf_len(namebuf);
692 		} else {
693 			name = hdrp->name;
694 			namelen = strnlen(hdrp->name, sizeof(hdrp->name));
695 		}
696 	}
697 
698 	error = tarfs_lookup_path(tmp, name, namelen, &namep,
699 	    &sep, &parent, &tnp, true);
700 	if (error != 0) {
701 		TARFS_DPF(ALLOC, "%s: failed to look up %.*s\n", __func__,
702 		    (int)namelen, name);
703 		error = EINVAL;
704 		goto bad;
705 	}
706 	if (tnp != NULL) {
707 		if (hdrp->typeflag[0] == TAR_TYPE_DIRECTORY) {
708 			/* XXX set attributes? */
709 			goto skip;
710 		}
711 		TARFS_DPF(ALLOC, "%s: duplicate file %.*s\n", __func__,
712 		    (int)namelen, name);
713 		error = EINVAL;
714 		goto bad;
715 	}
716 	switch (hdrp->typeflag[0]) {
717 	case TAR_TYPE_DIRECTORY:
718 		error = tarfs_alloc_node(tmp, namep, sep - namep, VDIR,
719 		    0, 0, mtime, uid, gid, mode, flags, NULL, 0,
720 		    parent, &tnp);
721 		break;
722 	case TAR_TYPE_FILE:
723 		error = tarfs_alloc_node(tmp, namep, sep - namep, VREG,
724 		    blknum * TARFS_BLOCKSIZE, sz, mtime, uid, gid, mode,
725 		    flags, NULL, 0, parent, &tnp);
726 		if (error == 0 && sparse) {
727 			error = tarfs_load_blockmap(tnp, realsize);
728 		}
729 		break;
730 	case TAR_TYPE_HARDLINK:
731 		if (link == NULL) {
732 			link = hdrp->linkname;
733 			linklen = strnlen(link, sizeof(hdrp->linkname));
734 		}
735 		error = tarfs_alloc_node(tmp, namep, sep - namep, VREG,
736 		    0, 0, 0, 0, 0, 0, 0, NULL, 0, parent, &tnp);
737 		if (error != 0) {
738 			goto bad;
739 		}
740 		error = tarfs_lookup_path(tmp, link, linklen, NULL,
741 		    NULL, NULL, &tnp->other, false);
742 		if (tnp->other == NULL ||
743 		    tnp->other->type != VREG ||
744 		    tnp->other->other != NULL) {
745 			TARFS_DPF(ALLOC, "%s: %.*s: dead hard link to %.*s\n",
746 			    __func__, (int)namelen, name, (int)linklen, link);
747 			error = EINVAL;
748 			goto bad;
749 		}
750 		tnp->other->nlink++;
751 		break;
752 	case TAR_TYPE_SYMLINK:
753 		if (link == NULL) {
754 			link = hdrp->linkname;
755 			linklen = strnlen(link, sizeof(hdrp->linkname));
756 		}
757 		error = tarfs_alloc_node(tmp, namep, sep - namep, VLNK,
758 		    0, linklen, mtime, uid, gid, mode, flags, link, 0,
759 		    parent, &tnp);
760 		break;
761 	case TAR_TYPE_BLOCK:
762 		major = tarfs_str2int64(hdrp->major, sizeof(hdrp->major));
763 		minor = tarfs_str2int64(hdrp->minor, sizeof(hdrp->minor));
764 		rdev = makedev(major, minor);
765 		error = tarfs_alloc_node(tmp, namep, sep - namep, VBLK,
766 		    0, 0, mtime, uid, gid, mode, flags, NULL, rdev,
767 		    parent, &tnp);
768 		break;
769 	case TAR_TYPE_CHAR:
770 		major = tarfs_str2int64(hdrp->major, sizeof(hdrp->major));
771 		minor = tarfs_str2int64(hdrp->minor, sizeof(hdrp->minor));
772 		rdev = makedev(major, minor);
773 		error = tarfs_alloc_node(tmp, namep, sep - namep, VCHR,
774 		    0, 0, mtime, uid, gid, mode, flags, NULL, rdev,
775 		    parent, &tnp);
776 		break;
777 	default:
778 		TARFS_DPF(ALLOC, "%s: unsupported type %c for %.*s\n",
779 		    __func__, hdrp->typeflag[0], (int)namelen, name);
780 		error = EINVAL;
781 		break;
782 	}
783 	if (error != 0)
784 		goto bad;
785 
786 skip:
787 	blknum += TARFS_SZ2BLKS(sz);
788 	tmp->nblocks = blknum;
789 	*blknump = blknum;
790 	if (exthdr != NULL) {
791 		free(exthdr, M_TEMP);
792 	}
793 	if (namebuf != NULL) {
794 		sbuf_delete(namebuf);
795 	}
796 	return (0);
797 eof:
798 	TARFS_DPF(IO, "%s: premature end of file\n", __func__);
799 	error = EIO;
800 	goto bad;
801 bad:
802 	if (exthdr != NULL) {
803 		free(exthdr, M_TEMP);
804 	}
805 	if (namebuf != NULL) {
806 		sbuf_delete(namebuf);
807 	}
808 	return (error);
809 }
810 
811 /*
812  * Allocates and populates the metadata structures for the tar file
813  * referenced by vp.  On success, a pointer to the tarfs_mount structure
814  * is stored in tmpp.  Returns 0 on success or a positive errno value on
815  * failure.
816  */
817 static int
818 tarfs_alloc_mount(struct mount *mp, struct vnode *vp,
819     uid_t root_uid, gid_t root_gid, mode_t root_mode,
820     struct tarfs_mount **tmpp)
821 {
822 	struct vattr va;
823 	struct thread *td = curthread;
824 	struct tarfs_mount *tmp;
825 	struct tarfs_node *root;
826 	off_t blknum;
827 	time_t mtime;
828 	int error;
829 
830 	KASSERT(tmpp != NULL, ("tarfs mount return is NULL"));
831 	ASSERT_VOP_LOCKED(vp, __func__);
832 
833 	tmp = NULL;
834 
835 	TARFS_DPF(ALLOC, "%s: Allocating tarfs mount structure for vp %p\n",
836 	    __func__, vp);
837 
838 	/* Get source metadata */
839 	error = VOP_GETATTR(vp, &va, td->td_ucred);
840 	if (error != 0) {
841 		return (error);
842 	}
843 	VOP_UNLOCK(vp);
844 	mtime = va.va_mtime.tv_sec;
845 
846 	/* Allocate and initialize tarfs mount structure */
847 	tmp = malloc(sizeof(*tmp), M_TARFSMNT, M_WAITOK | M_ZERO);
848 	TARFS_DPF(ALLOC, "%s: Allocated mount structure\n", __func__);
849 	mp->mnt_data = tmp;
850 
851 	mtx_init(&tmp->allnode_lock, "tarfs allnode lock", NULL,
852 	    MTX_DEF);
853 	TAILQ_INIT(&tmp->allnodes);
854 	tmp->ino_unr = new_unrhdr(TARFS_MININO, INT_MAX, &tmp->allnode_lock);
855 	tmp->vp = vp;
856 	tmp->vfs = mp;
857 	tmp->mtime = mtime;
858 
859 	/*
860 	 * XXX The decompression layer passes everything through the
861 	 * buffer cache, and the buffer cache wants to know our blocksize,
862 	 * but mnt_stat normally isn't populated until after we return, so
863 	 * we have to cheat a bit.
864 	 */
865 	tmp->iosize = 1U << tarfs_ioshift;
866 	mp->mnt_stat.f_iosize = tmp->iosize;
867 
868 	/* Initialize decompression layer */
869 	error = tarfs_io_init(tmp);
870 	if (error != 0)
871 		goto bad;
872 
873 	error = tarfs_alloc_node(tmp, NULL, 0, VDIR, 0, 0, mtime, root_uid,
874 	    root_gid, root_mode & ALLPERMS, 0, NULL, NODEV, NULL, &root);
875 	if (error != 0 || root == NULL)
876 		goto bad;
877 	tmp->root = root;
878 
879 	blknum = 0;
880 	do {
881 		if ((error = tarfs_alloc_one(tmp, &blknum)) != 0) {
882 			goto bad;
883 		}
884 	} while (blknum != TAR_EOF);
885 
886 	*tmpp = tmp;
887 
888 	TARFS_DPF(ALLOC, "%s: pfsmnt_root %p\n", __func__, tmp->root);
889 	return (0);
890 
891 bad:
892 	tarfs_free_mount(tmp);
893 	return (error);
894 }
895 
896 /*
897  * VFS Operations.
898  */
899 
900 static int
901 tarfs_mount(struct mount *mp)
902 {
903 	struct nameidata nd;
904 	struct vattr va;
905 	struct tarfs_mount *tmp = NULL;
906 	struct thread *td = curthread;
907 	struct vnode *vp;
908 	char *as, *from;
909 	uid_t root_uid;
910 	gid_t root_gid;
911 	mode_t root_mode;
912 	int error, flags, aslen, len;
913 
914 	if (mp->mnt_flag & MNT_UPDATE)
915 		return (EOPNOTSUPP);
916 
917 	if (vfs_filteropt(mp->mnt_optnew, tarfs_opts))
918 		return (EINVAL);
919 
920 	vn_lock(mp->mnt_vnodecovered, LK_SHARED | LK_RETRY);
921 	error = VOP_GETATTR(mp->mnt_vnodecovered, &va, mp->mnt_cred);
922 	VOP_UNLOCK(mp->mnt_vnodecovered);
923 	if (error)
924 		return (error);
925 
926 	if (mp->mnt_cred->cr_ruid != 0 ||
927 	    vfs_scanopt(mp->mnt_optnew, "gid", "%d", &root_gid) != 1)
928 		root_gid = va.va_gid;
929 	if (mp->mnt_cred->cr_ruid != 0 ||
930 	    vfs_scanopt(mp->mnt_optnew, "uid", "%d", &root_uid) != 1)
931 		root_uid = va.va_uid;
932 	if (mp->mnt_cred->cr_ruid != 0 ||
933 	    vfs_scanopt(mp->mnt_optnew, "mode", "%ho", &root_mode) != 1)
934 		root_mode = va.va_mode;
935 
936 	error = vfs_getopt(mp->mnt_optnew, "from", (void **)&from, &len);
937 	if (error != 0 || from[len - 1] != '\0')
938 		return (EINVAL);
939 	error = vfs_getopt(mp->mnt_optnew, "as", (void **)&as, &aslen);
940 	if (error != 0 || as[aslen - 1] != '\0')
941 		as = from;
942 
943 	/* Find the source tarball */
944 	TARFS_DPF(FS, "%s(%s%s%s, uid=%u, gid=%u, mode=%o)\n", __func__,
945 	    from, (as != from) ? " as " : "", (as != from) ? as : "",
946 	    root_uid, root_gid, root_mode);
947 	flags = FREAD;
948 	if (vfs_flagopt(mp->mnt_optnew, "verify", NULL, 0)) {
949 	    flags |= O_VERIFY;
950 	}
951 	NDINIT(&nd, LOOKUP, ISOPEN | FOLLOW | LOCKLEAF, UIO_SYSSPACE, from);
952 	error = namei(&nd);
953 	if (error != 0)
954 		return (error);
955 	NDFREE_PNBUF(&nd);
956 	vp = nd.ni_vp;
957 	TARFS_DPF(FS, "%s: N: hold %u use %u lock 0x%x\n", __func__,
958 	    vp->v_holdcnt, vp->v_usecount, VOP_ISLOCKED(vp));
959 	/* vp is now held and locked */
960 
961 	/* Open the source tarball */
962 	error = vn_open_vnode(vp, flags, td->td_ucred, td, NULL);
963 	if (error != 0) {
964 		TARFS_DPF(FS, "%s: failed to open %s: %d\n", __func__,
965 		    from, error);
966 		vput(vp);
967 		goto bad;
968 	}
969 	TARFS_DPF(FS, "%s: O: hold %u use %u lock 0x%x\n", __func__,
970 	    vp->v_holdcnt, vp->v_usecount, VOP_ISLOCKED(vp));
971 	if (vp->v_type != VREG) {
972 		TARFS_DPF(FS, "%s: not a regular file\n", __func__);
973 		error = EOPNOTSUPP;
974 		goto bad_open_locked;
975 	}
976 	error = priv_check(td, PRIV_VFS_MOUNT_PERM);
977 	if (error != 0) {
978 		TARFS_DPF(FS, "%s: not permitted to mount\n", __func__);
979 		goto bad_open_locked;
980 	}
981 	if (flags & O_VERIFY) {
982 		mp->mnt_flag |= MNT_VERIFIED;
983 	}
984 
985 	/* Allocate the tarfs mount */
986 	error = tarfs_alloc_mount(mp, vp, root_uid, root_gid, root_mode, &tmp);
987 	/* vp is now held but unlocked */
988 	if (error != 0) {
989 		TARFS_DPF(FS, "%s: failed to mount %s: %d\n", __func__,
990 		    from, error);
991 		goto bad_open_unlocked;
992 	}
993 	TARFS_DPF(FS, "%s: M: hold %u use %u lock 0x%x\n", __func__,
994 	    vp->v_holdcnt, vp->v_usecount, VOP_ISLOCKED(vp));
995 
996 	/* Unconditionally mount as read-only */
997 	MNT_ILOCK(mp);
998 	mp->mnt_flag |= (MNT_LOCAL | MNT_RDONLY);
999 	MNT_IUNLOCK(mp);
1000 
1001 	vfs_getnewfsid(mp);
1002 	vfs_mountedfrom(mp, as);
1003 	TARFS_DPF(FS, "%s: success\n", __func__);
1004 
1005 	return (0);
1006 
1007 bad_open_locked:
1008 	/* vp must be held and locked */
1009 	TARFS_DPF(FS, "%s: L: hold %u use %u lock 0x%x\n", __func__,
1010 	    vp->v_holdcnt, vp->v_usecount, VOP_ISLOCKED(vp));
1011 	VOP_UNLOCK(vp);
1012 bad_open_unlocked:
1013 	/* vp must be held and unlocked */
1014 	TARFS_DPF(FS, "%s: E: hold %u use %u lock 0x%x\n", __func__,
1015 	    vp->v_holdcnt, vp->v_usecount, VOP_ISLOCKED(vp));
1016 	(void)vn_close(vp, flags, td->td_ucred, td);
1017 bad:
1018 	/* vp must be released and unlocked */
1019 	TARFS_DPF(FS, "%s: X: hold %u use %u lock 0x%x\n", __func__,
1020 	    vp->v_holdcnt, vp->v_usecount, VOP_ISLOCKED(vp));
1021 	return (error);
1022 }
1023 
1024 /*
1025  * Unmounts a tarfs filesystem.
1026  */
1027 static int
1028 tarfs_unmount(struct mount *mp, int mntflags)
1029 {
1030 	struct thread *td = curthread;
1031 	struct tarfs_mount *tmp;
1032 	struct vnode *vp;
1033 	int error;
1034 	int flags = 0;
1035 
1036 	TARFS_DPF(FS, "%s: Unmounting %p\n", __func__, mp);
1037 
1038 	/* Handle forced unmounts */
1039 	if (mntflags & MNT_FORCE)
1040 		flags |= FORCECLOSE;
1041 
1042 	/* Finalize all pending I/O */
1043 	error = vflush(mp, 0, flags, curthread);
1044 	if (error != 0)
1045 		return (error);
1046 	tmp = MP_TO_TARFS_MOUNT(mp);
1047 	vp = tmp->vp;
1048 
1049 	MPASS(vp != NULL);
1050 	TARFS_DPF(FS, "%s: U: hold %u use %u lock 0x%x\n", __func__,
1051 	    vp->v_holdcnt, vp->v_usecount, VOP_ISLOCKED(vp));
1052 	vn_close(vp, FREAD, td->td_ucred, td);
1053 	TARFS_DPF(FS, "%s: C: hold %u use %u lock 0x%x\n", __func__,
1054 	    vp->v_holdcnt, vp->v_usecount, VOP_ISLOCKED(vp));
1055 	tarfs_free_mount(tmp);
1056 
1057 	return (0);
1058 }
1059 
1060 /*
1061  * Gets the root of a tarfs filesystem.  Returns 0 on success or a
1062  * positive errno value on failure.
1063  */
1064 static int
1065 tarfs_root(struct mount *mp, int flags, struct vnode **vpp)
1066 {
1067 	struct vnode *nvp;
1068 	int error;
1069 
1070 	TARFS_DPF(FS, "%s: Getting root vnode\n", __func__);
1071 
1072 	error = VFS_VGET(mp, TARFS_ROOTINO, LK_EXCLUSIVE, &nvp);
1073 	if (error != 0)
1074 		return (error);
1075 
1076 	nvp->v_vflag |= VV_ROOT;
1077 	*vpp = nvp;
1078 	return (0);
1079 }
1080 
1081 /*
1082  * Gets statistics for a tarfs filesystem.  Returns 0.
1083  */
1084 static int
1085 tarfs_statfs(struct mount *mp, struct statfs *sbp)
1086 {
1087 	struct tarfs_mount *tmp;
1088 
1089 	tmp = MP_TO_TARFS_MOUNT(mp);
1090 
1091 	sbp->f_bsize = TARFS_BLOCKSIZE;
1092 	sbp->f_iosize = tmp->iosize;
1093 	sbp->f_blocks = tmp->nblocks;
1094 	sbp->f_bfree = 0;
1095 	sbp->f_bavail = 0;
1096 	sbp->f_files = tmp->nfiles;
1097 	sbp->f_ffree = 0;
1098 
1099 	return (0);
1100 }
1101 
1102 /*
1103  * Gets a vnode for the given inode.  On success, a pointer to the vnode
1104  * is stored in vpp.  Returns 0 on success or a positive errno value on
1105  * failure.
1106  */
1107 static int
1108 tarfs_vget(struct mount *mp, ino_t ino, int lkflags, struct vnode **vpp)
1109 {
1110 	struct tarfs_mount *tmp;
1111 	struct tarfs_node *tnp;
1112 	struct thread *td;
1113 	struct vnode *vp;
1114 	int error;
1115 
1116 	TARFS_DPF(FS, "%s: mp %p, ino %lu, lkflags %d\n", __func__, mp, ino,
1117 	    lkflags);
1118 
1119 	td = curthread;
1120 	error = vfs_hash_get(mp, ino, lkflags, td, vpp, NULL, NULL);
1121 	if (error != 0)
1122 		return (error);
1123 
1124 	if (*vpp != NULL) {
1125 		TARFS_DPF(FS, "%s: found hashed vnode %p\n", __func__, *vpp);
1126 		return (error);
1127 	}
1128 
1129 	TARFS_DPF(FS, "%s: no hashed vnode for inode %lu\n", __func__, ino);
1130 
1131 	tmp = MP_TO_TARFS_MOUNT(mp);
1132 
1133 	if (ino == TARFS_ZIOINO) {
1134 		error = vget(tmp->znode, lkflags);
1135 		if (error != 0)
1136 			return (error);
1137 		*vpp = tmp->znode;
1138 		return (0);
1139 	}
1140 
1141 	/* XXX Should use hash instead? */
1142 	TAILQ_FOREACH(tnp, &tmp->allnodes, entries) {
1143 		if (tnp->ino == ino)
1144 			break;
1145 	}
1146 	TARFS_DPF(FS, "%s: search of all nodes found %p\n", __func__, tnp);
1147 	if (tnp == NULL)
1148 		return (ENOENT);
1149 
1150 	(void)getnewvnode("tarfs", mp, &tarfs_vnodeops, &vp);
1151 	TARFS_DPF(FS, "%s: allocated vnode\n", __func__);
1152 	vp->v_data = tnp;
1153 	vp->v_type = tnp->type;
1154 	tnp->vnode = vp;
1155 
1156 	lockmgr(vp->v_vnlock, lkflags, NULL);
1157 	error = insmntque(vp, mp);
1158 	if (error != 0)
1159 		goto bad;
1160 	TARFS_DPF(FS, "%s: inserting entry into VFS hash\n", __func__);
1161 	error = vfs_hash_insert(vp, ino, lkflags, td, vpp, NULL, NULL);
1162 	if (error != 0 || *vpp != NULL)
1163 		return (error);
1164 
1165 	vn_set_state(vp, VSTATE_CONSTRUCTED);
1166 	*vpp = vp;
1167 	return (0);
1168 
1169 bad:
1170 	*vpp = NULLVP;
1171 	return (error);
1172 }
1173 
1174 static int
1175 tarfs_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp)
1176 {
1177 	struct tarfs_node *tnp;
1178 	struct tarfs_fid *tfp;
1179 	struct vnode *nvp;
1180 	int error;
1181 
1182 	tfp = (struct tarfs_fid *)fhp;
1183 	MP_TO_TARFS_MOUNT(mp);
1184 	if (tfp->ino < TARFS_ROOTINO || tfp->ino > INT_MAX)
1185 		return (ESTALE);
1186 
1187 	error = VFS_VGET(mp, tfp->ino, LK_EXCLUSIVE, &nvp);
1188 	if (error != 0) {
1189 		*vpp = NULLVP;
1190 		return (error);
1191 	}
1192 	tnp = VP_TO_TARFS_NODE(nvp);
1193 	if (tnp->mode == 0 ||
1194 	    tnp->gen != tfp->gen ||
1195 	    tnp->nlink <= 0) {
1196 		vput(nvp);
1197 		*vpp = NULLVP;
1198 		return (ESTALE);
1199 	}
1200 	*vpp = nvp;
1201 	return (0);
1202 }
1203 
1204 static struct vfsops tarfs_vfsops = {
1205 	.vfs_fhtovp =	tarfs_fhtovp,
1206 	.vfs_mount =	tarfs_mount,
1207 	.vfs_root =	tarfs_root,
1208 	.vfs_statfs =	tarfs_statfs,
1209 	.vfs_unmount =	tarfs_unmount,
1210 	.vfs_vget =	tarfs_vget,
1211 };
1212 VFS_SET(tarfs_vfsops, tarfs, VFCF_READONLY);
1213 MODULE_VERSION(tarfs, 1);
1214 MODULE_DEPEND(tarfs, xz, 1, 1, 1);
1215