xref: /freebsd/sys/fs/tarfs/tarfs_vnops.c (revision 742f4b77)
169d94f4cSDag-Erling Smørgrav /*-
269d94f4cSDag-Erling Smørgrav  * SPDX-License-Identifier: BSD-2-Clause
369d94f4cSDag-Erling Smørgrav  *
469d94f4cSDag-Erling Smørgrav  * Copyright (c) 2013 Juniper Networks, Inc.
569d94f4cSDag-Erling Smørgrav  * Copyright (c) 2022-2023 Klara, Inc.
669d94f4cSDag-Erling Smørgrav  *
769d94f4cSDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
869d94f4cSDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
969d94f4cSDag-Erling Smørgrav  * are met:
1069d94f4cSDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
1169d94f4cSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer.
1269d94f4cSDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
1369d94f4cSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
1469d94f4cSDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
1569d94f4cSDag-Erling Smørgrav  *
1669d94f4cSDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1769d94f4cSDag-Erling Smørgrav  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1869d94f4cSDag-Erling Smørgrav  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1969d94f4cSDag-Erling Smørgrav  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2069d94f4cSDag-Erling Smørgrav  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2169d94f4cSDag-Erling Smørgrav  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2269d94f4cSDag-Erling Smørgrav  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2369d94f4cSDag-Erling Smørgrav  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2469d94f4cSDag-Erling Smørgrav  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2569d94f4cSDag-Erling Smørgrav  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2669d94f4cSDag-Erling Smørgrav  * SUCH DAMAGE.
2769d94f4cSDag-Erling Smørgrav  */
2869d94f4cSDag-Erling Smørgrav 
2969d94f4cSDag-Erling Smørgrav #include "opt_tarfs.h"
3069d94f4cSDag-Erling Smørgrav 
3169d94f4cSDag-Erling Smørgrav #include <sys/param.h>
3269d94f4cSDag-Erling Smørgrav #include <sys/systm.h>
3369d94f4cSDag-Erling Smørgrav #include <sys/bio.h>
3469d94f4cSDag-Erling Smørgrav #include <sys/buf.h>
3569d94f4cSDag-Erling Smørgrav #include <sys/dirent.h>
3669d94f4cSDag-Erling Smørgrav #include <sys/fcntl.h>
3769d94f4cSDag-Erling Smørgrav #include <sys/limits.h>
3869d94f4cSDag-Erling Smørgrav #include <sys/mount.h>
3969d94f4cSDag-Erling Smørgrav #include <sys/namei.h>
4069d94f4cSDag-Erling Smørgrav #include <sys/proc.h>
4169d94f4cSDag-Erling Smørgrav #include <sys/vnode.h>
4269d94f4cSDag-Erling Smørgrav 
4369d94f4cSDag-Erling Smørgrav #include <fs/tarfs/tarfs.h>
4469d94f4cSDag-Erling Smørgrav #include <fs/tarfs/tarfs_dbg.h>
4569d94f4cSDag-Erling Smørgrav 
4669d94f4cSDag-Erling Smørgrav static int
tarfs_open(struct vop_open_args * ap)4769d94f4cSDag-Erling Smørgrav tarfs_open(struct vop_open_args *ap)
4869d94f4cSDag-Erling Smørgrav {
4969d94f4cSDag-Erling Smørgrav 	struct tarfs_node *tnp;
5069d94f4cSDag-Erling Smørgrav 	struct vnode *vp;
5169d94f4cSDag-Erling Smørgrav 
5269d94f4cSDag-Erling Smørgrav 	vp = ap->a_vp;
5369d94f4cSDag-Erling Smørgrav 	MPASS(VOP_ISLOCKED(vp));
5469d94f4cSDag-Erling Smørgrav 	tnp = VP_TO_TARFS_NODE(vp);
5569d94f4cSDag-Erling Smørgrav 
5669d94f4cSDag-Erling Smørgrav 	TARFS_DPF(VNODE, "%s(%p=%s, %o)\n", __func__,
5769d94f4cSDag-Erling Smørgrav 	    tnp, tnp->name, ap->a_mode);
5869d94f4cSDag-Erling Smørgrav 
5969d94f4cSDag-Erling Smørgrav 	if (vp->v_type != VREG && vp->v_type != VDIR)
6069d94f4cSDag-Erling Smørgrav 		return (EOPNOTSUPP);
6169d94f4cSDag-Erling Smørgrav 
6269d94f4cSDag-Erling Smørgrav 	vnode_create_vobject(vp, tnp->size, ap->a_td);
6369d94f4cSDag-Erling Smørgrav 	return (0);
6469d94f4cSDag-Erling Smørgrav }
6569d94f4cSDag-Erling Smørgrav 
6669d94f4cSDag-Erling Smørgrav static int
tarfs_close(struct vop_close_args * ap)6769d94f4cSDag-Erling Smørgrav tarfs_close(struct vop_close_args *ap)
6869d94f4cSDag-Erling Smørgrav {
6969d94f4cSDag-Erling Smørgrav #ifdef TARFS_DEBUG
7069d94f4cSDag-Erling Smørgrav 	struct tarfs_node *tnp;
7169d94f4cSDag-Erling Smørgrav 	struct vnode *vp;
7269d94f4cSDag-Erling Smørgrav 
7369d94f4cSDag-Erling Smørgrav 	vp = ap->a_vp;
7469d94f4cSDag-Erling Smørgrav 
7569d94f4cSDag-Erling Smørgrav 	MPASS(VOP_ISLOCKED(vp));
7669d94f4cSDag-Erling Smørgrav 	tnp = VP_TO_TARFS_NODE(vp);
7769d94f4cSDag-Erling Smørgrav 
7869d94f4cSDag-Erling Smørgrav 	TARFS_DPF(VNODE, "%s(%p=%s)\n", __func__,
7969d94f4cSDag-Erling Smørgrav 	    tnp, tnp->name);
8069d94f4cSDag-Erling Smørgrav #else
8169d94f4cSDag-Erling Smørgrav 	(void)ap;
8269d94f4cSDag-Erling Smørgrav #endif
8369d94f4cSDag-Erling Smørgrav 	return (0);
8469d94f4cSDag-Erling Smørgrav }
8569d94f4cSDag-Erling Smørgrav 
8669d94f4cSDag-Erling Smørgrav static int
tarfs_access(struct vop_access_args * ap)8769d94f4cSDag-Erling Smørgrav tarfs_access(struct vop_access_args *ap)
8869d94f4cSDag-Erling Smørgrav {
8969d94f4cSDag-Erling Smørgrav 	struct tarfs_node *tnp;
9069d94f4cSDag-Erling Smørgrav 	struct vnode *vp;
9169d94f4cSDag-Erling Smørgrav 	accmode_t accmode;
9269d94f4cSDag-Erling Smørgrav 	struct ucred *cred;
9369d94f4cSDag-Erling Smørgrav 	int error;
9469d94f4cSDag-Erling Smørgrav 
9569d94f4cSDag-Erling Smørgrav 	vp = ap->a_vp;
9669d94f4cSDag-Erling Smørgrav 	accmode = ap->a_accmode;
9769d94f4cSDag-Erling Smørgrav 	cred = ap->a_cred;
9869d94f4cSDag-Erling Smørgrav 
9969d94f4cSDag-Erling Smørgrav 	MPASS(VOP_ISLOCKED(vp));
10069d94f4cSDag-Erling Smørgrav 	tnp = VP_TO_TARFS_NODE(vp);
10169d94f4cSDag-Erling Smørgrav 
10269d94f4cSDag-Erling Smørgrav 	TARFS_DPF(VNODE, "%s(%p=%s, %o)\n", __func__,
10369d94f4cSDag-Erling Smørgrav 	    tnp, tnp->name, accmode);
10469d94f4cSDag-Erling Smørgrav 
10569d94f4cSDag-Erling Smørgrav 	switch (vp->v_type) {
10669d94f4cSDag-Erling Smørgrav 	case VDIR:
10769d94f4cSDag-Erling Smørgrav 	case VLNK:
10869d94f4cSDag-Erling Smørgrav 	case VREG:
10969d94f4cSDag-Erling Smørgrav 		if ((accmode & VWRITE) != 0)
11069d94f4cSDag-Erling Smørgrav 			return (EROFS);
11169d94f4cSDag-Erling Smørgrav 		break;
11269d94f4cSDag-Erling Smørgrav 	case VBLK:
11369d94f4cSDag-Erling Smørgrav 	case VCHR:
11469d94f4cSDag-Erling Smørgrav 	case VFIFO:
11569d94f4cSDag-Erling Smørgrav 		break;
11669d94f4cSDag-Erling Smørgrav 	default:
11769d94f4cSDag-Erling Smørgrav 		return (EINVAL);
11869d94f4cSDag-Erling Smørgrav 	}
11969d94f4cSDag-Erling Smørgrav 
12069d94f4cSDag-Erling Smørgrav 	if ((accmode & VWRITE) != 0)
12169d94f4cSDag-Erling Smørgrav 		return (EPERM);
12269d94f4cSDag-Erling Smørgrav 
12369d94f4cSDag-Erling Smørgrav 	error = vaccess(vp->v_type, tnp->mode, tnp->uid,
12469d94f4cSDag-Erling Smørgrav 	    tnp->gid, accmode, cred);
12569d94f4cSDag-Erling Smørgrav 	return (error);
12669d94f4cSDag-Erling Smørgrav }
12769d94f4cSDag-Erling Smørgrav 
12869d94f4cSDag-Erling Smørgrav static int
tarfs_bmap(struct vop_bmap_args * ap)129a0895e39SMark Johnston tarfs_bmap(struct vop_bmap_args *ap)
130a0895e39SMark Johnston {
131a0895e39SMark Johnston 	struct tarfs_node *tnp;
132a0895e39SMark Johnston 	struct vnode *vp;
133a0895e39SMark Johnston 	off_t off;
134a0895e39SMark Johnston 	uint64_t iosize;
135a0895e39SMark Johnston 	int ra, rb, rmax;
136a0895e39SMark Johnston 
137a0895e39SMark Johnston 	vp = ap->a_vp;
138a0895e39SMark Johnston 	iosize = vp->v_mount->mnt_stat.f_iosize;
139a0895e39SMark Johnston 
140a0895e39SMark Johnston 	if (ap->a_bop != NULL)
141a0895e39SMark Johnston 		*ap->a_bop = &vp->v_bufobj;
142a0895e39SMark Johnston 	if (ap->a_bnp != NULL)
143a0895e39SMark Johnston 		*ap->a_bnp = ap->a_bn * btodb(iosize);
144a0895e39SMark Johnston 	if (ap->a_runp == NULL)
145a0895e39SMark Johnston 		return (0);
146a0895e39SMark Johnston 
147a0895e39SMark Johnston 	tnp = VP_TO_TARFS_NODE(vp);
148a0895e39SMark Johnston 	off = ap->a_bn * iosize;
149a0895e39SMark Johnston 
150a0895e39SMark Johnston 	ra = rb = 0;
151a0895e39SMark Johnston 	for (u_int i = 0; i < tnp->nblk; i++) {
152a0895e39SMark Johnston 		off_t bs, be;
153a0895e39SMark Johnston 
154a0895e39SMark Johnston 		bs = tnp->blk[i].o;
155a0895e39SMark Johnston 		be = tnp->blk[i].o + tnp->blk[i].l;
156a0895e39SMark Johnston 		if (off > be)
157a0895e39SMark Johnston 			continue;
158a0895e39SMark Johnston 		else if (off < bs) {
159a0895e39SMark Johnston 			/* We're in a hole. */
160a0895e39SMark Johnston 			ra = bs - off < iosize ?
161a0895e39SMark Johnston 			    0 : howmany(bs - (off + iosize), iosize);
162a0895e39SMark Johnston 			rb = howmany(off - (i == 0 ?
163a0895e39SMark Johnston 			    0 : tnp->blk[i - 1].o + tnp->blk[i - 1].l),
164a0895e39SMark Johnston 			    iosize);
165a0895e39SMark Johnston 			break;
166a0895e39SMark Johnston 		} else {
167a0895e39SMark Johnston 			/* We'll be reading from the backing file. */
168a0895e39SMark Johnston 			ra = be - off < iosize ?
169a0895e39SMark Johnston 			    0 : howmany(be - (off + iosize), iosize);
170a0895e39SMark Johnston 			rb = howmany(off - bs, iosize);
171a0895e39SMark Johnston 			break;
172a0895e39SMark Johnston 		}
173a0895e39SMark Johnston 	}
174a0895e39SMark Johnston 
175a0895e39SMark Johnston 	rmax = vp->v_mount->mnt_iosize_max / iosize - 1;
176a0895e39SMark Johnston 	*ap->a_runp = imin(ra, rmax);
177a0895e39SMark Johnston 	if (ap->a_runb != NULL)
178a0895e39SMark Johnston 		*ap->a_runb = imin(rb, rmax);
179a0895e39SMark Johnston 	return (0);
180a0895e39SMark Johnston }
181a0895e39SMark Johnston 
182a0895e39SMark Johnston static int
tarfs_getattr(struct vop_getattr_args * ap)18369d94f4cSDag-Erling Smørgrav tarfs_getattr(struct vop_getattr_args *ap)
18469d94f4cSDag-Erling Smørgrav {
18569d94f4cSDag-Erling Smørgrav 	struct tarfs_node *tnp;
18669d94f4cSDag-Erling Smørgrav 	struct vnode *vp;
18769d94f4cSDag-Erling Smørgrav 	struct vattr *vap;
18869d94f4cSDag-Erling Smørgrav 
18969d94f4cSDag-Erling Smørgrav 	vp = ap->a_vp;
19069d94f4cSDag-Erling Smørgrav 	vap = ap->a_vap;
19169d94f4cSDag-Erling Smørgrav 	tnp = VP_TO_TARFS_NODE(vp);
19269d94f4cSDag-Erling Smørgrav 
19369d94f4cSDag-Erling Smørgrav 	TARFS_DPF(VNODE, "%s(%p=%s)\n", __func__,
19469d94f4cSDag-Erling Smørgrav 	    tnp, tnp->name);
19569d94f4cSDag-Erling Smørgrav 
19669d94f4cSDag-Erling Smørgrav 	vap->va_type = vp->v_type;
19769d94f4cSDag-Erling Smørgrav 	vap->va_mode = tnp->mode;
19869d94f4cSDag-Erling Smørgrav 	vap->va_nlink = tnp->nlink;
19969d94f4cSDag-Erling Smørgrav 	vap->va_gid = tnp->gid;
20069d94f4cSDag-Erling Smørgrav 	vap->va_uid = tnp->uid;
20169d94f4cSDag-Erling Smørgrav 	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
20269d94f4cSDag-Erling Smørgrav 	vap->va_fileid = tnp->ino;
20369d94f4cSDag-Erling Smørgrav 	vap->va_size = tnp->size;
20469d94f4cSDag-Erling Smørgrav 	vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
20569d94f4cSDag-Erling Smørgrav 	vap->va_atime = tnp->atime;
20669d94f4cSDag-Erling Smørgrav 	vap->va_ctime = tnp->ctime;
20769d94f4cSDag-Erling Smørgrav 	vap->va_mtime = tnp->mtime;
20869d94f4cSDag-Erling Smørgrav 	vap->va_birthtime = tnp->birthtime;
20969d94f4cSDag-Erling Smørgrav 	vap->va_gen = tnp->gen;
21069d94f4cSDag-Erling Smørgrav 	vap->va_flags = tnp->flags;
21169d94f4cSDag-Erling Smørgrav 	vap->va_rdev = (vp->v_type == VBLK || vp->v_type == VCHR) ?
21269d94f4cSDag-Erling Smørgrav 	    tnp->rdev : NODEV;
21369d94f4cSDag-Erling Smørgrav 	vap->va_bytes = round_page(tnp->physize);
21469d94f4cSDag-Erling Smørgrav 	vap->va_filerev = 0;
21569d94f4cSDag-Erling Smørgrav 
21669d94f4cSDag-Erling Smørgrav 	return (0);
21769d94f4cSDag-Erling Smørgrav }
21869d94f4cSDag-Erling Smørgrav 
21969d94f4cSDag-Erling Smørgrav static int
tarfs_lookup(struct vop_cachedlookup_args * ap)22069d94f4cSDag-Erling Smørgrav tarfs_lookup(struct vop_cachedlookup_args *ap)
22169d94f4cSDag-Erling Smørgrav {
222af0435e1SDag-Erling Smørgrav 	struct tarfs_mount *tmp;
22369d94f4cSDag-Erling Smørgrav 	struct tarfs_node *dirnode, *parent, *tnp;
22469d94f4cSDag-Erling Smørgrav 	struct componentname *cnp;
22569d94f4cSDag-Erling Smørgrav 	struct vnode *dvp, **vpp;
22669d94f4cSDag-Erling Smørgrav #ifdef TARFS_DEBUG
22769d94f4cSDag-Erling Smørgrav 	struct vnode *vp;
22869d94f4cSDag-Erling Smørgrav #endif
22969d94f4cSDag-Erling Smørgrav 	int error;
23069d94f4cSDag-Erling Smørgrav 
23169d94f4cSDag-Erling Smørgrav 	dvp = ap->a_dvp;
23269d94f4cSDag-Erling Smørgrav 	vpp = ap->a_vpp;
23369d94f4cSDag-Erling Smørgrav 	cnp = ap->a_cnp;
23469d94f4cSDag-Erling Smørgrav 
23569d94f4cSDag-Erling Smørgrav 	*vpp = NULLVP;
23669d94f4cSDag-Erling Smørgrav 	dirnode = VP_TO_TARFS_NODE(dvp);
23769d94f4cSDag-Erling Smørgrav 	parent = dirnode->parent;
238af0435e1SDag-Erling Smørgrav 	tmp = dirnode->tmp;
23969d94f4cSDag-Erling Smørgrav 	tnp = NULL;
24069d94f4cSDag-Erling Smørgrav 
24169d94f4cSDag-Erling Smørgrav 	TARFS_DPF(LOOKUP, "%s(%p=%s, %.*s)\n", __func__,
24269d94f4cSDag-Erling Smørgrav 	    dirnode, dirnode->name,
24369d94f4cSDag-Erling Smørgrav 	    (int)cnp->cn_namelen, cnp->cn_nameptr);
24469d94f4cSDag-Erling Smørgrav 
24569d94f4cSDag-Erling Smørgrav 	error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, curthread);
24669d94f4cSDag-Erling Smørgrav 	if (error != 0)
24769d94f4cSDag-Erling Smørgrav 		return (error);
24869d94f4cSDag-Erling Smørgrav 
24969d94f4cSDag-Erling Smørgrav 	if (cnp->cn_flags & ISDOTDOT) {
25069d94f4cSDag-Erling Smørgrav 		/* Do not allow .. on the root node */
25169d94f4cSDag-Erling Smørgrav 		if (parent == NULL || parent == dirnode)
25269d94f4cSDag-Erling Smørgrav 			return (ENOENT);
25369d94f4cSDag-Erling Smørgrav 
25469d94f4cSDag-Erling Smørgrav 		/* Allocate a new vnode on the matching entry */
25569d94f4cSDag-Erling Smørgrav 		error = vn_vget_ino(dvp, parent->ino, cnp->cn_lkflags,
25669d94f4cSDag-Erling Smørgrav 		    vpp);
25769d94f4cSDag-Erling Smørgrav 		if (error != 0)
25869d94f4cSDag-Erling Smørgrav 			return (error);
25969d94f4cSDag-Erling Smørgrav 	} else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
26069d94f4cSDag-Erling Smørgrav 		VREF(dvp);
26169d94f4cSDag-Erling Smørgrav 		*vpp = dvp;
26269d94f4cSDag-Erling Smørgrav #ifdef TARFS_DEBUG
26369d94f4cSDag-Erling Smørgrav 	} else if (dirnode == dirnode->tmp->root &&
26469d94f4cSDag-Erling Smørgrav 	    (vp = dirnode->tmp->znode) != NULL &&
26569d94f4cSDag-Erling Smørgrav 	    cnp->cn_namelen == TARFS_ZIO_NAMELEN &&
26669d94f4cSDag-Erling Smørgrav 	    memcmp(cnp->cn_nameptr, TARFS_ZIO_NAME, TARFS_ZIO_NAMELEN) == 0) {
26769d94f4cSDag-Erling Smørgrav 		error = vn_lock(vp, cnp->cn_lkflags);
26869d94f4cSDag-Erling Smørgrav 		if (error != 0)
26969d94f4cSDag-Erling Smørgrav 			return (error);
27069d94f4cSDag-Erling Smørgrav 		vref(vp);
27169d94f4cSDag-Erling Smørgrav 		*vpp = vp;
27269d94f4cSDag-Erling Smørgrav 		return (0);
27369d94f4cSDag-Erling Smørgrav #endif
27469d94f4cSDag-Erling Smørgrav 	} else {
27569d94f4cSDag-Erling Smørgrav 		tnp = tarfs_lookup_node(dirnode, NULL, cnp);
27669d94f4cSDag-Erling Smørgrav 		if (tnp == NULL) {
27769d94f4cSDag-Erling Smørgrav 			TARFS_DPF(LOOKUP, "%s(%p=%s, %.*s): file not found\n", __func__,
27869d94f4cSDag-Erling Smørgrav 			    dirnode, dirnode->name,
27969d94f4cSDag-Erling Smørgrav 			    (int)cnp->cn_namelen, cnp->cn_nameptr);
28069d94f4cSDag-Erling Smørgrav 			return (ENOENT);
28169d94f4cSDag-Erling Smørgrav 		}
28269d94f4cSDag-Erling Smørgrav 
28369d94f4cSDag-Erling Smørgrav 		if ((cnp->cn_flags & ISLASTCN) == 0 &&
28469d94f4cSDag-Erling Smørgrav 		    (tnp->type != VDIR && tnp->type != VLNK))
28569d94f4cSDag-Erling Smørgrav 			return (ENOTDIR);
28669d94f4cSDag-Erling Smørgrav 
287af0435e1SDag-Erling Smørgrav 		error = VFS_VGET(tmp->vfs, tnp->ino, cnp->cn_lkflags, vpp);
28869d94f4cSDag-Erling Smørgrav 		if (error != 0)
28969d94f4cSDag-Erling Smørgrav 			return (error);
29069d94f4cSDag-Erling Smørgrav 	}
29169d94f4cSDag-Erling Smørgrav 
29269d94f4cSDag-Erling Smørgrav #ifdef	TARFS_DEBUG
29369d94f4cSDag-Erling Smørgrav 	if (tnp == NULL)
29469d94f4cSDag-Erling Smørgrav 		tnp = VP_TO_TARFS_NODE(*vpp);
29569d94f4cSDag-Erling Smørgrav 	TARFS_DPF(LOOKUP, "%s: found vnode %p, tarfs_node %p\n", __func__,
29669d94f4cSDag-Erling Smørgrav 	    *vpp, tnp);
29769d94f4cSDag-Erling Smørgrav #endif	/* TARFS_DEBUG */
29869d94f4cSDag-Erling Smørgrav 
299*742f4b77SGordon Bergling 	/* Store the result of the cache if MAKEENTRY is specified in flags */
30069d94f4cSDag-Erling Smørgrav 	if ((cnp->cn_flags & MAKEENTRY) != 0 && cnp->cn_nameiop != CREATE)
30169d94f4cSDag-Erling Smørgrav 		cache_enter(dvp, *vpp, cnp);
30269d94f4cSDag-Erling Smørgrav 
30369d94f4cSDag-Erling Smørgrav 	return (error);
30469d94f4cSDag-Erling Smørgrav }
30569d94f4cSDag-Erling Smørgrav 
30669d94f4cSDag-Erling Smørgrav static int
tarfs_readdir(struct vop_readdir_args * ap)30769d94f4cSDag-Erling Smørgrav tarfs_readdir(struct vop_readdir_args *ap)
30869d94f4cSDag-Erling Smørgrav {
309ce6a0c77SDag-Erling Smørgrav 	struct dirent cde = { };
31069d94f4cSDag-Erling Smørgrav 	struct tarfs_node *current, *tnp;
31169d94f4cSDag-Erling Smørgrav 	struct vnode *vp;
31269d94f4cSDag-Erling Smørgrav 	struct uio *uio;
31369d94f4cSDag-Erling Smørgrav 	int *eofflag;
314fb53e7adSDag-Erling Smørgrav 	uint64_t **cookies;
31569d94f4cSDag-Erling Smørgrav 	int *ncookies;
31669d94f4cSDag-Erling Smørgrav 	off_t off;
31769d94f4cSDag-Erling Smørgrav 	u_int idx, ndirents;
31869d94f4cSDag-Erling Smørgrav 	int error;
31969d94f4cSDag-Erling Smørgrav 
32069d94f4cSDag-Erling Smørgrav 	vp = ap->a_vp;
32169d94f4cSDag-Erling Smørgrav 	uio = ap->a_uio;
32269d94f4cSDag-Erling Smørgrav 	eofflag = ap->a_eofflag;
32369d94f4cSDag-Erling Smørgrav 	cookies = ap->a_cookies;
32469d94f4cSDag-Erling Smørgrav 	ncookies = ap->a_ncookies;
32569d94f4cSDag-Erling Smørgrav 
32669d94f4cSDag-Erling Smørgrav 	if (vp->v_type != VDIR)
32769d94f4cSDag-Erling Smørgrav 		return (ENOTDIR);
32869d94f4cSDag-Erling Smørgrav 
32969d94f4cSDag-Erling Smørgrav 	tnp = VP_TO_TARFS_NODE(vp);
33069d94f4cSDag-Erling Smørgrav 	off = uio->uio_offset;
33169d94f4cSDag-Erling Smørgrav 	current = NULL;
33269d94f4cSDag-Erling Smørgrav 	ndirents = 0;
33369d94f4cSDag-Erling Smørgrav 
33469d94f4cSDag-Erling Smørgrav 	TARFS_DPF(VNODE, "%s(%p=%s, %zu, %zd)\n", __func__,
33569d94f4cSDag-Erling Smørgrav 	    tnp, tnp->name, uio->uio_offset, uio->uio_resid);
33669d94f4cSDag-Erling Smørgrav 
33769d94f4cSDag-Erling Smørgrav 	if (uio->uio_offset == TARFS_COOKIE_EOF) {
33869d94f4cSDag-Erling Smørgrav 		TARFS_DPF(VNODE, "%s: EOF\n", __func__);
33969d94f4cSDag-Erling Smørgrav 		return (0);
34069d94f4cSDag-Erling Smørgrav 	}
34169d94f4cSDag-Erling Smørgrav 
34269d94f4cSDag-Erling Smørgrav 	if (uio->uio_offset == TARFS_COOKIE_DOT) {
34369d94f4cSDag-Erling Smørgrav 		TARFS_DPF(VNODE, "%s: Generating . entry\n", __func__);
34469d94f4cSDag-Erling Smørgrav 		/* fake . entry */
34569d94f4cSDag-Erling Smørgrav 		cde.d_fileno = tnp->ino;
34669d94f4cSDag-Erling Smørgrav 		cde.d_type = DT_DIR;
34769d94f4cSDag-Erling Smørgrav 		cde.d_namlen = 1;
34869d94f4cSDag-Erling Smørgrav 		cde.d_name[0] = '.';
34969d94f4cSDag-Erling Smørgrav 		cde.d_name[1] = '\0';
35069d94f4cSDag-Erling Smørgrav 		cde.d_reclen = GENERIC_DIRSIZ(&cde);
35169d94f4cSDag-Erling Smørgrav 		if (cde.d_reclen > uio->uio_resid)
35269d94f4cSDag-Erling Smørgrav 			goto full;
353c9ff56ceSDag-Erling Smørgrav 		dirent_terminate(&cde);
35469d94f4cSDag-Erling Smørgrav 		error = uiomove(&cde, cde.d_reclen, uio);
35569d94f4cSDag-Erling Smørgrav 		if (error)
35669d94f4cSDag-Erling Smørgrav 			return (error);
35769d94f4cSDag-Erling Smørgrav 		/* next is .. */
35869d94f4cSDag-Erling Smørgrav 		uio->uio_offset = TARFS_COOKIE_DOTDOT;
35969d94f4cSDag-Erling Smørgrav 		ndirents++;
36069d94f4cSDag-Erling Smørgrav 	}
36169d94f4cSDag-Erling Smørgrav 
36269d94f4cSDag-Erling Smørgrav 	if (uio->uio_offset == TARFS_COOKIE_DOTDOT) {
36369d94f4cSDag-Erling Smørgrav 		TARFS_DPF(VNODE, "%s: Generating .. entry\n", __func__);
36469d94f4cSDag-Erling Smørgrav 		/* fake .. entry */
36569d94f4cSDag-Erling Smørgrav 		MPASS(tnp->parent != NULL);
36669d94f4cSDag-Erling Smørgrav 		TARFS_NODE_LOCK(tnp->parent);
36769d94f4cSDag-Erling Smørgrav 		cde.d_fileno = tnp->parent->ino;
36869d94f4cSDag-Erling Smørgrav 		TARFS_NODE_UNLOCK(tnp->parent);
36969d94f4cSDag-Erling Smørgrav 		cde.d_type = DT_DIR;
37069d94f4cSDag-Erling Smørgrav 		cde.d_namlen = 2;
37169d94f4cSDag-Erling Smørgrav 		cde.d_name[0] = '.';
37269d94f4cSDag-Erling Smørgrav 		cde.d_name[1] = '.';
37369d94f4cSDag-Erling Smørgrav 		cde.d_name[2] = '\0';
37469d94f4cSDag-Erling Smørgrav 		cde.d_reclen = GENERIC_DIRSIZ(&cde);
37569d94f4cSDag-Erling Smørgrav 		if (cde.d_reclen > uio->uio_resid)
37669d94f4cSDag-Erling Smørgrav 			goto full;
377c9ff56ceSDag-Erling Smørgrav 		dirent_terminate(&cde);
37869d94f4cSDag-Erling Smørgrav 		error = uiomove(&cde, cde.d_reclen, uio);
37969d94f4cSDag-Erling Smørgrav 		if (error)
38069d94f4cSDag-Erling Smørgrav 			return (error);
38169d94f4cSDag-Erling Smørgrav 		/* next is first child */
38269d94f4cSDag-Erling Smørgrav 		current = TAILQ_FIRST(&tnp->dir.dirhead);
38369d94f4cSDag-Erling Smørgrav 		if (current == NULL)
38469d94f4cSDag-Erling Smørgrav 			goto done;
38569d94f4cSDag-Erling Smørgrav 		uio->uio_offset = current->ino;
38669d94f4cSDag-Erling Smørgrav 		TARFS_DPF(VNODE, "%s: [%u] setting current node to %p=%s\n",
38769d94f4cSDag-Erling Smørgrav 		    __func__, ndirents, current, current->name);
38869d94f4cSDag-Erling Smørgrav 		ndirents++;
38969d94f4cSDag-Erling Smørgrav 	}
39069d94f4cSDag-Erling Smørgrav 
39169d94f4cSDag-Erling Smørgrav 	/* resuming previous call */
39269d94f4cSDag-Erling Smørgrav 	if (current == NULL) {
39369d94f4cSDag-Erling Smørgrav 		current = tarfs_lookup_dir(tnp, uio->uio_offset);
39469d94f4cSDag-Erling Smørgrav 		if (current == NULL) {
39569d94f4cSDag-Erling Smørgrav 			error = EINVAL;
39669d94f4cSDag-Erling Smørgrav 			goto done;
39769d94f4cSDag-Erling Smørgrav 		}
39869d94f4cSDag-Erling Smørgrav 		uio->uio_offset = current->ino;
39969d94f4cSDag-Erling Smørgrav 		TARFS_DPF(VNODE, "%s: [%u] setting current node to %p=%s\n",
40069d94f4cSDag-Erling Smørgrav 		    __func__, ndirents, current, current->name);
40169d94f4cSDag-Erling Smørgrav 	}
40269d94f4cSDag-Erling Smørgrav 
40369d94f4cSDag-Erling Smørgrav 	for (;;) {
40469d94f4cSDag-Erling Smørgrav 		cde.d_fileno = current->ino;
40569d94f4cSDag-Erling Smørgrav 		switch (current->type) {
40669d94f4cSDag-Erling Smørgrav 		case VBLK:
40769d94f4cSDag-Erling Smørgrav 			cde.d_type = DT_BLK;
40869d94f4cSDag-Erling Smørgrav 			break;
40969d94f4cSDag-Erling Smørgrav 		case VCHR:
41069d94f4cSDag-Erling Smørgrav 			cde.d_type = DT_CHR;
41169d94f4cSDag-Erling Smørgrav 			break;
41269d94f4cSDag-Erling Smørgrav 		case VDIR:
41369d94f4cSDag-Erling Smørgrav 			cde.d_type = DT_DIR;
41469d94f4cSDag-Erling Smørgrav 			break;
41569d94f4cSDag-Erling Smørgrav 		case VFIFO:
41669d94f4cSDag-Erling Smørgrav 			cde.d_type = DT_FIFO;
41769d94f4cSDag-Erling Smørgrav 			break;
41869d94f4cSDag-Erling Smørgrav 		case VLNK:
41969d94f4cSDag-Erling Smørgrav 			cde.d_type = DT_LNK;
42069d94f4cSDag-Erling Smørgrav 			break;
42169d94f4cSDag-Erling Smørgrav 		case VREG:
42269d94f4cSDag-Erling Smørgrav 			cde.d_type = DT_REG;
42369d94f4cSDag-Erling Smørgrav 			break;
42469d94f4cSDag-Erling Smørgrav 		default:
42569d94f4cSDag-Erling Smørgrav 			panic("%s: tarfs_node %p, type %d\n", __func__,
42669d94f4cSDag-Erling Smørgrav 			    current, current->type);
42769d94f4cSDag-Erling Smørgrav 		}
42869d94f4cSDag-Erling Smørgrav 		cde.d_namlen = current->namelen;
42969d94f4cSDag-Erling Smørgrav 		MPASS(tnp->namelen < sizeof(cde.d_name));
43069d94f4cSDag-Erling Smørgrav 		(void)memcpy(cde.d_name, current->name, current->namelen);
43169d94f4cSDag-Erling Smørgrav 		cde.d_name[current->namelen] = '\0';
43269d94f4cSDag-Erling Smørgrav 		cde.d_reclen = GENERIC_DIRSIZ(&cde);
43369d94f4cSDag-Erling Smørgrav 		if (cde.d_reclen > uio->uio_resid)
43469d94f4cSDag-Erling Smørgrav 			goto full;
435c9ff56ceSDag-Erling Smørgrav 		dirent_terminate(&cde);
43669d94f4cSDag-Erling Smørgrav 		error = uiomove(&cde, cde.d_reclen, uio);
43769d94f4cSDag-Erling Smørgrav 		if (error != 0)
43869d94f4cSDag-Erling Smørgrav 			goto done;
43969d94f4cSDag-Erling Smørgrav 		ndirents++;
44069d94f4cSDag-Erling Smørgrav 		/* next sibling */
44169d94f4cSDag-Erling Smørgrav 		current = TAILQ_NEXT(current, dirents);
44269d94f4cSDag-Erling Smørgrav 		if (current == NULL)
44369d94f4cSDag-Erling Smørgrav 			goto done;
44469d94f4cSDag-Erling Smørgrav 		uio->uio_offset = current->ino;
44569d94f4cSDag-Erling Smørgrav 		TARFS_DPF(VNODE, "%s: [%u] setting current node to %p=%s\n",
44669d94f4cSDag-Erling Smørgrav 		    __func__, ndirents, current, current->name);
44769d94f4cSDag-Erling Smørgrav 	}
44869d94f4cSDag-Erling Smørgrav full:
44969d94f4cSDag-Erling Smørgrav 	if (cde.d_reclen > uio->uio_resid) {
45069d94f4cSDag-Erling Smørgrav 		TARFS_DPF(VNODE, "%s: out of space, returning\n",
45169d94f4cSDag-Erling Smørgrav 		    __func__);
45269d94f4cSDag-Erling Smørgrav 		error = (ndirents == 0) ? EINVAL : 0;
45369d94f4cSDag-Erling Smørgrav 	}
45469d94f4cSDag-Erling Smørgrav done:
45569d94f4cSDag-Erling Smørgrav 	TARFS_DPF(VNODE, "%s: %u entries written\n", __func__, ndirents);
45669d94f4cSDag-Erling Smørgrav 	TARFS_DPF(VNODE, "%s: saving cache information\n", __func__);
45769d94f4cSDag-Erling Smørgrav 	if (current == NULL) {
45869d94f4cSDag-Erling Smørgrav 		uio->uio_offset = TARFS_COOKIE_EOF;
45969d94f4cSDag-Erling Smørgrav 		tnp->dir.lastcookie = 0;
46069d94f4cSDag-Erling Smørgrav 		tnp->dir.lastnode = NULL;
46169d94f4cSDag-Erling Smørgrav 	} else {
46269d94f4cSDag-Erling Smørgrav 		tnp->dir.lastcookie = current->ino;
46369d94f4cSDag-Erling Smørgrav 		tnp->dir.lastnode = current;
46469d94f4cSDag-Erling Smørgrav 	}
46569d94f4cSDag-Erling Smørgrav 
46669d94f4cSDag-Erling Smørgrav 	if (eofflag != NULL) {
46769d94f4cSDag-Erling Smørgrav 		TARFS_DPF(VNODE, "%s: Setting EOF flag\n", __func__);
46869d94f4cSDag-Erling Smørgrav 		*eofflag = (error == 0 && current == NULL);
46969d94f4cSDag-Erling Smørgrav 	}
47069d94f4cSDag-Erling Smørgrav 
47169d94f4cSDag-Erling Smørgrav 	/* Update for NFS */
47269d94f4cSDag-Erling Smørgrav 	if (error == 0 && cookies != NULL && ncookies != NULL) {
47369d94f4cSDag-Erling Smørgrav 		TARFS_DPF(VNODE, "%s: Updating NFS cookies\n", __func__);
47469d94f4cSDag-Erling Smørgrav 		current = NULL;
47569d94f4cSDag-Erling Smørgrav 		*cookies = malloc(ndirents * sizeof(off_t), M_TEMP, M_WAITOK);
47669d94f4cSDag-Erling Smørgrav 		*ncookies = ndirents;
47769d94f4cSDag-Erling Smørgrav 		for (idx = 0; idx < ndirents; idx++) {
47869d94f4cSDag-Erling Smørgrav 			if (off == TARFS_COOKIE_DOT)
47969d94f4cSDag-Erling Smørgrav 				off = TARFS_COOKIE_DOTDOT;
48069d94f4cSDag-Erling Smørgrav 			else {
48169d94f4cSDag-Erling Smørgrav 				if (off == TARFS_COOKIE_DOTDOT) {
48269d94f4cSDag-Erling Smørgrav 					current = TAILQ_FIRST(&tnp->dir.dirhead);
48369d94f4cSDag-Erling Smørgrav 				} else if (current != NULL) {
48469d94f4cSDag-Erling Smørgrav 					current = TAILQ_NEXT(current, dirents);
48569d94f4cSDag-Erling Smørgrav 				} else {
48669d94f4cSDag-Erling Smørgrav 					current = tarfs_lookup_dir(tnp, off);
48769d94f4cSDag-Erling Smørgrav 					current = TAILQ_NEXT(current, dirents);
48869d94f4cSDag-Erling Smørgrav 				}
48969d94f4cSDag-Erling Smørgrav 				if (current == NULL)
49069d94f4cSDag-Erling Smørgrav 					off = TARFS_COOKIE_EOF;
49169d94f4cSDag-Erling Smørgrav 				else
49269d94f4cSDag-Erling Smørgrav 					off = current->ino;
49369d94f4cSDag-Erling Smørgrav 			}
49469d94f4cSDag-Erling Smørgrav 
49569d94f4cSDag-Erling Smørgrav 			TARFS_DPF(VNODE, "%s: [%u] offset %zu\n", __func__,
49669d94f4cSDag-Erling Smørgrav 			    idx, off);
49769d94f4cSDag-Erling Smørgrav 			(*cookies)[idx] = off;
49869d94f4cSDag-Erling Smørgrav 		}
49969d94f4cSDag-Erling Smørgrav 		MPASS(uio->uio_offset == off);
50069d94f4cSDag-Erling Smørgrav 	}
50169d94f4cSDag-Erling Smørgrav 
50269d94f4cSDag-Erling Smørgrav 	return (error);
50369d94f4cSDag-Erling Smørgrav }
50469d94f4cSDag-Erling Smørgrav 
50569d94f4cSDag-Erling Smørgrav static int
tarfs_read(struct vop_read_args * ap)50669d94f4cSDag-Erling Smørgrav tarfs_read(struct vop_read_args *ap)
50769d94f4cSDag-Erling Smørgrav {
50869d94f4cSDag-Erling Smørgrav 	struct tarfs_node *tnp;
50969d94f4cSDag-Erling Smørgrav 	struct uio *uiop;
51069d94f4cSDag-Erling Smørgrav 	struct vnode *vp;
51169d94f4cSDag-Erling Smørgrav 	size_t len;
51269d94f4cSDag-Erling Smørgrav 	off_t resid;
51369d94f4cSDag-Erling Smørgrav 	int error;
51469d94f4cSDag-Erling Smørgrav 
51569d94f4cSDag-Erling Smørgrav 	uiop = ap->a_uio;
51669d94f4cSDag-Erling Smørgrav 	vp = ap->a_vp;
51769d94f4cSDag-Erling Smørgrav 
51869d94f4cSDag-Erling Smørgrav 	if (vp->v_type == VCHR || vp->v_type == VBLK)
51969d94f4cSDag-Erling Smørgrav 		return (EOPNOTSUPP);
52069d94f4cSDag-Erling Smørgrav 
52169d94f4cSDag-Erling Smørgrav 	if (vp->v_type != VREG)
52269d94f4cSDag-Erling Smørgrav 		return (EISDIR);
52369d94f4cSDag-Erling Smørgrav 
52469d94f4cSDag-Erling Smørgrav 	if (uiop->uio_offset < 0)
52569d94f4cSDag-Erling Smørgrav 		return (EINVAL);
52669d94f4cSDag-Erling Smørgrav 
52769d94f4cSDag-Erling Smørgrav 	tnp = VP_TO_TARFS_NODE(vp);
52869d94f4cSDag-Erling Smørgrav 	error = 0;
52969d94f4cSDag-Erling Smørgrav 
53069d94f4cSDag-Erling Smørgrav 	TARFS_DPF(VNODE, "%s(%p=%s, %zu, %zd)\n", __func__,
53169d94f4cSDag-Erling Smørgrav 	    tnp, tnp->name, uiop->uio_offset, uiop->uio_resid);
53269d94f4cSDag-Erling Smørgrav 
53369d94f4cSDag-Erling Smørgrav 	while ((resid = uiop->uio_resid) > 0) {
53469d94f4cSDag-Erling Smørgrav 		if (tnp->size <= uiop->uio_offset)
53569d94f4cSDag-Erling Smørgrav 			break;
53669d94f4cSDag-Erling Smørgrav 		len = MIN(tnp->size - uiop->uio_offset, resid);
53769d94f4cSDag-Erling Smørgrav 		if (len == 0)
53869d94f4cSDag-Erling Smørgrav 			break;
53969d94f4cSDag-Erling Smørgrav 
54069d94f4cSDag-Erling Smørgrav 		error = tarfs_read_file(tnp, len, uiop);
54169d94f4cSDag-Erling Smørgrav 		if (error != 0 || resid == uiop->uio_resid)
54269d94f4cSDag-Erling Smørgrav 			break;
54369d94f4cSDag-Erling Smørgrav 	}
54469d94f4cSDag-Erling Smørgrav 
54569d94f4cSDag-Erling Smørgrav 	return (error);
54669d94f4cSDag-Erling Smørgrav }
54769d94f4cSDag-Erling Smørgrav 
54869d94f4cSDag-Erling Smørgrav static int
tarfs_readlink(struct vop_readlink_args * ap)54969d94f4cSDag-Erling Smørgrav tarfs_readlink(struct vop_readlink_args *ap)
55069d94f4cSDag-Erling Smørgrav {
55169d94f4cSDag-Erling Smørgrav 	struct tarfs_node *tnp;
55269d94f4cSDag-Erling Smørgrav 	struct uio *uiop;
55369d94f4cSDag-Erling Smørgrav 	struct vnode *vp;
55469d94f4cSDag-Erling Smørgrav 	int error;
55569d94f4cSDag-Erling Smørgrav 
55669d94f4cSDag-Erling Smørgrav 	uiop = ap->a_uio;
55769d94f4cSDag-Erling Smørgrav 	vp = ap->a_vp;
55869d94f4cSDag-Erling Smørgrav 
55969d94f4cSDag-Erling Smørgrav 	MPASS(uiop->uio_offset == 0);
56069d94f4cSDag-Erling Smørgrav 	MPASS(vp->v_type == VLNK);
56169d94f4cSDag-Erling Smørgrav 
56269d94f4cSDag-Erling Smørgrav 	tnp = VP_TO_TARFS_NODE(vp);
56369d94f4cSDag-Erling Smørgrav 
56469d94f4cSDag-Erling Smørgrav 	TARFS_DPF(VNODE, "%s(%p=%s)\n", __func__,
56569d94f4cSDag-Erling Smørgrav 	    tnp, tnp->name);
56669d94f4cSDag-Erling Smørgrav 
56769d94f4cSDag-Erling Smørgrav 	error = uiomove(tnp->link.name,
56869d94f4cSDag-Erling Smørgrav 	    MIN(tnp->size, uiop->uio_resid), uiop);
56969d94f4cSDag-Erling Smørgrav 
57069d94f4cSDag-Erling Smørgrav 	return (error);
57169d94f4cSDag-Erling Smørgrav }
57269d94f4cSDag-Erling Smørgrav 
57369d94f4cSDag-Erling Smørgrav static int
tarfs_reclaim(struct vop_reclaim_args * ap)57469d94f4cSDag-Erling Smørgrav tarfs_reclaim(struct vop_reclaim_args *ap)
57569d94f4cSDag-Erling Smørgrav {
57669d94f4cSDag-Erling Smørgrav 	struct tarfs_node *tnp;
57769d94f4cSDag-Erling Smørgrav 	struct vnode *vp;
57869d94f4cSDag-Erling Smørgrav 
57969d94f4cSDag-Erling Smørgrav 	vp = ap->a_vp;
58069d94f4cSDag-Erling Smørgrav 	tnp = VP_TO_TARFS_NODE(vp);
58169d94f4cSDag-Erling Smørgrav 
58269d94f4cSDag-Erling Smørgrav 	vfs_hash_remove(vp);
58369d94f4cSDag-Erling Smørgrav 
58469d94f4cSDag-Erling Smørgrav 	TARFS_NODE_LOCK(tnp);
58569d94f4cSDag-Erling Smørgrav 	tnp->vnode = NULLVP;
58669d94f4cSDag-Erling Smørgrav 	vp->v_data = NULL;
58769d94f4cSDag-Erling Smørgrav 	TARFS_NODE_UNLOCK(tnp);
58869d94f4cSDag-Erling Smørgrav 
58969d94f4cSDag-Erling Smørgrav 	return (0);
59069d94f4cSDag-Erling Smørgrav }
59169d94f4cSDag-Erling Smørgrav 
59269d94f4cSDag-Erling Smørgrav static int
tarfs_print(struct vop_print_args * ap)59369d94f4cSDag-Erling Smørgrav tarfs_print(struct vop_print_args *ap)
59469d94f4cSDag-Erling Smørgrav {
59569d94f4cSDag-Erling Smørgrav 	struct tarfs_node *tnp;
59669d94f4cSDag-Erling Smørgrav 	struct vnode *vp;
59769d94f4cSDag-Erling Smørgrav 
59869d94f4cSDag-Erling Smørgrav 	vp = ap->a_vp;
59969d94f4cSDag-Erling Smørgrav 	tnp = VP_TO_TARFS_NODE(vp);
60069d94f4cSDag-Erling Smørgrav 
60169d94f4cSDag-Erling Smørgrav 	printf("tag tarfs, tarfs_node %p, links %lu\n",
602fb53e7adSDag-Erling Smørgrav 	    tnp, (unsigned long)tnp->nlink);
60369d94f4cSDag-Erling Smørgrav 	printf("\tmode 0%o, owner %d, group %d, size %zd\n",
60469d94f4cSDag-Erling Smørgrav 	    tnp->mode, tnp->uid, tnp->gid,
60569d94f4cSDag-Erling Smørgrav 	    tnp->size);
60669d94f4cSDag-Erling Smørgrav 
60769d94f4cSDag-Erling Smørgrav 	if (vp->v_type == VFIFO)
60869d94f4cSDag-Erling Smørgrav 		fifo_printinfo(vp);
60969d94f4cSDag-Erling Smørgrav 
61069d94f4cSDag-Erling Smørgrav 	printf("\n");
61169d94f4cSDag-Erling Smørgrav 
61269d94f4cSDag-Erling Smørgrav 	return (0);
61369d94f4cSDag-Erling Smørgrav }
61469d94f4cSDag-Erling Smørgrav 
61569d94f4cSDag-Erling Smørgrav static int
tarfs_strategy(struct vop_strategy_args * ap)61669d94f4cSDag-Erling Smørgrav tarfs_strategy(struct vop_strategy_args *ap)
61769d94f4cSDag-Erling Smørgrav {
61869d94f4cSDag-Erling Smørgrav 	struct uio auio;
61969d94f4cSDag-Erling Smørgrav 	struct iovec iov;
62069d94f4cSDag-Erling Smørgrav 	struct tarfs_node *tnp;
62169d94f4cSDag-Erling Smørgrav 	struct buf *bp;
62269d94f4cSDag-Erling Smørgrav 	off_t off;
62369d94f4cSDag-Erling Smørgrav 	size_t len;
62469d94f4cSDag-Erling Smørgrav 	int error;
62569d94f4cSDag-Erling Smørgrav 
62669d94f4cSDag-Erling Smørgrav 	tnp = VP_TO_TARFS_NODE(ap->a_vp);
62769d94f4cSDag-Erling Smørgrav 	bp = ap->a_bp;
62869d94f4cSDag-Erling Smørgrav 	MPASS(bp->b_iocmd == BIO_READ);
62969d94f4cSDag-Erling Smørgrav 	MPASS(bp->b_iooffset >= 0);
63069d94f4cSDag-Erling Smørgrav 	MPASS(bp->b_bcount > 0);
63169d94f4cSDag-Erling Smørgrav 	MPASS(bp->b_bufsize >= bp->b_bcount);
63269d94f4cSDag-Erling Smørgrav 	TARFS_DPF(VNODE, "%s(%p=%s, %zu, %ld/%ld)\n", __func__, tnp,
63369d94f4cSDag-Erling Smørgrav 	    tnp->name, (size_t)bp->b_iooffset, bp->b_bcount, bp->b_bufsize);
63469d94f4cSDag-Erling Smørgrav 	iov.iov_base = bp->b_data;
63569d94f4cSDag-Erling Smørgrav 	iov.iov_len = bp->b_bcount;
63669d94f4cSDag-Erling Smørgrav 	off = bp->b_iooffset;
63769d94f4cSDag-Erling Smørgrav 	len = bp->b_bcount;
63869d94f4cSDag-Erling Smørgrav 	bp->b_resid = len;
63969d94f4cSDag-Erling Smørgrav 	if (off > tnp->size) {
64069d94f4cSDag-Erling Smørgrav 		/* XXX read beyond EOF - figure out correct handling */
64169d94f4cSDag-Erling Smørgrav 		error = EIO;
64269d94f4cSDag-Erling Smørgrav 		goto out;
64369d94f4cSDag-Erling Smørgrav 	}
64469d94f4cSDag-Erling Smørgrav 	if (off + len > tnp->size) {
64569d94f4cSDag-Erling Smørgrav 		/* clip to file length */
64669d94f4cSDag-Erling Smørgrav 		len = tnp->size - off;
64769d94f4cSDag-Erling Smørgrav 	}
64869d94f4cSDag-Erling Smørgrav 	auio.uio_iov = &iov;
64969d94f4cSDag-Erling Smørgrav 	auio.uio_iovcnt = 1;
65069d94f4cSDag-Erling Smørgrav 	auio.uio_offset = off;
65169d94f4cSDag-Erling Smørgrav 	auio.uio_resid = len;
65269d94f4cSDag-Erling Smørgrav 	auio.uio_segflg = UIO_SYSSPACE;
65369d94f4cSDag-Erling Smørgrav 	auio.uio_rw = UIO_READ;
65469d94f4cSDag-Erling Smørgrav 	auio.uio_td = curthread;
65569d94f4cSDag-Erling Smørgrav 	error = tarfs_read_file(tnp, len, &auio);
65669d94f4cSDag-Erling Smørgrav 	bp->b_resid -= len - auio.uio_resid;
65769d94f4cSDag-Erling Smørgrav out:
65869d94f4cSDag-Erling Smørgrav 	if (error != 0) {
65969d94f4cSDag-Erling Smørgrav 		bp->b_ioflags |= BIO_ERROR;
66069d94f4cSDag-Erling Smørgrav 		bp->b_error = error;
66169d94f4cSDag-Erling Smørgrav 	}
66269d94f4cSDag-Erling Smørgrav 	bp->b_flags |= B_DONE;
66369d94f4cSDag-Erling Smørgrav 	return (0);
66469d94f4cSDag-Erling Smørgrav }
66569d94f4cSDag-Erling Smørgrav 
66669d94f4cSDag-Erling Smørgrav static int
tarfs_vptofh(struct vop_vptofh_args * ap)66769d94f4cSDag-Erling Smørgrav tarfs_vptofh(struct vop_vptofh_args *ap)
66869d94f4cSDag-Erling Smørgrav {
66969d94f4cSDag-Erling Smørgrav 	struct tarfs_fid *tfp;
67069d94f4cSDag-Erling Smørgrav 	struct tarfs_node *tnp;
67169d94f4cSDag-Erling Smørgrav 
67269d94f4cSDag-Erling Smørgrav 	tfp = (struct tarfs_fid *)ap->a_fhp;
67369d94f4cSDag-Erling Smørgrav 	tnp = VP_TO_TARFS_NODE(ap->a_vp);
67469d94f4cSDag-Erling Smørgrav 
67569d94f4cSDag-Erling Smørgrav 	tfp->len = sizeof(struct tarfs_fid);
67669d94f4cSDag-Erling Smørgrav 	tfp->ino = tnp->ino;
67769d94f4cSDag-Erling Smørgrav 	tfp->gen = tnp->gen;
67869d94f4cSDag-Erling Smørgrav 
67969d94f4cSDag-Erling Smørgrav 	return (0);
68069d94f4cSDag-Erling Smørgrav }
68169d94f4cSDag-Erling Smørgrav 
68269d94f4cSDag-Erling Smørgrav struct vop_vector tarfs_vnodeops = {
68369d94f4cSDag-Erling Smørgrav 	.vop_default =		&default_vnodeops,
68469d94f4cSDag-Erling Smørgrav 
68569d94f4cSDag-Erling Smørgrav 	.vop_access =		tarfs_access,
686a0895e39SMark Johnston 	.vop_bmap =		tarfs_bmap,
68769d94f4cSDag-Erling Smørgrav 	.vop_cachedlookup =	tarfs_lookup,
68869d94f4cSDag-Erling Smørgrav 	.vop_close =		tarfs_close,
68969d94f4cSDag-Erling Smørgrav 	.vop_getattr =		tarfs_getattr,
69069d94f4cSDag-Erling Smørgrav 	.vop_lookup =		vfs_cache_lookup,
69169d94f4cSDag-Erling Smørgrav 	.vop_open =		tarfs_open,
69269d94f4cSDag-Erling Smørgrav 	.vop_print =		tarfs_print,
69369d94f4cSDag-Erling Smørgrav 	.vop_read =		tarfs_read,
69469d94f4cSDag-Erling Smørgrav 	.vop_readdir =		tarfs_readdir,
69569d94f4cSDag-Erling Smørgrav 	.vop_readlink =		tarfs_readlink,
69669d94f4cSDag-Erling Smørgrav 	.vop_reclaim =		tarfs_reclaim,
69769d94f4cSDag-Erling Smørgrav 	.vop_strategy =		tarfs_strategy,
69869d94f4cSDag-Erling Smørgrav 	.vop_vptofh =		tarfs_vptofh,
69969d94f4cSDag-Erling Smørgrav };
70069d94f4cSDag-Erling Smørgrav VFS_VOP_VECTOR_REGISTER(tarfs_vnodeops);
701