1*9b69ffe4Sriastradh /* $NetBSD: nfs_srvsubs.c,v 1.17 2023/03/23 19:52:42 riastradh Exp $ */
292ce8c6aSad
392ce8c6aSad /*
492ce8c6aSad * Copyright (c) 1989, 1993
592ce8c6aSad * The Regents of the University of California. All rights reserved.
692ce8c6aSad *
792ce8c6aSad * This code is derived from software contributed to Berkeley by
892ce8c6aSad * Rick Macklem at The University of Guelph.
992ce8c6aSad *
1092ce8c6aSad * Redistribution and use in source and binary forms, with or without
1192ce8c6aSad * modification, are permitted provided that the following conditions
1292ce8c6aSad * are met:
1392ce8c6aSad * 1. Redistributions of source code must retain the above copyright
1492ce8c6aSad * notice, this list of conditions and the following disclaimer.
1592ce8c6aSad * 2. Redistributions in binary form must reproduce the above copyright
1692ce8c6aSad * notice, this list of conditions and the following disclaimer in the
1792ce8c6aSad * documentation and/or other materials provided with the distribution.
1892ce8c6aSad * 3. Neither the name of the University nor the names of its contributors
1992ce8c6aSad * may be used to endorse or promote products derived from this software
2092ce8c6aSad * without specific prior written permission.
2192ce8c6aSad *
2292ce8c6aSad * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2392ce8c6aSad * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2492ce8c6aSad * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2592ce8c6aSad * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2692ce8c6aSad * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2792ce8c6aSad * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2892ce8c6aSad * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2992ce8c6aSad * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3092ce8c6aSad * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3192ce8c6aSad * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3292ce8c6aSad * SUCH DAMAGE.
3392ce8c6aSad *
3492ce8c6aSad * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95
3592ce8c6aSad */
3692ce8c6aSad
3792ce8c6aSad /*
3892ce8c6aSad * Copyright 2000 Wasabi Systems, Inc.
3992ce8c6aSad * All rights reserved.
4092ce8c6aSad *
4192ce8c6aSad * Written by Frank van der Linden for Wasabi Systems, Inc.
4292ce8c6aSad *
4392ce8c6aSad * Redistribution and use in source and binary forms, with or without
4492ce8c6aSad * modification, are permitted provided that the following conditions
4592ce8c6aSad * are met:
4692ce8c6aSad * 1. Redistributions of source code must retain the above copyright
4792ce8c6aSad * notice, this list of conditions and the following disclaimer.
4892ce8c6aSad * 2. Redistributions in binary form must reproduce the above copyright
4992ce8c6aSad * notice, this list of conditions and the following disclaimer in the
5092ce8c6aSad * documentation and/or other materials provided with the distribution.
5192ce8c6aSad * 3. All advertising materials mentioning features or use of this software
5292ce8c6aSad * must display the following acknowledgement:
5392ce8c6aSad * This product includes software developed for the NetBSD Project by
5492ce8c6aSad * Wasabi Systems, Inc.
5592ce8c6aSad * 4. The name of Wasabi Systems, Inc. may not be used to endorse
5692ce8c6aSad * or promote products derived from this software without specific prior
5792ce8c6aSad * written permission.
5892ce8c6aSad *
5992ce8c6aSad * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
6092ce8c6aSad * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
6192ce8c6aSad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
6292ce8c6aSad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
6392ce8c6aSad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
6492ce8c6aSad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
6592ce8c6aSad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
6692ce8c6aSad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
6792ce8c6aSad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
6892ce8c6aSad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
6992ce8c6aSad * POSSIBILITY OF SUCH DAMAGE.
7092ce8c6aSad */
7192ce8c6aSad
7292ce8c6aSad #include <sys/cdefs.h>
73*9b69ffe4Sriastradh __KERNEL_RCSID(0, "$NetBSD: nfs_srvsubs.c,v 1.17 2023/03/23 19:52:42 riastradh Exp $");
7492ce8c6aSad
7592ce8c6aSad #include <sys/param.h>
7692ce8c6aSad #include <sys/proc.h>
7792ce8c6aSad #include <sys/systm.h>
7892ce8c6aSad #include <sys/kernel.h>
7992ce8c6aSad #include <sys/kmem.h>
8092ce8c6aSad #include <sys/mount.h>
8192ce8c6aSad #include <sys/vnode.h>
8292ce8c6aSad #include <sys/namei.h>
8392ce8c6aSad #include <sys/mbuf.h>
8492ce8c6aSad #include <sys/socket.h>
8592ce8c6aSad #include <sys/stat.h>
8692ce8c6aSad #include <sys/filedesc.h>
8792ce8c6aSad #include <sys/time.h>
8892ce8c6aSad #include <sys/dirent.h>
8992ce8c6aSad #include <sys/once.h>
9092ce8c6aSad #include <sys/kauth.h>
9192ce8c6aSad #include <sys/atomic.h>
9292ce8c6aSad
9392ce8c6aSad #include <uvm/uvm_extern.h>
9492ce8c6aSad
9592ce8c6aSad #include <nfs/rpcv2.h>
9692ce8c6aSad #include <nfs/nfsproto.h>
9792ce8c6aSad #include <nfs/nfsnode.h>
9892ce8c6aSad #include <nfs/nfs.h>
9992ce8c6aSad #include <nfs/xdr_subs.h>
10092ce8c6aSad #include <nfs/nfsm_subs.h>
10192ce8c6aSad #include <nfs/nfsmount.h>
10292ce8c6aSad #include <nfs/nfsrtt.h>
10392ce8c6aSad #include <nfs/nfs_var.h>
10492ce8c6aSad
10592ce8c6aSad #include <miscfs/specfs/specdev.h>
10692ce8c6aSad
10792ce8c6aSad #include <netinet/in.h>
10892ce8c6aSad
10992ce8c6aSad /*
11092ce8c6aSad * Set up nameidata for a lookup() call and do it.
11192ce8c6aSad *
11292ce8c6aSad * If pubflag is set, this call is done for a lookup operation on the
11392ce8c6aSad * public filehandle. In that case we allow crossing mountpoints and
11492ce8c6aSad * absolute pathnames. However, the caller is expected to check that
11592ce8c6aSad * the lookup result is within the public fs, and deny access if
11692ce8c6aSad * it is not.
11792ce8c6aSad */
11892ce8c6aSad int
nfs_namei(struct nameidata * ndp,nfsrvfh_t * nsfh,uint32_t len,struct nfssvc_sock * slp,struct mbuf * nam,struct mbuf ** mdp,char ** dposp,struct vnode ** retdirp,int * dirattr_retp,struct vattr * dirattrp,struct lwp * l,int kerbflag,int pubflag)1195f179135Shannken nfs_namei(struct nameidata *ndp, nfsrvfh_t *nsfh, uint32_t len, struct nfssvc_sock *slp, struct mbuf *nam, struct mbuf **mdp, char **dposp, struct vnode **retdirp, int *dirattr_retp, struct vattr *dirattrp, struct lwp *l, int kerbflag, int pubflag)
12092ce8c6aSad {
12192ce8c6aSad int i, rem;
12292ce8c6aSad struct mbuf *md;
123d4eb0539Sdholland char *fromcp, *tocp, *cp, *path;
12492ce8c6aSad struct vnode *dp;
1258d360572Sdholland int error, rdonly;
1268d360572Sdholland int neverfollow;
12792ce8c6aSad struct componentname *cnp = &ndp->ni_cnd;
12892ce8c6aSad
12992ce8c6aSad *retdirp = NULL;
130d4eb0539Sdholland ndp->ni_pathbuf = NULL;
13192ce8c6aSad
132*9b69ffe4Sriastradh if (len > NFS_MAXPATHLEN - 1)
13392ce8c6aSad return (ENAMETOOLONG);
13492ce8c6aSad if (len == 0)
13592ce8c6aSad return (EACCES);
13692ce8c6aSad
13792ce8c6aSad /*
138d4eb0539Sdholland * Copy the name from the mbuf list to ndp->ni_pathbuf
13992ce8c6aSad * and set the various ndp fields appropriately.
14092ce8c6aSad */
141d4eb0539Sdholland path = PNBUF_GET();
14292ce8c6aSad fromcp = *dposp;
143d4eb0539Sdholland tocp = path;
14492ce8c6aSad md = *mdp;
14592ce8c6aSad rem = mtod(md, char *) + md->m_len - fromcp;
14692ce8c6aSad for (i = 0; i < len; i++) {
14792ce8c6aSad while (rem == 0) {
14892ce8c6aSad md = md->m_next;
14992ce8c6aSad if (md == NULL) {
15092ce8c6aSad error = EBADRPC;
15192ce8c6aSad goto out;
15292ce8c6aSad }
15392ce8c6aSad fromcp = mtod(md, void *);
15492ce8c6aSad rem = md->m_len;
15592ce8c6aSad }
15692ce8c6aSad if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
15792ce8c6aSad error = EACCES;
15892ce8c6aSad goto out;
15992ce8c6aSad }
16092ce8c6aSad *tocp++ = *fromcp++;
16192ce8c6aSad rem--;
16292ce8c6aSad }
16392ce8c6aSad *tocp = '\0';
16492ce8c6aSad *mdp = md;
16592ce8c6aSad *dposp = fromcp;
16692ce8c6aSad len = nfsm_rndup(len)-len;
16792ce8c6aSad if (len > 0) {
16892ce8c6aSad if (rem >= len)
16992ce8c6aSad *dposp += len;
17092ce8c6aSad else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
17192ce8c6aSad goto out;
17292ce8c6aSad }
17392ce8c6aSad
17492ce8c6aSad /*
17592ce8c6aSad * Extract and set starting directory.
17692ce8c6aSad */
17792ce8c6aSad error = nfsrv_fhtovp(nsfh, false, &dp, ndp->ni_cnd.cn_cred, slp,
17892ce8c6aSad nam, &rdonly, kerbflag, pubflag);
17992ce8c6aSad if (error)
18092ce8c6aSad goto out;
18192ce8c6aSad if (dp->v_type != VDIR) {
18292ce8c6aSad vrele(dp);
18392ce8c6aSad error = ENOTDIR;
18492ce8c6aSad goto out;
18592ce8c6aSad }
18692ce8c6aSad
18792ce8c6aSad if (rdonly)
18892ce8c6aSad cnp->cn_flags |= RDONLY;
18992ce8c6aSad
19092ce8c6aSad *retdirp = dp;
1915f179135Shannken if (dirattr_retp != NULL) {
1925f179135Shannken vn_lock(dp, LK_SHARED | LK_RETRY);
1935f179135Shannken *dirattr_retp = VOP_GETATTR(dp, dirattrp, ndp->ni_cnd.cn_cred);
1945f179135Shannken VOP_UNLOCK(dp);
1955f179135Shannken }
19692ce8c6aSad
19792ce8c6aSad if (pubflag) {
19892ce8c6aSad /*
19992ce8c6aSad * Oh joy. For WebNFS, handle those pesky '%' escapes,
20092ce8c6aSad * and the 'native path' indicator.
20192ce8c6aSad */
20292ce8c6aSad cp = PNBUF_GET();
203d4eb0539Sdholland fromcp = path;
20492ce8c6aSad tocp = cp;
20592ce8c6aSad if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
20692ce8c6aSad switch ((unsigned char)*fromcp) {
20792ce8c6aSad case WEBNFS_NATIVE_CHAR:
20892ce8c6aSad /*
20992ce8c6aSad * 'Native' path for us is the same
21092ce8c6aSad * as a path according to the NFS spec,
21192ce8c6aSad * just skip the escape char.
21292ce8c6aSad */
21392ce8c6aSad fromcp++;
21492ce8c6aSad break;
21592ce8c6aSad /*
21692ce8c6aSad * More may be added in the future, range 0x80-0xff
21792ce8c6aSad */
21892ce8c6aSad default:
21992ce8c6aSad error = EIO;
22092ce8c6aSad vrele(dp);
22192ce8c6aSad PNBUF_PUT(cp);
22292ce8c6aSad goto out;
22392ce8c6aSad }
22492ce8c6aSad }
22592ce8c6aSad /*
22692ce8c6aSad * Translate the '%' escapes, URL-style.
22792ce8c6aSad */
22892ce8c6aSad while (*fromcp != '\0') {
22992ce8c6aSad if (*fromcp == WEBNFS_ESC_CHAR) {
23092ce8c6aSad if (fromcp[1] != '\0' && fromcp[2] != '\0') {
23192ce8c6aSad fromcp++;
23292ce8c6aSad *tocp++ = HEXSTRTOI(fromcp);
23392ce8c6aSad fromcp += 2;
23492ce8c6aSad continue;
23592ce8c6aSad } else {
23692ce8c6aSad error = ENOENT;
23792ce8c6aSad vrele(dp);
23892ce8c6aSad PNBUF_PUT(cp);
23992ce8c6aSad goto out;
24092ce8c6aSad }
24192ce8c6aSad } else
24292ce8c6aSad *tocp++ = *fromcp++;
24392ce8c6aSad }
24492ce8c6aSad *tocp = '\0';
245d4eb0539Sdholland PNBUF_PUT(path);
246d4eb0539Sdholland path = cp;
24792ce8c6aSad }
24892ce8c6aSad
249b496a9dcSdholland ndp->ni_atdir = NULL;
250d4eb0539Sdholland ndp->ni_pathbuf = pathbuf_assimilate(path);
251d4eb0539Sdholland if (ndp->ni_pathbuf == NULL) {
252d4eb0539Sdholland error = ENOMEM;
253d4eb0539Sdholland goto out;
254d4eb0539Sdholland }
25592ce8c6aSad
25692ce8c6aSad if (pubflag) {
257d4eb0539Sdholland if (path[0] == '/')
25892ce8c6aSad dp = rootvnode;
25992ce8c6aSad } else {
26092ce8c6aSad cnp->cn_flags |= NOCROSSMOUNT;
26192ce8c6aSad }
26292ce8c6aSad
2638d360572Sdholland neverfollow = !pubflag;
26492ce8c6aSad
26592ce8c6aSad /*
26692ce8c6aSad * And call lookup() to do the real work
267d4eb0539Sdholland *
268ce8c87efSdholland * Note: ndp->ni_pathbuf is left undestroyed on success;
269ce8c87efSdholland * caller must clean it up.
27092ce8c6aSad */
2718d360572Sdholland error = lookup_for_nfsd(ndp, dp, neverfollow);
27292ce8c6aSad if (error) {
273ce8c87efSdholland goto out;
27492ce8c6aSad }
2758d360572Sdholland return 0;
27692ce8c6aSad
27792ce8c6aSad out:
278d4eb0539Sdholland if (ndp->ni_pathbuf != NULL) {
279d4eb0539Sdholland pathbuf_destroy(ndp->ni_pathbuf);
2804a414f41Sdholland ndp->ni_pathbuf = NULL;
281d4eb0539Sdholland } else {
282d4eb0539Sdholland PNBUF_PUT(path);
283d4eb0539Sdholland }
28492ce8c6aSad return (error);
28592ce8c6aSad }
28692ce8c6aSad
28792ce8c6aSad /*
28892ce8c6aSad * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
28992ce8c6aSad * - look up fsid in mount list (if not found ret error)
29092ce8c6aSad * - get vp and export rights by calling VFS_FHTOVP()
29192ce8c6aSad * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
29292ce8c6aSad * - if not lockflag unlock it with VOP_UNLOCK()
29392ce8c6aSad */
29492ce8c6aSad int
nfsrv_fhtovp(nfsrvfh_t * nsfh,int lockflag,struct vnode ** vpp,kauth_cred_t cred,struct nfssvc_sock * slp,struct mbuf * nam,int * rdonlyp,int kerbflag,int pubflag)29592ce8c6aSad nfsrv_fhtovp(nfsrvfh_t *nsfh, int lockflag, struct vnode **vpp,
29692ce8c6aSad kauth_cred_t cred, struct nfssvc_sock *slp, struct mbuf *nam, int *rdonlyp,
29792ce8c6aSad int kerbflag, int pubflag)
29892ce8c6aSad {
29992ce8c6aSad struct mount *mp;
30092ce8c6aSad kauth_cred_t credanon;
30192ce8c6aSad int error, exflags;
30292ce8c6aSad struct sockaddr_in *saddr;
30392ce8c6aSad fhandle_t *fhp;
30492ce8c6aSad
30592ce8c6aSad fhp = NFSRVFH_FHANDLE(nsfh);
30692ce8c6aSad *vpp = (struct vnode *)0;
30792ce8c6aSad
30892ce8c6aSad if (nfs_ispublicfh(nsfh)) {
30992ce8c6aSad if (!pubflag || !nfs_pub.np_valid)
31092ce8c6aSad return (ESTALE);
31192ce8c6aSad fhp = nfs_pub.np_handle;
31292ce8c6aSad }
31392ce8c6aSad
31492ce8c6aSad error = netexport_check(&fhp->fh_fsid, nam, &mp, &exflags, &credanon);
31592ce8c6aSad if (error) {
31692ce8c6aSad return error;
31792ce8c6aSad }
31892ce8c6aSad
319c2e9cb94Sad error = VFS_FHTOVP(mp, &fhp->fh_fid, LK_EXCLUSIVE, vpp);
32092ce8c6aSad if (error)
32192ce8c6aSad return (error);
32292ce8c6aSad
32392ce8c6aSad if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
32492ce8c6aSad saddr = mtod(nam, struct sockaddr_in *);
32592ce8c6aSad if ((saddr->sin_family == AF_INET) &&
32692ce8c6aSad ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
32792ce8c6aSad vput(*vpp);
32892ce8c6aSad return (NFSERR_AUTHERR | AUTH_TOOWEAK);
32992ce8c6aSad }
33092ce8c6aSad if ((saddr->sin_family == AF_INET6) &&
33192ce8c6aSad ntohs(saddr->sin_port) >= IPV6PORT_RESERVED) {
33292ce8c6aSad vput(*vpp);
33392ce8c6aSad return (NFSERR_AUTHERR | AUTH_TOOWEAK);
33492ce8c6aSad }
33592ce8c6aSad }
33692ce8c6aSad /*
33792ce8c6aSad * Check/setup credentials.
33892ce8c6aSad */
33992ce8c6aSad if (exflags & MNT_EXKERB) {
34092ce8c6aSad if (!kerbflag) {
34192ce8c6aSad vput(*vpp);
34292ce8c6aSad return (NFSERR_AUTHERR | AUTH_TOOWEAK);
34392ce8c6aSad }
34492ce8c6aSad } else if (kerbflag) {
34592ce8c6aSad vput(*vpp);
34692ce8c6aSad return (NFSERR_AUTHERR | AUTH_TOOWEAK);
34792ce8c6aSad } else if (kauth_cred_geteuid(cred) == 0 || /* NFS maproot, see below */
34892ce8c6aSad (exflags & MNT_EXPORTANON)) {
34992ce8c6aSad /*
35092ce8c6aSad * This is used by the NFS maproot option. While we can change
35192ce8c6aSad * the secmodel on our own host, we can't change it on the
35292ce8c6aSad * clients. As means of least surprise, we're doing the
35392ce8c6aSad * traditional thing here.
35492ce8c6aSad * Should look into adding a "mapprivileged" or similar where
35592ce8c6aSad * the users can be explicitly specified...
35692ce8c6aSad * [elad, yamt 2008-03-05]
35792ce8c6aSad */
35892ce8c6aSad kauth_cred_clone(credanon, cred);
35992ce8c6aSad }
36092ce8c6aSad if (exflags & MNT_EXRDONLY)
36192ce8c6aSad *rdonlyp = 1;
36292ce8c6aSad else
36392ce8c6aSad *rdonlyp = 0;
36492ce8c6aSad if (!lockflag)
3651423e65bShannken VOP_UNLOCK(*vpp);
36692ce8c6aSad return (0);
36792ce8c6aSad }
36892ce8c6aSad
36992ce8c6aSad /*
37092ce8c6aSad * WebNFS: check if a filehandle is a public filehandle. For v3, this
37192ce8c6aSad * means a length of 0, for v2 it means all zeroes.
37292ce8c6aSad */
37392ce8c6aSad int
nfs_ispublicfh(const nfsrvfh_t * nsfh)37492ce8c6aSad nfs_ispublicfh(const nfsrvfh_t *nsfh)
37592ce8c6aSad {
37692ce8c6aSad const char *cp = (const void *)(NFSRVFH_DATA(nsfh));
37792ce8c6aSad int i;
37892ce8c6aSad
37992ce8c6aSad if (NFSRVFH_SIZE(nsfh) == 0) {
38092ce8c6aSad return true;
38192ce8c6aSad }
38292ce8c6aSad if (NFSRVFH_SIZE(nsfh) != NFSX_V2FH) {
38392ce8c6aSad return false;
38492ce8c6aSad }
38592ce8c6aSad for (i = 0; i < NFSX_V2FH; i++)
38692ce8c6aSad if (*cp++ != 0)
38792ce8c6aSad return false;
38892ce8c6aSad return true;
38992ce8c6aSad }
39092ce8c6aSad
39192ce8c6aSad int
nfsrv_composefh(struct vnode * vp,nfsrvfh_t * nsfh,bool v3)39292ce8c6aSad nfsrv_composefh(struct vnode *vp, nfsrvfh_t *nsfh, bool v3)
39392ce8c6aSad {
39492ce8c6aSad int error;
39592ce8c6aSad size_t fhsize;
39692ce8c6aSad
39792ce8c6aSad fhsize = NFSD_MAXFHSIZE;
39892ce8c6aSad error = vfs_composefh(vp, (void *)NFSRVFH_DATA(nsfh), &fhsize);
39992ce8c6aSad if (NFSX_FHTOOBIG_P(fhsize, v3)) {
40092ce8c6aSad error = EOPNOTSUPP;
40192ce8c6aSad }
40292ce8c6aSad if (error != 0) {
40392ce8c6aSad return error;
40492ce8c6aSad }
40592ce8c6aSad if (!v3 && fhsize < NFSX_V2FH) {
40692ce8c6aSad memset((char *)NFSRVFH_DATA(nsfh) + fhsize, 0,
40792ce8c6aSad NFSX_V2FH - fhsize);
40892ce8c6aSad fhsize = NFSX_V2FH;
40992ce8c6aSad }
41092ce8c6aSad if ((fhsize % NFSX_UNSIGNED) != 0) {
41192ce8c6aSad return EOPNOTSUPP;
41292ce8c6aSad }
41392ce8c6aSad nsfh->nsfh_size = fhsize;
41492ce8c6aSad return 0;
41592ce8c6aSad }
41692ce8c6aSad
41792ce8c6aSad int
nfsrv_comparefh(const nfsrvfh_t * fh1,const nfsrvfh_t * fh2)41892ce8c6aSad nfsrv_comparefh(const nfsrvfh_t *fh1, const nfsrvfh_t *fh2)
41992ce8c6aSad {
42092ce8c6aSad
42192ce8c6aSad if (NFSRVFH_SIZE(fh1) != NFSRVFH_SIZE(fh2)) {
42292ce8c6aSad return NFSRVFH_SIZE(fh2) - NFSRVFH_SIZE(fh1);
42392ce8c6aSad }
42492ce8c6aSad return memcmp(NFSRVFH_DATA(fh1), NFSRVFH_DATA(fh2), NFSRVFH_SIZE(fh1));
42592ce8c6aSad }
42692ce8c6aSad
42792ce8c6aSad void
nfsrv_copyfh(nfsrvfh_t * fh1,const nfsrvfh_t * fh2)42892ce8c6aSad nfsrv_copyfh(nfsrvfh_t *fh1, const nfsrvfh_t *fh2)
42992ce8c6aSad {
43092ce8c6aSad size_t size;
43192ce8c6aSad
43292ce8c6aSad fh1->nsfh_size = size = NFSRVFH_SIZE(fh2);
43392ce8c6aSad memcpy(NFSRVFH_DATA(fh1), NFSRVFH_DATA(fh2), size);
43492ce8c6aSad }
435