The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/nfsserver/nfs_nfsdserv.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1989, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * This code is derived from software contributed to Berkeley by
    6  * Rick Macklem at The University of Guelph.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 4. Neither the name of the University nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD$");
   36 
   37 /*
   38  * nfs version 2, 3 and 4 server calls to vnode ops
   39  * - these routines generally have 3 phases
   40  *   1 - break down and validate rpc request in mbuf list
   41  *   2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
   42  *       function in nfsd_port.c
   43  *   3 - build the rpc reply in an mbuf list
   44  * For nfsv4, these functions are called for each Op within the Compound RPC.
   45  */
   46 
   47 #ifndef APPLEKEXT
   48 #include <fs/nfs/nfsport.h>
   49 
   50 /* Global vars */
   51 extern u_int32_t newnfs_false, newnfs_true;
   52 extern enum vtype nv34tov_type[8];
   53 extern struct timeval nfsboottime;
   54 extern int nfs_rootfhset;
   55 extern int nfsrv_enable_crossmntpt;
   56 #endif  /* !APPLEKEXT */
   57 
   58 static int      nfs_async = 0;
   59 SYSCTL_DECL(_vfs_nfsd);
   60 SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
   61     "Tell client that writes were synced even though they were not");
   62 
   63 /*
   64  * This list defines the GSS mechanisms supported.
   65  * (Don't ask me how you get these strings from the RFC stuff like
   66  *  iso(1), org(3)... but someone did it, so I don't need to know.)
   67  */
   68 static struct nfsgss_mechlist nfsgss_mechlist[] = {
   69         { 9, "\052\206\110\206\367\022\001\002\002", 11 },
   70         { 0, "", 0 },
   71 };
   72 
   73 /* local functions */
   74 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
   75     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
   76     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
   77     int *diraft_retp, nfsattrbit_t *attrbitp,
   78     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
   79     int pathlen);
   80 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
   81     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
   82     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
   83     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
   84     NFSPROC_T *p, struct nfsexstuff *exp);
   85 
   86 /*
   87  * nfs access service (not a part of NFS V2)
   88  */
   89 APPLESTATIC int
   90 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
   91     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
   92 {
   93         u_int32_t *tl;
   94         int getret, error = 0;
   95         struct nfsvattr nva;
   96         u_int32_t testmode, nfsmode, supported = 0;
   97         accmode_t deletebit;
   98 
   99         if (nd->nd_repstat) {
  100                 nfsrv_postopattr(nd, 1, &nva);
  101                 goto out;
  102         }
  103         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
  104         nfsmode = fxdr_unsigned(u_int32_t, *tl);
  105         if ((nd->nd_flag & ND_NFSV4) &&
  106             (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
  107              NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
  108              NFSACCESS_EXECUTE))) {
  109                 nd->nd_repstat = NFSERR_INVAL;
  110                 vput(vp);
  111                 goto out;
  112         }
  113         if (nfsmode & NFSACCESS_READ) {
  114                 supported |= NFSACCESS_READ;
  115                 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
  116                     NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
  117                         nfsmode &= ~NFSACCESS_READ;
  118         }
  119         if (nfsmode & NFSACCESS_MODIFY) {
  120                 supported |= NFSACCESS_MODIFY;
  121                 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
  122                     NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
  123                         nfsmode &= ~NFSACCESS_MODIFY;
  124         }
  125         if (nfsmode & NFSACCESS_EXTEND) {
  126                 supported |= NFSACCESS_EXTEND;
  127                 if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
  128                     NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
  129                         nfsmode &= ~NFSACCESS_EXTEND;
  130         }
  131         if (nfsmode & NFSACCESS_DELETE) {
  132                 supported |= NFSACCESS_DELETE;
  133                 if (vp->v_type == VDIR)
  134                         deletebit = VDELETE_CHILD;
  135                 else
  136                         deletebit = VDELETE;
  137                 if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
  138                     NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
  139                         nfsmode &= ~NFSACCESS_DELETE;
  140         }
  141         if (vnode_vtype(vp) == VDIR)
  142                 testmode = NFSACCESS_LOOKUP;
  143         else
  144                 testmode = NFSACCESS_EXECUTE;
  145         if (nfsmode & testmode) {
  146                 supported |= (nfsmode & testmode);
  147                 if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
  148                     NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
  149                         nfsmode &= ~testmode;
  150         }
  151         nfsmode &= supported;
  152         if (nd->nd_flag & ND_NFSV3) {
  153                 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
  154                 nfsrv_postopattr(nd, getret, &nva);
  155         }
  156         vput(vp);
  157         if (nd->nd_flag & ND_NFSV4) {
  158                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  159                 *tl++ = txdr_unsigned(supported);
  160         } else
  161                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  162         *tl = txdr_unsigned(nfsmode);
  163 
  164 out:
  165         NFSEXITCODE2(0, nd);
  166         return (0);
  167 nfsmout:
  168         vput(vp);
  169         NFSEXITCODE2(error, nd);
  170         return (error);
  171 }
  172 
  173 /*
  174  * nfs getattr service
  175  */
  176 APPLESTATIC int
  177 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
  178     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
  179 {
  180         struct nfsvattr nva;
  181         fhandle_t fh;
  182         int at_root = 0, error = 0, supports_nfsv4acls;
  183         struct nfsreferral *refp;
  184         nfsattrbit_t attrbits, tmpbits;
  185         struct mount *mp;
  186         struct vnode *tvp = NULL;
  187         struct vattr va;
  188         uint64_t mounted_on_fileno = 0;
  189         accmode_t accmode;
  190 
  191         if (nd->nd_repstat)
  192                 goto out;
  193         if (nd->nd_flag & ND_NFSV4) {
  194                 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
  195                 if (error) {
  196                         vput(vp);
  197                         goto out;
  198                 }
  199 
  200                 /*
  201                  * Check for a referral.
  202                  */
  203                 refp = nfsv4root_getreferral(vp, NULL, 0);
  204                 if (refp != NULL) {
  205                         (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
  206                             &nd->nd_repstat);
  207                         vput(vp);
  208                         goto out;
  209                 }
  210                 if (nd->nd_repstat == 0) {
  211                         accmode = 0;
  212                         NFSSET_ATTRBIT(&tmpbits, &attrbits);
  213                         if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
  214                                 NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
  215                                 accmode |= VREAD_ACL;
  216                         }
  217                         if (NFSNONZERO_ATTRBIT(&tmpbits))
  218                                 accmode |= VREAD_ATTRIBUTES;
  219                         if (accmode != 0)
  220                                 nd->nd_repstat = nfsvno_accchk(vp, accmode,
  221                                     nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
  222                                     NFSACCCHK_VPISLOCKED, NULL);
  223                 }
  224         }
  225         if (!nd->nd_repstat)
  226                 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
  227         if (!nd->nd_repstat) {
  228                 if (nd->nd_flag & ND_NFSV4) {
  229                         if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
  230                                 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
  231                         if (!nd->nd_repstat)
  232                                 nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
  233                                     &nva, &attrbits, nd->nd_cred, p);
  234                         if (nd->nd_repstat == 0) {
  235                                 supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
  236                                 mp = vp->v_mount;
  237                                 if (nfsrv_enable_crossmntpt != 0 &&
  238                                     vp->v_type == VDIR &&
  239                                     (vp->v_vflag & VV_ROOT) != 0 &&
  240                                     vp != rootvnode) {
  241                                         tvp = mp->mnt_vnodecovered;
  242                                         VREF(tvp);
  243                                         at_root = 1;
  244                                 } else
  245                                         at_root = 0;
  246                                 vfs_ref(mp);
  247                                 NFSVOPUNLOCK(vp, 0);
  248                                 if (at_root != 0) {
  249                                         if ((nd->nd_repstat =
  250                                              NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
  251                                                 nd->nd_repstat = VOP_GETATTR(
  252                                                     tvp, &va, nd->nd_cred);
  253                                                 vput(tvp);
  254                                         } else
  255                                                 vrele(tvp);
  256                                         if (nd->nd_repstat == 0)
  257                                                 mounted_on_fileno = (uint64_t)
  258                                                     va.va_fileid;
  259                                         else
  260                                                 at_root = 0;
  261                                 }
  262                                 if (nd->nd_repstat == 0)
  263                                         nd->nd_repstat = vfs_busy(mp, 0);
  264                                 vfs_rel(mp);
  265                                 if (nd->nd_repstat == 0) {
  266                                         (void)nfsvno_fillattr(nd, mp, vp, &nva,
  267                                             &fh, 0, &attrbits, nd->nd_cred, p,
  268                                             isdgram, 1, supports_nfsv4acls,
  269                                             at_root, mounted_on_fileno);
  270                                         vfs_unbusy(mp);
  271                                 }
  272                                 vrele(vp);
  273                         } else
  274                                 vput(vp);
  275                 } else {
  276                         nfsrv_fillattr(nd, &nva);
  277                         vput(vp);
  278                 }
  279         } else {
  280                 vput(vp);
  281         }
  282 
  283 out:
  284         NFSEXITCODE2(error, nd);
  285         return (error);
  286 }
  287 
  288 /*
  289  * nfs setattr service
  290  */
  291 APPLESTATIC int
  292 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
  293     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
  294 {
  295         struct nfsvattr nva, nva2;
  296         u_int32_t *tl;
  297         int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
  298         struct timespec guard = { 0, 0 };
  299         nfsattrbit_t attrbits, retbits;
  300         nfsv4stateid_t stateid;
  301         NFSACL_T *aclp = NULL;
  302 
  303         if (nd->nd_repstat) {
  304                 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
  305                 goto out;
  306         }
  307 #ifdef NFS4_ACL_EXTATTR_NAME
  308         aclp = acl_alloc(M_WAITOK);
  309         aclp->acl_cnt = 0;
  310 #endif
  311         NFSVNO_ATTRINIT(&nva);
  312         NFSZERO_ATTRBIT(&retbits);
  313         if (nd->nd_flag & ND_NFSV4) {
  314                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
  315                 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
  316                 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
  317         }
  318         error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
  319         if (error)
  320                 goto nfsmout;
  321         preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1);
  322         if (!nd->nd_repstat)
  323                 nd->nd_repstat = preat_ret;
  324         if (nd->nd_flag & ND_NFSV3) {
  325                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
  326                 gcheck = fxdr_unsigned(int, *tl);
  327                 if (gcheck) {
  328                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  329                         fxdr_nfsv3time(tl, &guard);
  330                 }
  331                 if (!nd->nd_repstat && gcheck &&
  332                     (nva2.na_ctime.tv_sec != guard.tv_sec ||
  333                      nva2.na_ctime.tv_nsec != guard.tv_nsec))
  334                         nd->nd_repstat = NFSERR_NOT_SYNC;
  335                 if (nd->nd_repstat) {
  336                         vput(vp);
  337 #ifdef NFS4_ACL_EXTATTR_NAME
  338                         acl_free(aclp);
  339 #endif
  340                         nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
  341                         goto out;
  342                 }
  343         } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
  344                 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
  345 
  346         /*
  347          * Now that we have all the fields, lets do it.
  348          * If the size is being changed write access is required, otherwise
  349          * just check for a read only file system.
  350          */
  351         if (!nd->nd_repstat) {
  352                 if (NFSVNO_NOTSETSIZE(&nva)) {
  353                         if (NFSVNO_EXRDONLY(exp) ||
  354                             (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
  355                                 nd->nd_repstat = EROFS;
  356                 } else {
  357                         if (vnode_vtype(vp) != VREG)
  358                                 nd->nd_repstat = EINVAL;
  359                         else if (nva2.na_uid != nd->nd_cred->cr_uid ||
  360                             NFSVNO_EXSTRICTACCESS(exp))
  361                                 nd->nd_repstat = nfsvno_accchk(vp,
  362                                     VWRITE, nd->nd_cred, exp, p,
  363                                     NFSACCCHK_NOOVERRIDE,
  364                                     NFSACCCHK_VPISLOCKED, NULL);
  365                 }
  366         }
  367         if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
  368                 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
  369                     &nva, &attrbits, exp, p);
  370 
  371         if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
  372             /*
  373              * For V4, try setting the attrbutes in sets, so that the
  374              * reply bitmap will be correct for an error case.
  375              */
  376             if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
  377                 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
  378                 NFSVNO_ATTRINIT(&nva2);
  379                 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
  380                 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
  381                 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
  382                     exp);
  383                 if (!nd->nd_repstat) {
  384                     if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
  385                         NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
  386                     if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
  387                         NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
  388                 }
  389             }
  390             if (!nd->nd_repstat &&
  391                 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
  392                 NFSVNO_ATTRINIT(&nva2);
  393                 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
  394                 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
  395                     exp);
  396                 if (!nd->nd_repstat)
  397                     NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
  398             }
  399             if (!nd->nd_repstat &&
  400                 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
  401                  NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
  402                 NFSVNO_ATTRINIT(&nva2);
  403                 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
  404                 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
  405                 if (nva.na_vaflags & VA_UTIMES_NULL) {
  406                         nva2.na_vaflags |= VA_UTIMES_NULL;
  407                         NFSVNO_SETACTIVE(&nva2, vaflags);
  408                 }
  409                 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
  410                     exp);
  411                 if (!nd->nd_repstat) {
  412                     if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
  413                         NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
  414                     if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
  415                         NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
  416                 }
  417             }
  418             if (!nd->nd_repstat &&
  419                 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) {
  420                 NFSVNO_ATTRINIT(&nva2);
  421                 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
  422                 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
  423                     exp);
  424                 if (!nd->nd_repstat)
  425                     NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
  426             }
  427 
  428 #ifdef NFS4_ACL_EXTATTR_NAME
  429             if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
  430                 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
  431                 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
  432                 if (!nd->nd_repstat) 
  433                     NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
  434             }
  435 #endif
  436         } else if (!nd->nd_repstat) {
  437                 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
  438                     exp);
  439         }
  440         if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
  441                 postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
  442                 if (!nd->nd_repstat)
  443                         nd->nd_repstat = postat_ret;
  444         }
  445         vput(vp);
  446 #ifdef NFS4_ACL_EXTATTR_NAME
  447         acl_free(aclp);
  448 #endif
  449         if (nd->nd_flag & ND_NFSV3)
  450                 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
  451         else if (nd->nd_flag & ND_NFSV4)
  452                 (void) nfsrv_putattrbit(nd, &retbits);
  453         else if (!nd->nd_repstat)
  454                 nfsrv_fillattr(nd, &nva);
  455 
  456 out:
  457         NFSEXITCODE2(0, nd);
  458         return (0);
  459 nfsmout:
  460         vput(vp);
  461 #ifdef NFS4_ACL_EXTATTR_NAME
  462         acl_free(aclp);
  463 #endif
  464         if (nd->nd_flag & ND_NFSV4) {
  465                 /*
  466                  * For all nd_repstat, the V4 reply includes a bitmap,
  467                  * even NFSERR_BADXDR, which is what this will end up
  468                  * returning.
  469                  */
  470                 (void) nfsrv_putattrbit(nd, &retbits);
  471         }
  472         NFSEXITCODE2(error, nd);
  473         return (error);
  474 }
  475 
  476 /*
  477  * nfs lookup rpc
  478  * (Also performs lookup parent for v4)
  479  */
  480 APPLESTATIC int
  481 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
  482     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
  483     struct nfsexstuff *exp)
  484 {
  485         struct nameidata named;
  486         vnode_t vp, dirp = NULL;
  487         int error = 0, dattr_ret = 1;
  488         struct nfsvattr nva, dattr;
  489         char *bufp;
  490         u_long *hashp;
  491 
  492         if (nd->nd_repstat) {
  493                 nfsrv_postopattr(nd, dattr_ret, &dattr);
  494                 goto out;
  495         }
  496 
  497         /*
  498          * For some reason, if dp is a symlink, the error
  499          * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
  500          */
  501         if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
  502                 nd->nd_repstat = NFSERR_SYMLINK;
  503                 vrele(dp);
  504                 goto out;
  505         }
  506 
  507         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
  508             LOCKLEAF | SAVESTART);
  509         nfsvno_setpathbuf(&named, &bufp, &hashp);
  510         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
  511         if (error) {
  512                 vrele(dp);
  513                 nfsvno_relpathbuf(&named);
  514                 goto out;
  515         }
  516         if (!nd->nd_repstat) {
  517                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
  518         } else {
  519                 vrele(dp);
  520                 nfsvno_relpathbuf(&named);
  521         }
  522         if (nd->nd_repstat) {
  523                 if (dirp) {
  524                         if (nd->nd_flag & ND_NFSV3)
  525                                 dattr_ret = nfsvno_getattr(dirp, &dattr,
  526                                     nd->nd_cred, p, 0);
  527                         vrele(dirp);
  528                 }
  529                 if (nd->nd_flag & ND_NFSV3)
  530                         nfsrv_postopattr(nd, dattr_ret, &dattr);
  531                 goto out;
  532         }
  533         if (named.ni_startdir)
  534                 vrele(named.ni_startdir);
  535         nfsvno_relpathbuf(&named);
  536         vp = named.ni_vp;
  537         if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
  538             vp->v_type != VDIR && vp->v_type != VLNK)
  539                 /*
  540                  * Only allow lookup of VDIR and VLNK for traversal of
  541                  * non-exported volumes during NFSv4 mounting.
  542                  */
  543                 nd->nd_repstat = ENOENT;
  544         if (nd->nd_repstat == 0)
  545                 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
  546         if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
  547                 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
  548         if (vpp != NULL && nd->nd_repstat == 0)
  549                 *vpp = vp;
  550         else
  551                 vput(vp);
  552         if (dirp) {
  553                 if (nd->nd_flag & ND_NFSV3)
  554                         dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred,
  555                             p, 0);
  556                 vrele(dirp);
  557         }
  558         if (nd->nd_repstat) {
  559                 if (nd->nd_flag & ND_NFSV3)
  560                         nfsrv_postopattr(nd, dattr_ret, &dattr);
  561                 goto out;
  562         }
  563         if (nd->nd_flag & ND_NFSV2) {
  564                 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
  565                 nfsrv_fillattr(nd, &nva);
  566         } else if (nd->nd_flag & ND_NFSV3) {
  567                 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
  568                 nfsrv_postopattr(nd, 0, &nva);
  569                 nfsrv_postopattr(nd, dattr_ret, &dattr);
  570         }
  571 
  572 out:
  573         NFSEXITCODE2(error, nd);
  574         return (error);
  575 }
  576 
  577 /*
  578  * nfs readlink service
  579  */
  580 APPLESTATIC int
  581 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
  582     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
  583 {
  584         u_int32_t *tl;
  585         mbuf_t mp = NULL, mpend = NULL;
  586         int getret = 1, len;
  587         struct nfsvattr nva;
  588 
  589         if (nd->nd_repstat) {
  590                 nfsrv_postopattr(nd, getret, &nva);
  591                 goto out;
  592         }
  593         if (vnode_vtype(vp) != VLNK) {
  594                 if (nd->nd_flag & ND_NFSV2)
  595                         nd->nd_repstat = ENXIO;
  596                 else
  597                         nd->nd_repstat = EINVAL;
  598         }
  599         if (!nd->nd_repstat)
  600                 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
  601                     &mp, &mpend, &len);
  602         if (nd->nd_flag & ND_NFSV3)
  603                 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
  604         vput(vp);
  605         if (nd->nd_flag & ND_NFSV3)
  606                 nfsrv_postopattr(nd, getret, &nva);
  607         if (nd->nd_repstat)
  608                 goto out;
  609         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  610         *tl = txdr_unsigned(len);
  611         mbuf_setnext(nd->nd_mb, mp);
  612         nd->nd_mb = mpend;
  613         nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
  614 
  615 out:
  616         NFSEXITCODE2(0, nd);
  617         return (0);
  618 }
  619 
  620 /*
  621  * nfs read service
  622  */
  623 APPLESTATIC int
  624 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
  625     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
  626 {
  627         u_int32_t *tl;
  628         int error = 0, cnt, getret = 1, reqlen, eof = 0;
  629         mbuf_t m2, m3;
  630         struct nfsvattr nva;
  631         off_t off = 0x0;
  632         struct nfsstate st, *stp = &st;
  633         struct nfslock lo, *lop = &lo;
  634         nfsv4stateid_t stateid;
  635         nfsquad_t clientid;
  636 
  637         if (nd->nd_repstat) {
  638                 nfsrv_postopattr(nd, getret, &nva);
  639                 goto out;
  640         }
  641         if (nd->nd_flag & ND_NFSV2) {
  642                 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  643                 off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
  644                 reqlen = fxdr_unsigned(int, *tl);
  645         } else if (nd->nd_flag & ND_NFSV3) {
  646                 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
  647                 off = fxdr_hyper(tl);
  648                 tl += 2;
  649                 reqlen = fxdr_unsigned(int, *tl);
  650         } else {
  651                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
  652                 reqlen = fxdr_unsigned(int, *(tl + 6));
  653         }
  654         if (reqlen > NFS_SRVMAXDATA(nd)) {
  655                 reqlen = NFS_SRVMAXDATA(nd);
  656         } else if (reqlen < 0) {
  657                 error = EBADRPC;
  658                 goto nfsmout;
  659         }
  660         if (nd->nd_flag & ND_NFSV4) {
  661                 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
  662                 lop->lo_flags = NFSLCK_READ;
  663                 stp->ls_ownerlen = 0;
  664                 stp->ls_op = NULL;
  665                 stp->ls_uid = nd->nd_cred->cr_uid;
  666                 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
  667                 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
  668                 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
  669                 if (nd->nd_flag & ND_IMPLIEDCLID) {
  670                         if (nd->nd_clientid.qval != clientid.qval)
  671                                 printf("EEK! multiple clids\n");
  672                 } else {
  673                         nd->nd_flag |= ND_IMPLIEDCLID;
  674                         nd->nd_clientid.qval = clientid.qval;
  675                 }
  676                 stp->ls_stateid.other[2] = *tl++;
  677                 off = fxdr_hyper(tl);
  678                 lop->lo_first = off;
  679                 tl += 2;
  680                 lop->lo_end = off + reqlen;
  681                 /*
  682                  * Paranoia, just in case it wraps around.
  683                  */
  684                 if (lop->lo_end < off)
  685                         lop->lo_end = NFS64BITSSET;
  686         }
  687         if (vnode_vtype(vp) != VREG) {
  688                 if (nd->nd_flag & ND_NFSV3)
  689                         nd->nd_repstat = EINVAL;
  690                 else
  691                         nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
  692                             EINVAL;
  693         }
  694         getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
  695         if (!nd->nd_repstat)
  696                 nd->nd_repstat = getret;
  697         if (!nd->nd_repstat &&
  698             (nva.na_uid != nd->nd_cred->cr_uid ||
  699              NFSVNO_EXSTRICTACCESS(exp))) {
  700                 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
  701                     nd->nd_cred, exp, p,
  702                     NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
  703                 if (nd->nd_repstat)
  704                         nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
  705                             nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
  706                             NFSACCCHK_VPISLOCKED, NULL);
  707         }
  708         if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
  709                 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
  710                     &stateid, exp, nd, p);
  711         if (nd->nd_repstat) {
  712                 vput(vp);
  713                 if (nd->nd_flag & ND_NFSV3)
  714                         nfsrv_postopattr(nd, getret, &nva);
  715                 goto out;
  716         }
  717         if (off >= nva.na_size) {
  718                 cnt = 0;
  719                 eof = 1;
  720         } else if (reqlen == 0)
  721                 cnt = 0;
  722         else if ((off + reqlen) >= nva.na_size) {
  723                 cnt = nva.na_size - off;
  724                 eof = 1;
  725         } else
  726                 cnt = reqlen;
  727         m3 = NULL;
  728         if (cnt > 0) {
  729                 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
  730                     &m3, &m2);
  731                 if (!(nd->nd_flag & ND_NFSV4)) {
  732                         getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
  733                         if (!nd->nd_repstat)
  734                                 nd->nd_repstat = getret;
  735                 }
  736                 if (nd->nd_repstat) {
  737                         vput(vp);
  738                         if (m3)
  739                                 mbuf_freem(m3);
  740                         if (nd->nd_flag & ND_NFSV3)
  741                                 nfsrv_postopattr(nd, getret, &nva);
  742                         goto out;
  743                 }
  744         }
  745         vput(vp);
  746         if (nd->nd_flag & ND_NFSV2) {
  747                 nfsrv_fillattr(nd, &nva);
  748                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  749         } else {
  750                 if (nd->nd_flag & ND_NFSV3) {
  751                         nfsrv_postopattr(nd, getret, &nva);
  752                         NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
  753                         *tl++ = txdr_unsigned(cnt);
  754                 } else
  755                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  756                 if (eof)
  757                         *tl++ = newnfs_true;
  758                 else
  759                         *tl++ = newnfs_false;
  760         }
  761         *tl = txdr_unsigned(cnt);
  762         if (m3) {
  763                 mbuf_setnext(nd->nd_mb, m3);
  764                 nd->nd_mb = m2;
  765                 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
  766         }
  767 
  768 out:
  769         NFSEXITCODE2(0, nd);
  770         return (0);
  771 nfsmout:
  772         vput(vp);
  773         NFSEXITCODE2(error, nd);
  774         return (error);
  775 }
  776 
  777 /*
  778  * nfs write service
  779  */
  780 APPLESTATIC int
  781 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
  782     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
  783 {
  784         int i, cnt;
  785         u_int32_t *tl;
  786         mbuf_t mp;
  787         struct nfsvattr nva, forat;
  788         int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
  789         int stable = NFSWRITE_FILESYNC;
  790         off_t off;
  791         struct nfsstate st, *stp = &st;
  792         struct nfslock lo, *lop = &lo;
  793         nfsv4stateid_t stateid;
  794         nfsquad_t clientid;
  795 
  796         if (nd->nd_repstat) {
  797                 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
  798                 goto out;
  799         }
  800         if (nd->nd_flag & ND_NFSV2) {
  801                 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
  802                 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
  803                 tl += 2;
  804                 retlen = len = fxdr_unsigned(int32_t, *tl);
  805         } else if (nd->nd_flag & ND_NFSV3) {
  806                 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
  807                 off = fxdr_hyper(tl);
  808                 tl += 3;
  809                 stable = fxdr_unsigned(int, *tl++);
  810                 retlen = len = fxdr_unsigned(int32_t, *tl);
  811         } else {
  812                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
  813                 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
  814                 lop->lo_flags = NFSLCK_WRITE;
  815                 stp->ls_ownerlen = 0;
  816                 stp->ls_op = NULL;
  817                 stp->ls_uid = nd->nd_cred->cr_uid;
  818                 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
  819                 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
  820                 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
  821                 if (nd->nd_flag & ND_IMPLIEDCLID) {
  822                         if (nd->nd_clientid.qval != clientid.qval)
  823                                 printf("EEK! multiple clids\n");
  824                 } else {
  825                         nd->nd_flag |= ND_IMPLIEDCLID;
  826                         nd->nd_clientid.qval = clientid.qval;
  827                 }
  828                 stp->ls_stateid.other[2] = *tl++;
  829                 off = fxdr_hyper(tl);
  830                 lop->lo_first = off;
  831                 tl += 2;
  832                 stable = fxdr_unsigned(int, *tl++);
  833                 retlen = len = fxdr_unsigned(int32_t, *tl);
  834                 lop->lo_end = off + len;
  835                 /*
  836                  * Paranoia, just in case it wraps around, which shouldn't
  837                  * ever happen anyhow.
  838                  */
  839                 if (lop->lo_end < lop->lo_first)
  840                         lop->lo_end = NFS64BITSSET;
  841         }
  842 
  843         /*
  844          * Loop through the mbuf chain, counting how many mbufs are a
  845          * part of this write operation, so the iovec size is known.
  846          */
  847         cnt = 0;
  848         mp = nd->nd_md;
  849         i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
  850         while (len > 0) {
  851                 if (i > 0) {
  852                         len -= i;
  853                         cnt++;
  854                 }
  855                 mp = mbuf_next(mp);
  856                 if (!mp) {
  857                         if (len > 0) {
  858                                 error = EBADRPC;
  859                                 goto nfsmout;
  860                         }
  861                 } else
  862                         i = mbuf_len(mp);
  863         }
  864 
  865         if (retlen > NFS_SRVMAXIO || retlen < 0)
  866                 nd->nd_repstat = EIO;
  867         if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
  868                 if (nd->nd_flag & ND_NFSV3)
  869                         nd->nd_repstat = EINVAL;
  870                 else
  871                         nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
  872                             EINVAL;
  873         }
  874         forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1);
  875         if (!nd->nd_repstat)
  876                 nd->nd_repstat = forat_ret;
  877         if (!nd->nd_repstat &&
  878             (forat.na_uid != nd->nd_cred->cr_uid ||
  879              NFSVNO_EXSTRICTACCESS(exp)))
  880                 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
  881                     nd->nd_cred, exp, p,
  882                     NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
  883         if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
  884                 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
  885                     &stateid, exp, nd, p);
  886         }
  887         if (nd->nd_repstat) {
  888                 vput(vp);
  889                 if (nd->nd_flag & ND_NFSV3)
  890                         nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
  891                 goto out;
  892         }
  893 
  894         /*
  895          * For NFS Version 2, it is not obvious what a write of zero length
  896          * should do, but I might as well be consistent with Version 3,
  897          * which is to return ok so long as there are no permission problems.
  898          */
  899         if (retlen > 0) {
  900                 nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable,
  901                     nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
  902                 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
  903                 if (error)
  904                         panic("nfsrv_write mbuf");
  905         }
  906         if (nd->nd_flag & ND_NFSV4)
  907                 aftat_ret = 0;
  908         else
  909                 aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
  910         vput(vp);
  911         if (!nd->nd_repstat)
  912                 nd->nd_repstat = aftat_ret;
  913         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
  914                 if (nd->nd_flag & ND_NFSV3)
  915                         nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
  916                 if (nd->nd_repstat)
  917                         goto out;
  918                 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
  919                 *tl++ = txdr_unsigned(retlen);
  920                 /*
  921                  * If nfs_async is set, then pretend the write was FILESYNC.
  922                  * Warning: Doing this violates RFC1813 and runs a risk
  923                  * of data written by a client being lost when the server
  924                  * crashes/reboots.
  925                  */
  926                 if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
  927                         *tl++ = txdr_unsigned(stable);
  928                 else
  929                         *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
  930                 /*
  931                  * Actually, there is no need to txdr these fields,
  932                  * but it may make the values more human readable,
  933                  * for debugging purposes.
  934                  */
  935                 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
  936                 *tl = txdr_unsigned(nfsboottime.tv_usec);
  937         } else if (!nd->nd_repstat)
  938                 nfsrv_fillattr(nd, &nva);
  939 
  940 out:
  941         NFSEXITCODE2(0, nd);
  942         return (0);
  943 nfsmout:
  944         vput(vp);
  945         NFSEXITCODE2(error, nd);
  946         return (error);
  947 }
  948 
  949 /*
  950  * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
  951  * now does a truncate to 0 length via. setattr if it already exists
  952  * The core creation routine has been extracted out into nfsrv_creatsub(),
  953  * so it can also be used by nfsrv_open() for V4.
  954  */
  955 APPLESTATIC int
  956 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
  957     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
  958 {
  959         struct nfsvattr nva, dirfor, diraft;
  960         struct nfsv2_sattr *sp;
  961         struct nameidata named;
  962         u_int32_t *tl;
  963         int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
  964         int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
  965         NFSDEV_T rdev = 0;
  966         vnode_t vp = NULL, dirp = NULL;
  967         fhandle_t fh;
  968         char *bufp;
  969         u_long *hashp;
  970         enum vtype vtyp;
  971         int32_t cverf[2], tverf[2] = { 0, 0 };
  972 
  973         if (nd->nd_repstat) {
  974                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
  975                 goto out;
  976         }
  977         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
  978             LOCKPARENT | LOCKLEAF | SAVESTART);
  979         nfsvno_setpathbuf(&named, &bufp, &hashp);
  980         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
  981         if (error)
  982                 goto nfsmout;
  983         if (!nd->nd_repstat) {
  984                 NFSVNO_ATTRINIT(&nva);
  985                 if (nd->nd_flag & ND_NFSV2) {
  986                         NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
  987                         vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
  988                         if (vtyp == VNON)
  989                                 vtyp = VREG;
  990                         NFSVNO_SETATTRVAL(&nva, type, vtyp);
  991                         NFSVNO_SETATTRVAL(&nva, mode,
  992                             nfstov_mode(sp->sa_mode));
  993                         switch (nva.na_type) {
  994                         case VREG:
  995                                 tsize = fxdr_unsigned(int32_t, sp->sa_size);
  996                                 if (tsize != -1)
  997                                         NFSVNO_SETATTRVAL(&nva, size,
  998                                             (u_quad_t)tsize);
  999                                 break;
 1000                         case VCHR:
 1001                         case VBLK:
 1002                         case VFIFO:
 1003                                 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
 1004                                 break;
 1005                         default:
 1006                                 break;
 1007                         };
 1008                 } else {
 1009                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1010                         how = fxdr_unsigned(int, *tl);
 1011                         switch (how) {
 1012                         case NFSCREATE_GUARDED:
 1013                         case NFSCREATE_UNCHECKED:
 1014                                 error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
 1015                                 if (error)
 1016                                         goto nfsmout;
 1017                                 break;
 1018                         case NFSCREATE_EXCLUSIVE:
 1019                                 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
 1020                                 cverf[0] = *tl++;
 1021                                 cverf[1] = *tl;
 1022                                 exclusive_flag = 1;
 1023                                 break;
 1024                         };
 1025                         NFSVNO_SETATTRVAL(&nva, type, VREG);
 1026                 }
 1027         }
 1028         if (nd->nd_repstat) {
 1029                 nfsvno_relpathbuf(&named);
 1030                 if (nd->nd_flag & ND_NFSV3) {
 1031                         dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred,
 1032                             p, 1);
 1033                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
 1034                             &diraft);
 1035                 }
 1036                 vput(dp);
 1037                 goto out;
 1038         }
 1039 
 1040         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
 1041         if (dirp) {
 1042                 if (nd->nd_flag & ND_NFSV2) {
 1043                         vrele(dirp);
 1044                         dirp = NULL;
 1045                 } else {
 1046                         dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
 1047                             p, 0);
 1048                 }
 1049         }
 1050         if (nd->nd_repstat) {
 1051                 if (nd->nd_flag & ND_NFSV3)
 1052                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
 1053                             &diraft);
 1054                 if (dirp)
 1055                         vrele(dirp);
 1056                 goto out;
 1057         }
 1058 
 1059         if (!(nd->nd_flag & ND_NFSV2)) {
 1060                 switch (how) {
 1061                 case NFSCREATE_GUARDED:
 1062                         if (named.ni_vp)
 1063                                 nd->nd_repstat = EEXIST;
 1064                         break;
 1065                 case NFSCREATE_UNCHECKED:
 1066                         break;
 1067                 case NFSCREATE_EXCLUSIVE:
 1068                         if (named.ni_vp == NULL)
 1069                                 NFSVNO_SETATTRVAL(&nva, mode, 0);
 1070                         break;
 1071                 };
 1072         }
 1073 
 1074         /*
 1075          * Iff doesn't exist, create it
 1076          * otherwise just truncate to 0 length
 1077          *   should I set the mode too ?
 1078          */
 1079         nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
 1080             &exclusive_flag, cverf, rdev, p, exp);
 1081 
 1082         if (!nd->nd_repstat) {
 1083                 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
 1084                 if (!nd->nd_repstat)
 1085                         nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
 1086                             p, 1);
 1087                 vput(vp);
 1088                 if (!nd->nd_repstat) {
 1089                         tverf[0] = nva.na_atime.tv_sec;
 1090                         tverf[1] = nva.na_atime.tv_nsec;
 1091                 }
 1092         }
 1093         if (nd->nd_flag & ND_NFSV2) {
 1094                 if (!nd->nd_repstat) {
 1095                         (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
 1096                         nfsrv_fillattr(nd, &nva);
 1097                 }
 1098         } else {
 1099                 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
 1100                     || cverf[1] != tverf[1]))
 1101                         nd->nd_repstat = EEXIST;
 1102                 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
 1103                 vrele(dirp);
 1104                 if (!nd->nd_repstat) {
 1105                         (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
 1106                         nfsrv_postopattr(nd, 0, &nva);
 1107                 }
 1108                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1109         }
 1110 
 1111 out:
 1112         NFSEXITCODE2(0, nd);
 1113         return (0);
 1114 nfsmout:
 1115         vput(dp);
 1116         nfsvno_relpathbuf(&named);
 1117         NFSEXITCODE2(error, nd);
 1118         return (error);
 1119 }
 1120 
 1121 /*
 1122  * nfs v3 mknod service (and v4 create)
 1123  */
 1124 APPLESTATIC int
 1125 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
 1126     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
 1127     struct nfsexstuff *exp)
 1128 {
 1129         struct nfsvattr nva, dirfor, diraft;
 1130         u_int32_t *tl;
 1131         struct nameidata named;
 1132         int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
 1133         u_int32_t major, minor;
 1134         enum vtype vtyp = VNON;
 1135         nfstype nfs4type = NFNON;
 1136         vnode_t vp, dirp = NULL;
 1137         nfsattrbit_t attrbits;
 1138         char *bufp = NULL, *pathcp = NULL;
 1139         u_long *hashp, cnflags;
 1140         NFSACL_T *aclp = NULL;
 1141 
 1142         NFSVNO_ATTRINIT(&nva);
 1143         cnflags = (LOCKPARENT | SAVESTART);
 1144         if (nd->nd_repstat) {
 1145                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1146                 goto out;
 1147         }
 1148 #ifdef NFS4_ACL_EXTATTR_NAME
 1149         aclp = acl_alloc(M_WAITOK);
 1150         aclp->acl_cnt = 0;
 1151 #endif
 1152 
 1153         /*
 1154          * For V4, the creation stuff is here, Yuck!
 1155          */
 1156         if (nd->nd_flag & ND_NFSV4) {
 1157                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1158                 vtyp = nfsv34tov_type(*tl);
 1159                 nfs4type = fxdr_unsigned(nfstype, *tl);
 1160                 switch (nfs4type) {
 1161                 case NFLNK:
 1162                         error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
 1163                             &pathlen);
 1164                         if (error)
 1165                                 goto nfsmout;
 1166                         break;
 1167                 case NFCHR:
 1168                 case NFBLK:
 1169                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1170                         major = fxdr_unsigned(u_int32_t, *tl++);
 1171                         minor = fxdr_unsigned(u_int32_t, *tl);
 1172                         nva.na_rdev = NFSMAKEDEV(major, minor);
 1173                         break;
 1174                 case NFSOCK:
 1175                 case NFFIFO:
 1176                         break;
 1177                 case NFDIR:
 1178                         cnflags = (LOCKPARENT | SAVENAME);
 1179                         break;
 1180                 default:
 1181                         nd->nd_repstat = NFSERR_BADTYPE;
 1182                         vrele(dp);
 1183 #ifdef NFS4_ACL_EXTATTR_NAME
 1184                         acl_free(aclp);
 1185 #endif
 1186                         goto out;
 1187                 }
 1188         }
 1189         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags);
 1190         nfsvno_setpathbuf(&named, &bufp, &hashp);
 1191         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
 1192         if (error)
 1193                 goto nfsmout;
 1194         if (!nd->nd_repstat) {
 1195                 if (nd->nd_flag & ND_NFSV3) {
 1196                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1197                         vtyp = nfsv34tov_type(*tl);
 1198                 }
 1199                 error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
 1200                 if (error)
 1201                         goto nfsmout;
 1202                 nva.na_type = vtyp;
 1203                 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
 1204                     (vtyp == VCHR || vtyp == VBLK)) {
 1205                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1206                         major = fxdr_unsigned(u_int32_t, *tl++);
 1207                         minor = fxdr_unsigned(u_int32_t, *tl);
 1208                         nva.na_rdev = NFSMAKEDEV(major, minor);
 1209                 }
 1210         }
 1211 
 1212         dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
 1213         if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
 1214                 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
 1215                     dirfor.na_gid == nva.na_gid)
 1216                         NFSVNO_UNSET(&nva, gid);
 1217                 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
 1218         }
 1219         if (nd->nd_repstat) {
 1220                 vrele(dp);
 1221 #ifdef NFS4_ACL_EXTATTR_NAME
 1222                 acl_free(aclp);
 1223 #endif
 1224                 nfsvno_relpathbuf(&named);
 1225                 if (pathcp)
 1226                         FREE(pathcp, M_TEMP);
 1227                 if (nd->nd_flag & ND_NFSV3)
 1228                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
 1229                             &diraft);
 1230                 goto out;
 1231         }
 1232 
 1233         /*
 1234          * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
 1235          * in va_mode, so we'll have to set a default here.
 1236          */
 1237         if (NFSVNO_NOTSETMODE(&nva)) {
 1238                 if (vtyp == VLNK)
 1239                         nva.na_mode = 0755;
 1240                 else
 1241                         nva.na_mode = 0400;
 1242         }
 1243 
 1244         if (vtyp == VDIR)
 1245                 named.ni_cnd.cn_flags |= WILLBEDIR;
 1246         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
 1247         if (nd->nd_repstat) {
 1248                 if (dirp) {
 1249                         if (nd->nd_flag & ND_NFSV3)
 1250                                 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
 1251                                     nd->nd_cred, p, 0);
 1252                         vrele(dirp);
 1253                 }
 1254 #ifdef NFS4_ACL_EXTATTR_NAME
 1255                 acl_free(aclp);
 1256 #endif
 1257                 if (nd->nd_flag & ND_NFSV3)
 1258                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
 1259                             &diraft);
 1260                 goto out;
 1261         }
 1262         if (dirp)
 1263                 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
 1264 
 1265         if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
 1266                 if (vtyp == VDIR) {
 1267                         nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
 1268                             &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
 1269                             exp);
 1270 #ifdef NFS4_ACL_EXTATTR_NAME
 1271                         acl_free(aclp);
 1272 #endif
 1273                         goto out;
 1274                 } else if (vtyp == VLNK) {
 1275                         nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
 1276                             &dirfor, &diraft, &diraft_ret, &attrbits,
 1277                             aclp, p, exp, pathcp, pathlen);
 1278 #ifdef NFS4_ACL_EXTATTR_NAME
 1279                         acl_free(aclp);
 1280 #endif
 1281                         FREE(pathcp, M_TEMP);
 1282                         goto out;
 1283                 }
 1284         }
 1285 
 1286         nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
 1287         if (!nd->nd_repstat) {
 1288                 vp = named.ni_vp;
 1289                 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
 1290                 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
 1291                 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
 1292                         nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
 1293                             p, 1);
 1294                 if (vpp != NULL && nd->nd_repstat == 0) {
 1295                         NFSVOPUNLOCK(vp, 0);
 1296                         *vpp = vp;
 1297                 } else
 1298                         vput(vp);
 1299         }
 1300 
 1301         diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
 1302         vrele(dirp);
 1303         if (!nd->nd_repstat) {
 1304                 if (nd->nd_flag & ND_NFSV3) {
 1305                         (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
 1306                         nfsrv_postopattr(nd, 0, &nva);
 1307                 } else {
 1308                         NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 1309                         *tl++ = newnfs_false;
 1310                         txdr_hyper(dirfor.na_filerev, tl);
 1311                         tl += 2;
 1312                         txdr_hyper(diraft.na_filerev, tl);
 1313                         (void) nfsrv_putattrbit(nd, &attrbits);
 1314                 }
 1315         }
 1316         if (nd->nd_flag & ND_NFSV3)
 1317                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1318 #ifdef NFS4_ACL_EXTATTR_NAME
 1319         acl_free(aclp);
 1320 #endif
 1321 
 1322 out:
 1323         NFSEXITCODE2(0, nd);
 1324         return (0);
 1325 nfsmout:
 1326         vrele(dp);
 1327 #ifdef NFS4_ACL_EXTATTR_NAME
 1328         acl_free(aclp);
 1329 #endif
 1330         if (bufp)
 1331                 nfsvno_relpathbuf(&named);
 1332         if (pathcp)
 1333                 FREE(pathcp, M_TEMP);
 1334 
 1335         NFSEXITCODE2(error, nd);
 1336         return (error);
 1337 }
 1338 
 1339 /*
 1340  * nfs remove service
 1341  */
 1342 APPLESTATIC int
 1343 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
 1344     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
 1345 {
 1346         struct nameidata named;
 1347         u_int32_t *tl;
 1348         int error = 0, dirfor_ret = 1, diraft_ret = 1;
 1349         vnode_t dirp = NULL;
 1350         struct nfsvattr dirfor, diraft;
 1351         char *bufp;
 1352         u_long *hashp;
 1353 
 1354         if (nd->nd_repstat) {
 1355                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1356                 goto out;
 1357         }
 1358         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
 1359             LOCKPARENT | LOCKLEAF);
 1360         nfsvno_setpathbuf(&named, &bufp, &hashp);
 1361         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
 1362         if (error) {
 1363                 vput(dp);
 1364                 nfsvno_relpathbuf(&named);
 1365                 goto out;
 1366         }
 1367         if (!nd->nd_repstat) {
 1368                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
 1369         } else {
 1370                 vput(dp);
 1371                 nfsvno_relpathbuf(&named);
 1372         }
 1373         if (dirp) {
 1374                 if (!(nd->nd_flag & ND_NFSV2)) {
 1375                         dirfor_ret = nfsvno_getattr(dirp, &dirfor,
 1376                             nd->nd_cred, p, 0);
 1377                 } else {
 1378                         vrele(dirp);
 1379                         dirp = NULL;
 1380                 }
 1381         }
 1382         if (!nd->nd_repstat) {
 1383                 if (nd->nd_flag & ND_NFSV4) {
 1384                         if (vnode_vtype(named.ni_vp) == VDIR)
 1385                                 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
 1386                                     nd->nd_cred, p, exp);
 1387                         else
 1388                                 nd->nd_repstat = nfsvno_removesub(&named, 1,
 1389                                     nd->nd_cred, p, exp);
 1390                 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
 1391                         nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
 1392                             nd->nd_cred, p, exp);
 1393                 } else {
 1394                         nd->nd_repstat = nfsvno_removesub(&named, 0,
 1395                             nd->nd_cred, p, exp);
 1396                 }
 1397         }
 1398         if (!(nd->nd_flag & ND_NFSV2)) {
 1399                 if (dirp) {
 1400                         diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred,
 1401                             p, 0);
 1402                         vrele(dirp);
 1403                 }
 1404                 if (nd->nd_flag & ND_NFSV3) {
 1405                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
 1406                             &diraft);
 1407                 } else if (!nd->nd_repstat) {
 1408                         NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 1409                         *tl++ = newnfs_false;
 1410                         txdr_hyper(dirfor.na_filerev, tl);
 1411                         tl += 2;
 1412                         txdr_hyper(diraft.na_filerev, tl);
 1413                 }
 1414         }
 1415 
 1416 out:
 1417         NFSEXITCODE2(error, nd);
 1418         return (error);
 1419 }
 1420 
 1421 /*
 1422  * nfs rename service
 1423  */
 1424 APPLESTATIC int
 1425 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
 1426     vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp,
 1427     struct nfsexstuff *toexp)
 1428 {
 1429         u_int32_t *tl;
 1430         int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
 1431         int tdirfor_ret = 1, tdiraft_ret = 1;
 1432         struct nameidata fromnd, tond;
 1433         vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
 1434         struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
 1435         struct nfsexstuff tnes;
 1436         struct nfsrvfh tfh;
 1437         char *bufp, *tbufp = NULL;
 1438         u_long *hashp;
 1439         fhandle_t fh;
 1440 
 1441         if (nd->nd_repstat) {
 1442                 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
 1443                 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
 1444                 goto out;
 1445         }
 1446         if (!(nd->nd_flag & ND_NFSV2))
 1447                 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1);
 1448         tond.ni_cnd.cn_nameiop = 0;
 1449         tond.ni_startdir = NULL;
 1450         NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
 1451         nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
 1452         error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
 1453         if (error) {
 1454                 vput(dp);
 1455                 if (todp)
 1456                         vrele(todp);
 1457                 nfsvno_relpathbuf(&fromnd);
 1458                 goto out;
 1459         }
 1460         /*
 1461          * Unlock dp in this code section, so it is unlocked before
 1462          * tdp gets locked. This avoids a potential LOR if tdp is the
 1463          * parent directory of dp.
 1464          */
 1465         if (nd->nd_flag & ND_NFSV4) {
 1466                 tdp = todp;
 1467                 tnes = *toexp;
 1468                 if (dp != tdp) {
 1469                         NFSVOPUNLOCK(dp, 0);
 1470                         tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
 1471                             p, 0);      /* Might lock tdp. */
 1472                 } else {
 1473                         tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
 1474                             p, 1);
 1475                         NFSVOPUNLOCK(dp, 0);
 1476                 }
 1477         } else {
 1478                 tfh.nfsrvfh_len = 0;
 1479                 error = nfsrv_mtofh(nd, &tfh);
 1480                 if (error == 0)
 1481                         error = nfsvno_getfh(dp, &fh, p);
 1482                 if (error) {
 1483                         vput(dp);
 1484                         /* todp is always NULL except NFSv4 */
 1485                         nfsvno_relpathbuf(&fromnd);
 1486                         goto out;
 1487                 }
 1488 
 1489                 /* If this is the same file handle, just VREF() the vnode. */
 1490                 if (tfh.nfsrvfh_len == NFSX_MYFH &&
 1491                     !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
 1492                         VREF(dp);
 1493                         tdp = dp;
 1494                         tnes = *exp;
 1495                         tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
 1496                             p, 1);
 1497                         NFSVOPUNLOCK(dp, 0);
 1498                 } else {
 1499                         NFSVOPUNLOCK(dp, 0);
 1500                         nd->nd_cred->cr_uid = nd->nd_saveduid;
 1501                         nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
 1502                             0, p);      /* Locks tdp. */
 1503                         if (tdp) {
 1504                                 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor,
 1505                                     nd->nd_cred, p, 1);
 1506                                 NFSVOPUNLOCK(tdp, 0);
 1507                         }
 1508                 }
 1509         }
 1510         NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
 1511         nfsvno_setpathbuf(&tond, &tbufp, &hashp);
 1512         if (!nd->nd_repstat) {
 1513                 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
 1514                 if (error) {
 1515                         if (tdp)
 1516                                 vrele(tdp);
 1517                         vrele(dp);
 1518                         nfsvno_relpathbuf(&fromnd);
 1519                         nfsvno_relpathbuf(&tond);
 1520                         goto out;
 1521                 }
 1522         }
 1523         if (nd->nd_repstat) {
 1524                 if (nd->nd_flag & ND_NFSV3) {
 1525                         nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
 1526                             &fdiraft);
 1527                         nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
 1528                             &tdiraft);
 1529                 }
 1530                 if (tdp)
 1531                         vrele(tdp);
 1532                 vrele(dp);
 1533                 nfsvno_relpathbuf(&fromnd);
 1534                 nfsvno_relpathbuf(&tond);
 1535                 goto out;
 1536         }
 1537 
 1538         /*
 1539          * Done parsing, now down to business.
 1540          */
 1541         nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
 1542         if (nd->nd_repstat) {
 1543                 if (nd->nd_flag & ND_NFSV3) {
 1544                         nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
 1545                             &fdiraft);
 1546                         nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
 1547                             &tdiraft);
 1548                 }
 1549                 if (fdirp)
 1550                         vrele(fdirp);
 1551                 if (tdp)
 1552                         vrele(tdp);
 1553                 nfsvno_relpathbuf(&tond);
 1554                 goto out;
 1555         }
 1556         if (vnode_vtype(fromnd.ni_vp) == VDIR)
 1557                 tond.ni_cnd.cn_flags |= WILLBEDIR;
 1558         nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
 1559         nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
 1560             nd->nd_flag, nd->nd_cred, p);
 1561         if (fdirp)
 1562                 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p,
 1563                     0);
 1564         if (tdirp)
 1565                 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
 1566                     0);
 1567         if (fdirp)
 1568                 vrele(fdirp);
 1569         if (tdirp)
 1570                 vrele(tdirp);
 1571         if (nd->nd_flag & ND_NFSV3) {
 1572                 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
 1573                 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
 1574         } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
 1575                 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
 1576                 *tl++ = newnfs_false;
 1577                 txdr_hyper(fdirfor.na_filerev, tl);
 1578                 tl += 2;
 1579                 txdr_hyper(fdiraft.na_filerev, tl);
 1580                 tl += 2;
 1581                 *tl++ = newnfs_false;
 1582                 txdr_hyper(tdirfor.na_filerev, tl);
 1583                 tl += 2;
 1584                 txdr_hyper(tdiraft.na_filerev, tl);
 1585         }
 1586 
 1587 out:
 1588         NFSEXITCODE2(error, nd);
 1589         return (error);
 1590 }
 1591 
 1592 /*
 1593  * nfs link service
 1594  */
 1595 APPLESTATIC int
 1596 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
 1597     vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
 1598     struct nfsexstuff *toexp)
 1599 {
 1600         struct nameidata named;
 1601         u_int32_t *tl;
 1602         int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
 1603         vnode_t dirp = NULL, dp = NULL;
 1604         struct nfsvattr dirfor, diraft, at;
 1605         struct nfsexstuff tnes;
 1606         struct nfsrvfh dfh;
 1607         char *bufp;
 1608         u_long *hashp;
 1609 
 1610         if (nd->nd_repstat) {
 1611                 nfsrv_postopattr(nd, getret, &at);
 1612                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1613                 goto out;
 1614         }
 1615         NFSVOPUNLOCK(vp, 0);
 1616         if (vnode_vtype(vp) == VDIR) {
 1617                 if (nd->nd_flag & ND_NFSV4)
 1618                         nd->nd_repstat = NFSERR_ISDIR;
 1619                 else
 1620                         nd->nd_repstat = NFSERR_INVAL;
 1621                 if (tovp)
 1622                         vrele(tovp);
 1623         }
 1624         if (!nd->nd_repstat) {
 1625                 if (nd->nd_flag & ND_NFSV4) {
 1626                         dp = tovp;
 1627                         tnes = *toexp;
 1628                 } else {
 1629                         error = nfsrv_mtofh(nd, &dfh);
 1630                         if (error) {
 1631                                 vrele(vp);
 1632                                 /* tovp is always NULL unless NFSv4 */
 1633                                 goto out;
 1634                         }
 1635                         nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0,
 1636                             p);
 1637                         if (dp)
 1638                                 NFSVOPUNLOCK(dp, 0);
 1639                 }
 1640         }
 1641         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
 1642             LOCKPARENT | SAVENAME);
 1643         if (!nd->nd_repstat) {
 1644                 nfsvno_setpathbuf(&named, &bufp, &hashp);
 1645                 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
 1646                 if (error) {
 1647                         vrele(vp);
 1648                         if (dp)
 1649                                 vrele(dp);
 1650                         nfsvno_relpathbuf(&named);
 1651                         goto out;
 1652                 }
 1653                 if (!nd->nd_repstat) {
 1654                         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
 1655                             p, &dirp);
 1656                 } else {
 1657                         if (dp)
 1658                                 vrele(dp);
 1659                         nfsvno_relpathbuf(&named);
 1660                 }
 1661         }
 1662         if (dirp) {
 1663                 if (nd->nd_flag & ND_NFSV2) {
 1664                         vrele(dirp);
 1665                         dirp = NULL;
 1666                 } else {
 1667                         dirfor_ret = nfsvno_getattr(dirp, &dirfor,
 1668                             nd->nd_cred, p, 0);
 1669                 }
 1670         }
 1671         if (!nd->nd_repstat)
 1672                 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
 1673         if (nd->nd_flag & ND_NFSV3)
 1674                 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
 1675         if (dirp) {
 1676                 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
 1677                 vrele(dirp);
 1678         }
 1679         vrele(vp);
 1680         if (nd->nd_flag & ND_NFSV3) {
 1681                 nfsrv_postopattr(nd, getret, &at);
 1682                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1683         } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
 1684                 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 1685                 *tl++ = newnfs_false;
 1686                 txdr_hyper(dirfor.na_filerev, tl);
 1687                 tl += 2;
 1688                 txdr_hyper(diraft.na_filerev, tl);
 1689         }
 1690 
 1691 out:
 1692         NFSEXITCODE2(error, nd);
 1693         return (error);
 1694 }
 1695 
 1696 /*
 1697  * nfs symbolic link service
 1698  */
 1699 APPLESTATIC int
 1700 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
 1701     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
 1702     struct nfsexstuff *exp)
 1703 {
 1704         struct nfsvattr nva, dirfor, diraft;
 1705         struct nameidata named;
 1706         int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
 1707         vnode_t dirp = NULL;
 1708         char *bufp, *pathcp = NULL;
 1709         u_long *hashp;
 1710 
 1711         if (nd->nd_repstat) {
 1712                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1713                 goto out;
 1714         }
 1715         if (vpp)
 1716                 *vpp = NULL;
 1717         NFSVNO_ATTRINIT(&nva);
 1718         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
 1719             LOCKPARENT | SAVESTART);
 1720         nfsvno_setpathbuf(&named, &bufp, &hashp);
 1721         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
 1722         if (!error && !nd->nd_repstat)
 1723                 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
 1724         if (error) {
 1725                 vrele(dp);
 1726                 nfsvno_relpathbuf(&named);
 1727                 goto out;
 1728         }
 1729         if (!nd->nd_repstat) {
 1730                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
 1731         } else {
 1732                 vrele(dp);
 1733                 nfsvno_relpathbuf(&named);
 1734         }
 1735         if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
 1736                 vrele(dirp);
 1737                 dirp = NULL;
 1738         }
 1739 
 1740         /*
 1741          * And call nfsrvd_symlinksub() to do the common code. It will
 1742          * return EBADRPC upon a parsing error, 0 otherwise.
 1743          */
 1744         if (!nd->nd_repstat) {
 1745                 if (dirp != NULL)
 1746                         dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
 1747                             p, 0);
 1748                 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
 1749                     &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
 1750                     pathcp, pathlen);
 1751         } else if (dirp != NULL) {
 1752                 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
 1753                 vrele(dirp);
 1754         }
 1755         if (pathcp)
 1756                 FREE(pathcp, M_TEMP);
 1757 
 1758         if (nd->nd_flag & ND_NFSV3) {
 1759                 if (!nd->nd_repstat) {
 1760                         (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
 1761                         nfsrv_postopattr(nd, 0, &nva);
 1762                 }
 1763                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1764         }
 1765 
 1766 out:
 1767         NFSEXITCODE2(error, nd);
 1768         return (error);
 1769 }
 1770 
 1771 /*
 1772  * Common code for creating a symbolic link.
 1773  */
 1774 static void
 1775 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
 1776     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
 1777     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
 1778     int *diraft_retp, nfsattrbit_t *attrbitp,
 1779     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
 1780     int pathlen)
 1781 {
 1782         u_int32_t *tl;
 1783 
 1784         nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
 1785             !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
 1786         if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
 1787                 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
 1788                 if (nd->nd_flag & ND_NFSV3) {
 1789                         nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
 1790                         if (!nd->nd_repstat)
 1791                                 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
 1792                                     nvap, nd->nd_cred, p, 1);
 1793                 }
 1794                 if (vpp != NULL && nd->nd_repstat == 0) {
 1795                         NFSVOPUNLOCK(ndp->ni_vp, 0);
 1796                         *vpp = ndp->ni_vp;
 1797                 } else
 1798                         vput(ndp->ni_vp);
 1799         }
 1800         if (dirp) {
 1801                 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
 1802                 vrele(dirp);
 1803         }
 1804         if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
 1805                 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 1806                 *tl++ = newnfs_false;
 1807                 txdr_hyper(dirforp->na_filerev, tl);
 1808                 tl += 2;
 1809                 txdr_hyper(diraftp->na_filerev, tl);
 1810                 (void) nfsrv_putattrbit(nd, attrbitp);
 1811         }
 1812 
 1813         NFSEXITCODE2(0, nd);
 1814 }
 1815 
 1816 /*
 1817  * nfs mkdir service
 1818  */
 1819 APPLESTATIC int
 1820 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
 1821     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
 1822     struct nfsexstuff *exp)
 1823 {
 1824         struct nfsvattr nva, dirfor, diraft;
 1825         struct nameidata named;
 1826         u_int32_t *tl;
 1827         int error = 0, dirfor_ret = 1, diraft_ret = 1;
 1828         vnode_t dirp = NULL;
 1829         char *bufp;
 1830         u_long *hashp;
 1831 
 1832         if (nd->nd_repstat) {
 1833                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1834                 goto out;
 1835         }
 1836         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
 1837             LOCKPARENT | SAVENAME);
 1838         nfsvno_setpathbuf(&named, &bufp, &hashp);
 1839         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
 1840         if (error)
 1841                 goto nfsmout;
 1842         if (!nd->nd_repstat) {
 1843                 NFSVNO_ATTRINIT(&nva);
 1844                 if (nd->nd_flag & ND_NFSV3) {
 1845                         error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
 1846                         if (error)
 1847                                 goto nfsmout;
 1848                 } else {
 1849                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1850                         nva.na_mode = nfstov_mode(*tl++);
 1851                 }
 1852         }
 1853         if (!nd->nd_repstat) {
 1854                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
 1855         } else {
 1856                 vrele(dp);
 1857                 nfsvno_relpathbuf(&named);
 1858         }
 1859         if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
 1860                 vrele(dirp);
 1861                 dirp = NULL;
 1862         }
 1863         if (nd->nd_repstat) {
 1864                 if (dirp != NULL) {
 1865                         dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
 1866                             p, 0);
 1867                         vrele(dirp);
 1868                 }
 1869                 if (nd->nd_flag & ND_NFSV3)
 1870                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
 1871                             &diraft);
 1872                 goto out;
 1873         }
 1874         if (dirp != NULL)
 1875                 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
 1876 
 1877         /*
 1878          * Call nfsrvd_mkdirsub() for the code common to V4 as well.
 1879          */
 1880         nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
 1881             &diraft_ret, NULL, NULL, p, exp);
 1882 
 1883         if (nd->nd_flag & ND_NFSV3) {
 1884                 if (!nd->nd_repstat) {
 1885                         (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
 1886                         nfsrv_postopattr(nd, 0, &nva);
 1887                 }
 1888                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1889         } else if (!nd->nd_repstat) {
 1890                 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
 1891                 nfsrv_fillattr(nd, &nva);
 1892         }
 1893 
 1894 out:
 1895         NFSEXITCODE2(0, nd);
 1896         return (0);
 1897 nfsmout:
 1898         vrele(dp);
 1899         nfsvno_relpathbuf(&named);
 1900         NFSEXITCODE2(error, nd);
 1901         return (error);
 1902 }
 1903 
 1904 /*
 1905  * Code common to mkdir for V2,3 and 4.
 1906  */
 1907 static void
 1908 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
 1909     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
 1910     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
 1911     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
 1912     NFSPROC_T *p, struct nfsexstuff *exp)
 1913 {
 1914         vnode_t vp;
 1915         u_int32_t *tl;
 1916 
 1917         NFSVNO_SETATTRVAL(nvap, type, VDIR);
 1918         nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
 1919             nd->nd_cred, p, exp);
 1920         if (!nd->nd_repstat) {
 1921                 vp = ndp->ni_vp;
 1922                 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
 1923                 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
 1924                 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
 1925                         nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
 1926                             p, 1);
 1927                 if (vpp && !nd->nd_repstat) {
 1928                         NFSVOPUNLOCK(vp, 0);
 1929                         *vpp = vp;
 1930                 } else {
 1931                         vput(vp);
 1932                 }
 1933         }
 1934         if (dirp) {
 1935                 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
 1936                 vrele(dirp);
 1937         }
 1938         if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
 1939                 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 1940                 *tl++ = newnfs_false;
 1941                 txdr_hyper(dirforp->na_filerev, tl);
 1942                 tl += 2;
 1943                 txdr_hyper(diraftp->na_filerev, tl);
 1944                 (void) nfsrv_putattrbit(nd, attrbitp);
 1945         }
 1946 
 1947         NFSEXITCODE2(0, nd);
 1948 }
 1949 
 1950 /*
 1951  * nfs commit service
 1952  */
 1953 APPLESTATIC int
 1954 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
 1955     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 1956 {
 1957         struct nfsvattr bfor, aft;
 1958         u_int32_t *tl;
 1959         int error = 0, for_ret = 1, aft_ret = 1, cnt;
 1960         u_int64_t off;
 1961 
 1962         if (nd->nd_repstat) {
 1963                 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
 1964                 goto out;
 1965         }
 1966         NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 1967         /*
 1968          * XXX At this time VOP_FSYNC() does not accept offset and byte
 1969          * count parameters, so these arguments are useless (someday maybe).
 1970          */
 1971         off = fxdr_hyper(tl);
 1972         tl += 2;
 1973         cnt = fxdr_unsigned(int, *tl);
 1974         if (nd->nd_flag & ND_NFSV3)
 1975                 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
 1976         nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
 1977         if (nd->nd_flag & ND_NFSV3) {
 1978                 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
 1979                 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
 1980         }
 1981         vput(vp);
 1982         if (!nd->nd_repstat) {
 1983                 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
 1984                 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
 1985                 *tl = txdr_unsigned(nfsboottime.tv_usec);
 1986         }
 1987 
 1988 out:
 1989         NFSEXITCODE2(0, nd);
 1990         return (0);
 1991 nfsmout:
 1992         vput(vp);
 1993         NFSEXITCODE2(error, nd);
 1994         return (error);
 1995 }
 1996 
 1997 /*
 1998  * nfs statfs service
 1999  */
 2000 APPLESTATIC int
 2001 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
 2002     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 2003 {
 2004         struct statfs *sf;
 2005         u_int32_t *tl;
 2006         int getret = 1;
 2007         struct nfsvattr at;
 2008         struct statfs sfs;
 2009         u_quad_t tval;
 2010 
 2011         if (nd->nd_repstat) {
 2012                 nfsrv_postopattr(nd, getret, &at);
 2013                 goto out;
 2014         }
 2015         sf = &sfs;
 2016         nd->nd_repstat = nfsvno_statfs(vp, sf);
 2017         getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
 2018         vput(vp);
 2019         if (nd->nd_flag & ND_NFSV3)
 2020                 nfsrv_postopattr(nd, getret, &at);
 2021         if (nd->nd_repstat)
 2022                 goto out;
 2023         if (nd->nd_flag & ND_NFSV2) {
 2024                 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
 2025                 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
 2026                 *tl++ = txdr_unsigned(sf->f_bsize);
 2027                 *tl++ = txdr_unsigned(sf->f_blocks);
 2028                 *tl++ = txdr_unsigned(sf->f_bfree);
 2029                 *tl = txdr_unsigned(sf->f_bavail);
 2030         } else {
 2031                 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
 2032                 tval = (u_quad_t)sf->f_blocks;
 2033                 tval *= (u_quad_t)sf->f_bsize;
 2034                 txdr_hyper(tval, tl); tl += 2;
 2035                 tval = (u_quad_t)sf->f_bfree;
 2036                 tval *= (u_quad_t)sf->f_bsize;
 2037                 txdr_hyper(tval, tl); tl += 2;
 2038                 tval = (u_quad_t)sf->f_bavail;
 2039                 tval *= (u_quad_t)sf->f_bsize;
 2040                 txdr_hyper(tval, tl); tl += 2;
 2041                 tval = (u_quad_t)sf->f_files;
 2042                 txdr_hyper(tval, tl); tl += 2;
 2043                 tval = (u_quad_t)sf->f_ffree;
 2044                 txdr_hyper(tval, tl); tl += 2;
 2045                 tval = (u_quad_t)sf->f_ffree;
 2046                 txdr_hyper(tval, tl); tl += 2;
 2047                 *tl = 0;
 2048         }
 2049 
 2050 out:
 2051         NFSEXITCODE2(0, nd);
 2052         return (0);
 2053 }
 2054 
 2055 /*
 2056  * nfs fsinfo service
 2057  */
 2058 APPLESTATIC int
 2059 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
 2060     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 2061 {
 2062         u_int32_t *tl;
 2063         struct nfsfsinfo fs;
 2064         int getret = 1;
 2065         struct nfsvattr at;
 2066 
 2067         if (nd->nd_repstat) {
 2068                 nfsrv_postopattr(nd, getret, &at);
 2069                 goto out;
 2070         }
 2071         getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
 2072         nfsvno_getfs(&fs, isdgram);
 2073         vput(vp);
 2074         nfsrv_postopattr(nd, getret, &at);
 2075         NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
 2076         *tl++ = txdr_unsigned(fs.fs_rtmax);
 2077         *tl++ = txdr_unsigned(fs.fs_rtpref);
 2078         *tl++ = txdr_unsigned(fs.fs_rtmult);
 2079         *tl++ = txdr_unsigned(fs.fs_wtmax);
 2080         *tl++ = txdr_unsigned(fs.fs_wtpref);
 2081         *tl++ = txdr_unsigned(fs.fs_wtmult);
 2082         *tl++ = txdr_unsigned(fs.fs_dtpref);
 2083         txdr_hyper(fs.fs_maxfilesize, tl);
 2084         tl += 2;
 2085         txdr_nfsv3time(&fs.fs_timedelta, tl);
 2086         tl += 2;
 2087         *tl = txdr_unsigned(fs.fs_properties);
 2088 
 2089 out:
 2090         NFSEXITCODE2(0, nd);
 2091         return (0);
 2092 }
 2093 
 2094 /*
 2095  * nfs pathconf service
 2096  */
 2097 APPLESTATIC int
 2098 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
 2099     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 2100 {
 2101         struct nfsv3_pathconf *pc;
 2102         int getret = 1;
 2103         register_t linkmax, namemax, chownres, notrunc;
 2104         struct nfsvattr at;
 2105 
 2106         if (nd->nd_repstat) {
 2107                 nfsrv_postopattr(nd, getret, &at);
 2108                 goto out;
 2109         }
 2110         nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
 2111             nd->nd_cred, p);
 2112         if (!nd->nd_repstat)
 2113                 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
 2114                     nd->nd_cred, p);
 2115         if (!nd->nd_repstat)
 2116                 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
 2117                     &chownres, nd->nd_cred, p);
 2118         if (!nd->nd_repstat)
 2119                 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, &notrunc,
 2120                     nd->nd_cred, p);
 2121         getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
 2122         vput(vp);
 2123         nfsrv_postopattr(nd, getret, &at);
 2124         if (!nd->nd_repstat) {
 2125                 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
 2126                 pc->pc_linkmax = txdr_unsigned(linkmax);
 2127                 pc->pc_namemax = txdr_unsigned(namemax);
 2128                 pc->pc_notrunc = txdr_unsigned(notrunc);
 2129                 pc->pc_chownrestricted = txdr_unsigned(chownres);
 2130 
 2131                 /*
 2132                  * These should probably be supported by VOP_PATHCONF(), but
 2133                  * until msdosfs is exportable (why would you want to?), the
 2134                  * Unix defaults should be ok.
 2135                  */
 2136                 pc->pc_caseinsensitive = newnfs_false;
 2137                 pc->pc_casepreserving = newnfs_true;
 2138         }
 2139 
 2140 out:
 2141         NFSEXITCODE2(0, nd);
 2142         return (0);
 2143 }
 2144 
 2145 /*
 2146  * nfsv4 lock service
 2147  */
 2148 APPLESTATIC int
 2149 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
 2150     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
 2151 {
 2152         u_int32_t *tl;
 2153         int i;
 2154         struct nfsstate *stp = NULL;
 2155         struct nfslock *lop;
 2156         struct nfslockconflict cf;
 2157         int error = 0;
 2158         u_short flags = NFSLCK_LOCK, lflags;
 2159         u_int64_t offset, len;
 2160         nfsv4stateid_t stateid;
 2161         nfsquad_t clientid;
 2162 
 2163         NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
 2164         i = fxdr_unsigned(int, *tl++);
 2165         switch (i) {
 2166         case NFSV4LOCKT_READW:
 2167                 flags |= NFSLCK_BLOCKING;
 2168         case NFSV4LOCKT_READ:
 2169                 lflags = NFSLCK_READ;
 2170                 break;
 2171         case NFSV4LOCKT_WRITEW:
 2172                 flags |= NFSLCK_BLOCKING;
 2173         case NFSV4LOCKT_WRITE:
 2174                 lflags = NFSLCK_WRITE;
 2175                 break;
 2176         default:
 2177                 nd->nd_repstat = NFSERR_BADXDR;
 2178                 goto nfsmout;
 2179         };
 2180         if (*tl++ == newnfs_true)
 2181                 flags |= NFSLCK_RECLAIM;
 2182         offset = fxdr_hyper(tl);
 2183         tl += 2;
 2184         len = fxdr_hyper(tl);
 2185         tl += 2;
 2186         if (*tl == newnfs_true)
 2187                 flags |= NFSLCK_OPENTOLOCK;
 2188         if (flags & NFSLCK_OPENTOLOCK) {
 2189                 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
 2190                 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
 2191                 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
 2192                         nd->nd_repstat = NFSERR_BADXDR;
 2193                         goto nfsmout;
 2194                 }
 2195                 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
 2196                         M_NFSDSTATE, M_WAITOK);
 2197                 stp->ls_ownerlen = i;
 2198                 stp->ls_op = nd->nd_rp;
 2199                 stp->ls_seq = fxdr_unsigned(int, *tl++);
 2200                 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 2201                 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 2202                         NFSX_STATEIDOTHER);
 2203                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 2204                 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
 2205                 clientid.lval[0] = *tl++;
 2206                 clientid.lval[1] = *tl++;
 2207                 if (nd->nd_flag & ND_IMPLIEDCLID) {
 2208                         if (nd->nd_clientid.qval != clientid.qval)
 2209                                 printf("EEK! multiple clids\n");
 2210                 } else {
 2211                         nd->nd_flag |= ND_IMPLIEDCLID;
 2212                         nd->nd_clientid.qval = clientid.qval;
 2213                 }
 2214                 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
 2215                 if (error)
 2216                         goto nfsmout;
 2217         } else {
 2218                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
 2219                 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
 2220                         M_NFSDSTATE, M_WAITOK);
 2221                 stp->ls_ownerlen = 0;
 2222                 stp->ls_op = nd->nd_rp;
 2223                 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 2224                 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 2225                         NFSX_STATEIDOTHER);
 2226                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 2227                 stp->ls_seq = fxdr_unsigned(int, *tl);
 2228                 clientid.lval[0] = stp->ls_stateid.other[0];
 2229                 clientid.lval[1] = stp->ls_stateid.other[1];
 2230                 if (nd->nd_flag & ND_IMPLIEDCLID) {
 2231                         if (nd->nd_clientid.qval != clientid.qval)
 2232                                 printf("EEK! multiple clids\n");
 2233                 } else {
 2234                         nd->nd_flag |= ND_IMPLIEDCLID;
 2235                         nd->nd_clientid.qval = clientid.qval;
 2236                 }
 2237         }
 2238         MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
 2239                 M_NFSDLOCK, M_WAITOK);
 2240         lop->lo_first = offset;
 2241         if (len == NFS64BITSSET) {
 2242                 lop->lo_end = NFS64BITSSET;
 2243         } else {
 2244                 lop->lo_end = offset + len;
 2245                 if (lop->lo_end <= lop->lo_first)
 2246                         nd->nd_repstat = NFSERR_INVAL;
 2247         }
 2248         lop->lo_flags = lflags;
 2249         stp->ls_flags = flags;
 2250         stp->ls_uid = nd->nd_cred->cr_uid;
 2251 
 2252         /*
 2253          * Do basic access checking.
 2254          */
 2255         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
 2256             if (vnode_vtype(vp) == VDIR)
 2257                 nd->nd_repstat = NFSERR_ISDIR;
 2258             else
 2259                 nd->nd_repstat = NFSERR_INVAL;
 2260         }
 2261         if (!nd->nd_repstat) {
 2262             if (lflags & NFSLCK_WRITE) {
 2263                 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
 2264                     nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
 2265                     NFSACCCHK_VPISLOCKED, NULL);
 2266             } else {
 2267                 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
 2268                     nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
 2269                     NFSACCCHK_VPISLOCKED, NULL);
 2270                 if (nd->nd_repstat)
 2271                     nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
 2272                         nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
 2273                         NFSACCCHK_VPISLOCKED, NULL);
 2274             }
 2275         }
 2276 
 2277         /*
 2278          * We call nfsrv_lockctrl() even if nd_repstat set, so that the
 2279          * seqid# gets updated. nfsrv_lockctrl() will return the value
 2280          * of nd_repstat, if it gets that far.
 2281          */
 2282         nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 
 2283                 &stateid, exp, nd, p);
 2284         if (lop)
 2285                 FREE((caddr_t)lop, M_NFSDLOCK);
 2286         if (stp)
 2287                 FREE((caddr_t)stp, M_NFSDSTATE);
 2288         if (!nd->nd_repstat) {
 2289                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 2290                 *tl++ = txdr_unsigned(stateid.seqid);
 2291                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
 2292         } else if (nd->nd_repstat == NFSERR_DENIED) {
 2293                 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
 2294                 txdr_hyper(cf.cl_first, tl);
 2295                 tl += 2;
 2296                 if (cf.cl_end == NFS64BITSSET)
 2297                         len = NFS64BITSSET;
 2298                 else
 2299                         len = cf.cl_end - cf.cl_first;
 2300                 txdr_hyper(len, tl);
 2301                 tl += 2;
 2302                 if (cf.cl_flags == NFSLCK_WRITE)
 2303                         *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
 2304                 else
 2305                         *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
 2306                 *tl++ = stateid.other[0];
 2307                 *tl = stateid.other[1];
 2308                 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
 2309         }
 2310         vput(vp);
 2311         NFSEXITCODE2(0, nd);
 2312         return (0);
 2313 nfsmout:
 2314         vput(vp);
 2315         if (stp)
 2316                 free((caddr_t)stp, M_NFSDSTATE);
 2317         NFSEXITCODE2(error, nd);
 2318         return (error);
 2319 }
 2320 
 2321 /*
 2322  * nfsv4 lock test service
 2323  */
 2324 APPLESTATIC int
 2325 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
 2326     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
 2327 {
 2328         u_int32_t *tl;
 2329         int i;
 2330         struct nfsstate *stp = NULL;
 2331         struct nfslock lo, *lop = &lo;
 2332         struct nfslockconflict cf;
 2333         int error = 0;
 2334         nfsv4stateid_t stateid;
 2335         nfsquad_t clientid;
 2336         u_int64_t len;
 2337 
 2338         NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
 2339         i = fxdr_unsigned(int, *(tl + 7));
 2340         if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
 2341                 nd->nd_repstat = NFSERR_BADXDR;
 2342                 goto nfsmout;
 2343         }
 2344         MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
 2345             M_NFSDSTATE, M_WAITOK);
 2346         stp->ls_ownerlen = i;
 2347         stp->ls_op = NULL;
 2348         stp->ls_flags = NFSLCK_TEST;
 2349         stp->ls_uid = nd->nd_cred->cr_uid;
 2350         i = fxdr_unsigned(int, *tl++);
 2351         switch (i) {
 2352         case NFSV4LOCKT_READW:
 2353                 stp->ls_flags |= NFSLCK_BLOCKING;
 2354         case NFSV4LOCKT_READ:
 2355                 lo.lo_flags = NFSLCK_READ;
 2356                 break;
 2357         case NFSV4LOCKT_WRITEW:
 2358                 stp->ls_flags |= NFSLCK_BLOCKING;
 2359         case NFSV4LOCKT_WRITE:
 2360                 lo.lo_flags = NFSLCK_WRITE;
 2361                 break;
 2362         default:
 2363                 nd->nd_repstat = NFSERR_BADXDR;
 2364                 goto nfsmout;
 2365         };
 2366         lo.lo_first = fxdr_hyper(tl);
 2367         tl += 2;
 2368         len = fxdr_hyper(tl);
 2369         if (len == NFS64BITSSET) {
 2370                 lo.lo_end = NFS64BITSSET;
 2371         } else {
 2372                 lo.lo_end = lo.lo_first + len;
 2373                 if (lo.lo_end <= lo.lo_first)
 2374                         nd->nd_repstat = NFSERR_INVAL;
 2375         }
 2376         tl += 2;
 2377         clientid.lval[0] = *tl++;
 2378         clientid.lval[1] = *tl;
 2379         if (nd->nd_flag & ND_IMPLIEDCLID) {
 2380                 if (nd->nd_clientid.qval != clientid.qval)
 2381                         printf("EEK! multiple clids\n");
 2382         } else {
 2383                 nd->nd_flag |= ND_IMPLIEDCLID;
 2384                 nd->nd_clientid.qval = clientid.qval;
 2385         }
 2386         error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
 2387         if (error)
 2388                 goto nfsmout;
 2389         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
 2390             if (vnode_vtype(vp) == VDIR)
 2391                 nd->nd_repstat = NFSERR_ISDIR;
 2392             else
 2393                 nd->nd_repstat = NFSERR_INVAL;
 2394         }
 2395         if (!nd->nd_repstat)
 2396           nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
 2397             &stateid, exp, nd, p);
 2398         if (nd->nd_repstat) {
 2399             if (nd->nd_repstat == NFSERR_DENIED) {
 2400                 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
 2401                 txdr_hyper(cf.cl_first, tl);
 2402                 tl += 2;
 2403                 if (cf.cl_end == NFS64BITSSET)
 2404                         len = NFS64BITSSET;
 2405                 else
 2406                         len = cf.cl_end - cf.cl_first;
 2407                 txdr_hyper(len, tl);
 2408                 tl += 2;
 2409                 if (cf.cl_flags == NFSLCK_WRITE)
 2410                         *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
 2411                 else
 2412                         *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
 2413                 *tl++ = stp->ls_stateid.other[0];
 2414                 *tl = stp->ls_stateid.other[1];
 2415                 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
 2416             }
 2417         }
 2418         vput(vp);
 2419         if (stp)
 2420                 FREE((caddr_t)stp, M_NFSDSTATE);
 2421         NFSEXITCODE2(0, nd);
 2422         return (0);
 2423 nfsmout:
 2424         vput(vp);
 2425         if (stp)
 2426                 free((caddr_t)stp, M_NFSDSTATE);
 2427         NFSEXITCODE2(error, nd);
 2428         return (error);
 2429 }
 2430 
 2431 /*
 2432  * nfsv4 unlock service
 2433  */
 2434 APPLESTATIC int
 2435 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
 2436     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
 2437 {
 2438         u_int32_t *tl;
 2439         int i;
 2440         struct nfsstate *stp;
 2441         struct nfslock *lop;
 2442         int error = 0;
 2443         nfsv4stateid_t stateid;
 2444         nfsquad_t clientid;
 2445         u_int64_t len;
 2446 
 2447         NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
 2448         MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
 2449             M_NFSDSTATE, M_WAITOK);
 2450         MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
 2451             M_NFSDLOCK, M_WAITOK);
 2452         stp->ls_flags = NFSLCK_UNLOCK;
 2453         lop->lo_flags = NFSLCK_UNLOCK;
 2454         stp->ls_op = nd->nd_rp;
 2455         i = fxdr_unsigned(int, *tl++);
 2456         switch (i) {
 2457         case NFSV4LOCKT_READW:
 2458                 stp->ls_flags |= NFSLCK_BLOCKING;
 2459         case NFSV4LOCKT_READ:
 2460                 break;
 2461         case NFSV4LOCKT_WRITEW:
 2462                 stp->ls_flags |= NFSLCK_BLOCKING;
 2463         case NFSV4LOCKT_WRITE:
 2464                 break;
 2465         default:
 2466                 nd->nd_repstat = NFSERR_BADXDR;
 2467                 free(stp, M_NFSDSTATE);
 2468                 free(lop, M_NFSDLOCK);
 2469                 goto nfsmout;
 2470         };
 2471         stp->ls_ownerlen = 0;
 2472         stp->ls_uid = nd->nd_cred->cr_uid;
 2473         stp->ls_seq = fxdr_unsigned(int, *tl++);
 2474         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 2475         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 2476             NFSX_STATEIDOTHER);
 2477         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 2478         lop->lo_first = fxdr_hyper(tl);
 2479         tl += 2;
 2480         len = fxdr_hyper(tl);
 2481         if (len == NFS64BITSSET) {
 2482                 lop->lo_end = NFS64BITSSET;
 2483         } else {
 2484                 lop->lo_end = lop->lo_first + len;
 2485                 if (lop->lo_end <= lop->lo_first)
 2486                         nd->nd_repstat = NFSERR_INVAL;
 2487         }
 2488         clientid.lval[0] = stp->ls_stateid.other[0];
 2489         clientid.lval[1] = stp->ls_stateid.other[1];
 2490         if (nd->nd_flag & ND_IMPLIEDCLID) {
 2491                 if (nd->nd_clientid.qval != clientid.qval)
 2492                         printf("EEK! multiple clids\n");
 2493         } else {
 2494                 nd->nd_flag |= ND_IMPLIEDCLID;
 2495                 nd->nd_clientid.qval = clientid.qval;
 2496         }
 2497         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
 2498             if (vnode_vtype(vp) == VDIR)
 2499                 nd->nd_repstat = NFSERR_ISDIR;
 2500             else
 2501                 nd->nd_repstat = NFSERR_INVAL;
 2502         }
 2503         /*
 2504          * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
 2505          * seqid# gets incremented. nfsrv_lockctrl() will return the
 2506          * value of nd_repstat, if it gets that far.
 2507          */
 2508         nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
 2509             &stateid, exp, nd, p);
 2510         if (stp)
 2511                 FREE((caddr_t)stp, M_NFSDSTATE);
 2512         if (lop)
 2513                 free((caddr_t)lop, M_NFSDLOCK);
 2514         if (!nd->nd_repstat) {
 2515                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 2516                 *tl++ = txdr_unsigned(stateid.seqid);
 2517                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
 2518         }
 2519 nfsmout:
 2520         vput(vp);
 2521         NFSEXITCODE2(error, nd);
 2522         return (error);
 2523 }
 2524 
 2525 /*
 2526  * nfsv4 open service
 2527  */
 2528 APPLESTATIC int
 2529 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
 2530     vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
 2531     struct nfsexstuff *exp)
 2532 {
 2533         u_int32_t *tl;
 2534         int i;
 2535         struct nfsstate *stp = NULL;
 2536         int error = 0, create, claim, exclusive_flag = 0;
 2537         u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
 2538         int how = NFSCREATE_UNCHECKED;
 2539         int32_t cverf[2], tverf[2] = { 0, 0 };
 2540         vnode_t vp = NULL, dirp = NULL;
 2541         struct nfsvattr nva, dirfor, diraft;
 2542         struct nameidata named;
 2543         nfsv4stateid_t stateid, delegstateid;
 2544         nfsattrbit_t attrbits;
 2545         nfsquad_t clientid;
 2546         char *bufp = NULL;
 2547         u_long *hashp;
 2548         NFSACL_T *aclp = NULL;
 2549 
 2550 #ifdef NFS4_ACL_EXTATTR_NAME
 2551         aclp = acl_alloc(M_WAITOK);
 2552         aclp->acl_cnt = 0;
 2553 #endif
 2554         NFSZERO_ATTRBIT(&attrbits);
 2555         named.ni_startdir = NULL;
 2556         named.ni_cnd.cn_nameiop = 0;
 2557         NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
 2558         i = fxdr_unsigned(int, *(tl + 5));
 2559         if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
 2560                 nd->nd_repstat = NFSERR_BADXDR;
 2561                 goto nfsmout;
 2562         }
 2563         MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
 2564             M_NFSDSTATE, M_WAITOK);
 2565         stp->ls_ownerlen = i;
 2566         stp->ls_op = nd->nd_rp;
 2567         stp->ls_flags = NFSLCK_OPEN;
 2568         stp->ls_uid = nd->nd_cred->cr_uid;
 2569         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
 2570         i = fxdr_unsigned(int, *tl++);
 2571         switch (i) {
 2572         case NFSV4OPEN_ACCESSREAD:
 2573                 stp->ls_flags |= NFSLCK_READACCESS;
 2574                 break;
 2575         case NFSV4OPEN_ACCESSWRITE:
 2576                 stp->ls_flags |= NFSLCK_WRITEACCESS;
 2577                 break;
 2578         case NFSV4OPEN_ACCESSBOTH:
 2579                 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
 2580                 break;
 2581         default:
 2582                 nd->nd_repstat = NFSERR_INVAL;
 2583         };
 2584         i = fxdr_unsigned(int, *tl++);
 2585         switch (i) {
 2586         case NFSV4OPEN_DENYNONE:
 2587                 break;
 2588         case NFSV4OPEN_DENYREAD:
 2589                 stp->ls_flags |= NFSLCK_READDENY;
 2590                 break;
 2591         case NFSV4OPEN_DENYWRITE:
 2592                 stp->ls_flags |= NFSLCK_WRITEDENY;
 2593                 break;
 2594         case NFSV4OPEN_DENYBOTH:
 2595                 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
 2596                 break;
 2597         default:
 2598                 nd->nd_repstat = NFSERR_INVAL;
 2599         };
 2600         clientid.lval[0] = *tl++;
 2601         clientid.lval[1] = *tl;
 2602         if (nd->nd_flag & ND_IMPLIEDCLID) {
 2603                 if (nd->nd_clientid.qval != clientid.qval)
 2604                         printf("EEK! multiple clids\n");
 2605         } else {
 2606                 nd->nd_flag |= ND_IMPLIEDCLID;
 2607                 nd->nd_clientid.qval = clientid.qval;
 2608         }
 2609         error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
 2610         if (error)
 2611                 goto nfsmout;
 2612         NFSVNO_ATTRINIT(&nva);
 2613         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2614         create = fxdr_unsigned(int, *tl);
 2615         if (!nd->nd_repstat)
 2616                 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
 2617         if (create == NFSV4OPEN_CREATE) {
 2618                 nva.na_type = VREG;
 2619                 nva.na_mode = 0;
 2620                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2621                 how = fxdr_unsigned(int, *tl);
 2622                 switch (how) {
 2623                 case NFSCREATE_UNCHECKED:
 2624                 case NFSCREATE_GUARDED:
 2625                         error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
 2626                         if (error)
 2627                                 goto nfsmout;
 2628                         /*
 2629                          * If the na_gid being set is the same as that of
 2630                          * the directory it is going in, clear it, since
 2631                          * that is what will be set by default. This allows
 2632                          * a user that isn't in that group to do the create.
 2633                          */
 2634                         if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
 2635                             nva.na_gid == dirfor.na_gid)
 2636                                 NFSVNO_UNSET(&nva, gid);
 2637                         if (!nd->nd_repstat)
 2638                                 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
 2639                         break;
 2640                 case NFSCREATE_EXCLUSIVE:
 2641                         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
 2642                         cverf[0] = *tl++;
 2643                         cverf[1] = *tl;
 2644                         break;
 2645                 default:
 2646                         nd->nd_repstat = NFSERR_BADXDR;
 2647                         goto nfsmout;
 2648                 };
 2649         } else if (create != NFSV4OPEN_NOCREATE) {
 2650                 nd->nd_repstat = NFSERR_BADXDR;
 2651                 goto nfsmout;
 2652         }
 2653 
 2654         /*
 2655          * Now, handle the claim, which usually includes looking up a
 2656          * name in the directory referenced by dp. The exception is
 2657          * NFSV4OPEN_CLAIMPREVIOUS.
 2658          */
 2659         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2660         claim = fxdr_unsigned(int, *tl);
 2661         if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
 2662                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
 2663                 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 2664                 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
 2665                 stp->ls_flags |= NFSLCK_DELEGCUR;
 2666         } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
 2667                 stp->ls_flags |= NFSLCK_DELEGPREV;
 2668         }
 2669         if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
 2670             || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
 2671                 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
 2672                     claim != NFSV4OPEN_CLAIMNULL)
 2673                         nd->nd_repstat = NFSERR_INVAL;
 2674                 if (nd->nd_repstat) {
 2675                         nd->nd_repstat = nfsrv_opencheck(clientid,
 2676                             &stateid, stp, NULL, nd, p, nd->nd_repstat);
 2677                         goto nfsmout;
 2678                 }
 2679                 if (create == NFSV4OPEN_CREATE)
 2680                     NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
 2681                         LOCKPARENT | LOCKLEAF | SAVESTART);
 2682                 else
 2683                     NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
 2684                         LOCKLEAF | SAVESTART);
 2685                 nfsvno_setpathbuf(&named, &bufp, &hashp);
 2686                 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
 2687                 if (error) {
 2688                         vrele(dp);
 2689 #ifdef NFS4_ACL_EXTATTR_NAME
 2690                         acl_free(aclp);
 2691 #endif
 2692                         FREE((caddr_t)stp, M_NFSDSTATE);
 2693                         nfsvno_relpathbuf(&named);
 2694                         NFSEXITCODE2(error, nd);
 2695                         return (error);
 2696                 }
 2697                 if (!nd->nd_repstat) {
 2698                         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
 2699                             p, &dirp);
 2700                 } else {
 2701                         vrele(dp);
 2702                         nfsvno_relpathbuf(&named);
 2703                 }
 2704                 if (create == NFSV4OPEN_CREATE) {
 2705                     switch (how) {
 2706                     case NFSCREATE_UNCHECKED:
 2707                         if (named.ni_vp) {
 2708                                 /*
 2709                                  * Clear the setable attribute bits, except
 2710                                  * for Size, if it is being truncated.
 2711                                  */
 2712                                 NFSZERO_ATTRBIT(&attrbits);
 2713                                 if (NFSVNO_ISSETSIZE(&nva))
 2714                                         NFSSETBIT_ATTRBIT(&attrbits,
 2715                                             NFSATTRBIT_SIZE);
 2716                         }
 2717                         break;
 2718                     case NFSCREATE_GUARDED:
 2719                         if (named.ni_vp && !nd->nd_repstat)
 2720                                 nd->nd_repstat = EEXIST;
 2721                         break;
 2722                     case NFSCREATE_EXCLUSIVE:
 2723                         exclusive_flag = 1;
 2724                         if (!named.ni_vp)
 2725                                 nva.na_mode = 0;
 2726                     };
 2727                 }
 2728                 nfsvno_open(nd, &named, clientid, &stateid, stp,
 2729                     &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
 2730                     nd->nd_cred, p, exp, &vp);
 2731         } else if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
 2732                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2733                 i = fxdr_unsigned(int, *tl);
 2734                 switch (i) {
 2735                 case NFSV4OPEN_DELEGATEREAD:
 2736                         stp->ls_flags |= NFSLCK_DELEGREAD;
 2737                         break;
 2738                 case NFSV4OPEN_DELEGATEWRITE:
 2739                         stp->ls_flags |= NFSLCK_DELEGWRITE;
 2740                 case NFSV4OPEN_DELEGATENONE:
 2741                         break;
 2742                 default:
 2743                         nd->nd_repstat = NFSERR_BADXDR;
 2744                         goto nfsmout;
 2745                 };
 2746                 stp->ls_flags |= NFSLCK_RECLAIM;
 2747                 vp = dp;
 2748                 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
 2749                 if ((vp->v_iflag & VI_DOOMED) == 0)
 2750                         nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
 2751                             stp, vp, nd, p, nd->nd_repstat);
 2752                 else
 2753                         nd->nd_repstat = NFSERR_PERM;
 2754         } else {
 2755                 nd->nd_repstat = NFSERR_BADXDR;
 2756                 goto nfsmout;
 2757         }
 2758 
 2759         /*
 2760          * Do basic access checking.
 2761          */
 2762         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
 2763                 /*
 2764                  * The IETF working group decided that this is the correct
 2765                  * error return for all non-regular files.
 2766                  */
 2767                 nd->nd_repstat = NFSERR_SYMLINK;
 2768         }
 2769         if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
 2770             nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
 2771                 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
 2772         if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
 2773             nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
 2774                 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
 2775             if (nd->nd_repstat)
 2776                 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
 2777                     nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
 2778                     NFSACCCHK_VPISLOCKED, NULL);
 2779         }
 2780 
 2781         if (!nd->nd_repstat) {
 2782                 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
 2783                 if (!nd->nd_repstat) {
 2784                         tverf[0] = nva.na_atime.tv_sec;
 2785                         tverf[1] = nva.na_atime.tv_nsec;
 2786                 }
 2787         }
 2788         if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
 2789             cverf[1] != tverf[1]))
 2790                 nd->nd_repstat = EEXIST;
 2791         /*
 2792          * Do the open locking/delegation stuff.
 2793          */
 2794         if (!nd->nd_repstat)
 2795             nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
 2796                 &delegstateid, &rflags, exp, p, nva.na_filerev);
 2797 
 2798         /*
 2799          * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
 2800          * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
 2801          * (ie: Leave the NFSVOPUNLOCK() about here.)
 2802          */
 2803         if (vp)
 2804                 NFSVOPUNLOCK(vp, 0);
 2805         if (stp)
 2806                 FREE((caddr_t)stp, M_NFSDSTATE);
 2807         if (!nd->nd_repstat && dirp)
 2808                 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
 2809                     0);
 2810         if (!nd->nd_repstat) {
 2811                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
 2812                 *tl++ = txdr_unsigned(stateid.seqid);
 2813                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
 2814                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 2815                 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
 2816                         *tl++ = newnfs_true;
 2817                         *tl++ = 0;
 2818                         *tl++ = 0;
 2819                         *tl++ = 0;
 2820                         *tl++ = 0;
 2821                 } else {
 2822                         *tl++ = newnfs_false;   /* Since dirp is not locked */
 2823                         txdr_hyper(dirfor.na_filerev, tl);
 2824                         tl += 2;
 2825                         txdr_hyper(diraft.na_filerev, tl);
 2826                         tl += 2;
 2827                 }
 2828                 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
 2829                 (void) nfsrv_putattrbit(nd, &attrbits);
 2830                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2831                 if (rflags & NFSV4OPEN_READDELEGATE)
 2832                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
 2833                 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
 2834                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
 2835                 else
 2836                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
 2837                 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
 2838                         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
 2839                         *tl++ = txdr_unsigned(delegstateid.seqid);
 2840                         NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
 2841                             NFSX_STATEIDOTHER);
 2842                         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 2843                         if (rflags & NFSV4OPEN_RECALL)
 2844                                 *tl = newnfs_true;
 2845                         else
 2846                                 *tl = newnfs_false;
 2847                         if (rflags & NFSV4OPEN_WRITEDELEGATE) {
 2848                                 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 2849                                 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
 2850                                 txdr_hyper(nva.na_size, tl);
 2851                         }
 2852                         NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 2853                         *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
 2854                         *tl++ = txdr_unsigned(0x0);
 2855                         acemask = NFSV4ACE_ALLFILESMASK;
 2856                         if (nva.na_mode & S_IRUSR)
 2857                             acemask |= NFSV4ACE_READMASK;
 2858                         if (nva.na_mode & S_IWUSR)
 2859                             acemask |= NFSV4ACE_WRITEMASK;
 2860                         if (nva.na_mode & S_IXUSR)
 2861                             acemask |= NFSV4ACE_EXECUTEMASK;
 2862                         *tl = txdr_unsigned(acemask);
 2863                         (void) nfsm_strtom(nd, "OWNER@", 6);
 2864                 }
 2865                 *vpp = vp;
 2866         } else if (vp) {
 2867                 vrele(vp);
 2868         }
 2869         if (dirp)
 2870                 vrele(dirp);
 2871 #ifdef NFS4_ACL_EXTATTR_NAME
 2872         acl_free(aclp);
 2873 #endif
 2874         NFSEXITCODE2(0, nd);
 2875         return (0);
 2876 nfsmout:
 2877         vrele(dp);
 2878 #ifdef NFS4_ACL_EXTATTR_NAME
 2879         acl_free(aclp);
 2880 #endif
 2881         if (stp)
 2882                 FREE((caddr_t)stp, M_NFSDSTATE);
 2883         NFSEXITCODE2(error, nd);
 2884         return (error);
 2885 }
 2886 
 2887 /*
 2888  * nfsv4 close service
 2889  */
 2890 APPLESTATIC int
 2891 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
 2892     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 2893 {
 2894         u_int32_t *tl;
 2895         struct nfsstate st, *stp = &st;
 2896         int error = 0;
 2897         nfsv4stateid_t stateid;
 2898         nfsquad_t clientid;
 2899 
 2900         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
 2901         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
 2902         stp->ls_ownerlen = 0;
 2903         stp->ls_op = nd->nd_rp;
 2904         stp->ls_uid = nd->nd_cred->cr_uid;
 2905         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 2906         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 2907             NFSX_STATEIDOTHER);
 2908         stp->ls_flags = NFSLCK_CLOSE;
 2909         clientid.lval[0] = stp->ls_stateid.other[0];
 2910         clientid.lval[1] = stp->ls_stateid.other[1];
 2911         if (nd->nd_flag & ND_IMPLIEDCLID) {
 2912                 if (nd->nd_clientid.qval != clientid.qval)
 2913                         printf("EEK! multiple clids\n");
 2914         } else {
 2915                 nd->nd_flag |= ND_IMPLIEDCLID;
 2916                 nd->nd_clientid.qval = clientid.qval;
 2917         }
 2918         nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
 2919         vput(vp);
 2920         if (!nd->nd_repstat) {
 2921                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 2922                 *tl++ = txdr_unsigned(stateid.seqid);
 2923                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
 2924         }
 2925         NFSEXITCODE2(0, nd);
 2926         return (0);
 2927 nfsmout:
 2928         vput(vp);
 2929         NFSEXITCODE2(error, nd);
 2930         return (error);
 2931 }
 2932 
 2933 /*
 2934  * nfsv4 delegpurge service
 2935  */
 2936 APPLESTATIC int
 2937 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
 2938     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
 2939 {
 2940         u_int32_t *tl;
 2941         int error = 0;
 2942         nfsquad_t clientid;
 2943 
 2944         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
 2945                 nd->nd_repstat = NFSERR_WRONGSEC;
 2946                 goto nfsmout;
 2947         }
 2948         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2949         clientid.lval[0] = *tl++;
 2950         clientid.lval[1] = *tl;
 2951         if (nd->nd_flag & ND_IMPLIEDCLID) {
 2952                 if (nd->nd_clientid.qval != clientid.qval)
 2953                         printf("EEK! multiple clids\n");
 2954         } else {
 2955                 nd->nd_flag |= ND_IMPLIEDCLID;
 2956                 nd->nd_clientid.qval = clientid.qval;
 2957         }
 2958         nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL,
 2959             NFSV4OP_DELEGPURGE, nd->nd_cred, p);
 2960 nfsmout:
 2961         NFSEXITCODE2(error, nd);
 2962         return (error);
 2963 }
 2964 
 2965 /*
 2966  * nfsv4 delegreturn service
 2967  */
 2968 APPLESTATIC int
 2969 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
 2970     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 2971 {
 2972         u_int32_t *tl;
 2973         int error = 0;
 2974         nfsv4stateid_t stateid;
 2975         nfsquad_t clientid;
 2976 
 2977         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
 2978         stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 2979         NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
 2980         clientid.lval[0] = stateid.other[0];
 2981         clientid.lval[1] = stateid.other[1];
 2982         if (nd->nd_flag & ND_IMPLIEDCLID) {
 2983                 if (nd->nd_clientid.qval != clientid.qval)
 2984                         printf("EEK! multiple clids\n");
 2985         } else {
 2986                 nd->nd_flag |= ND_IMPLIEDCLID;
 2987                 nd->nd_clientid.qval = clientid.qval;
 2988         }
 2989         nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp,
 2990             NFSV4OP_DELEGRETURN, nd->nd_cred, p);
 2991 nfsmout:
 2992         vput(vp);
 2993         NFSEXITCODE2(error, nd);
 2994         return (error);
 2995 }
 2996 
 2997 /*
 2998  * nfsv4 get file handle service
 2999  */
 3000 APPLESTATIC int
 3001 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
 3002     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 3003 {
 3004         fhandle_t fh;
 3005 
 3006         nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
 3007         vput(vp);
 3008         if (!nd->nd_repstat)
 3009                 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
 3010         NFSEXITCODE2(0, nd);
 3011         return (0);
 3012 }
 3013 
 3014 /*
 3015  * nfsv4 open confirm service
 3016  */
 3017 APPLESTATIC int
 3018 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
 3019     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 3020 {
 3021         u_int32_t *tl;
 3022         struct nfsstate st, *stp = &st;
 3023         int error = 0;
 3024         nfsv4stateid_t stateid;
 3025         nfsquad_t clientid;
 3026 
 3027         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
 3028         stp->ls_ownerlen = 0;
 3029         stp->ls_op = nd->nd_rp;
 3030         stp->ls_uid = nd->nd_cred->cr_uid;
 3031         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 3032         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 3033             NFSX_STATEIDOTHER);
 3034         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 3035         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
 3036         stp->ls_flags = NFSLCK_CONFIRM;
 3037         clientid.lval[0] = stp->ls_stateid.other[0];
 3038         clientid.lval[1] = stp->ls_stateid.other[1];
 3039         if (nd->nd_flag & ND_IMPLIEDCLID) {
 3040                 if (nd->nd_clientid.qval != clientid.qval)
 3041                         printf("EEK! multiple clids\n");
 3042         } else {
 3043                 nd->nd_flag |= ND_IMPLIEDCLID;
 3044                 nd->nd_clientid.qval = clientid.qval;
 3045         }
 3046         nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
 3047         if (!nd->nd_repstat) {
 3048                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 3049                 *tl++ = txdr_unsigned(stateid.seqid);
 3050                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
 3051         }
 3052 nfsmout:
 3053         vput(vp);
 3054         NFSEXITCODE2(error, nd);
 3055         return (error);
 3056 }
 3057 
 3058 /*
 3059  * nfsv4 open downgrade service
 3060  */
 3061 APPLESTATIC int
 3062 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
 3063     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 3064 {
 3065         u_int32_t *tl;
 3066         int i;
 3067         struct nfsstate st, *stp = &st;
 3068         int error = 0;
 3069         nfsv4stateid_t stateid;
 3070         nfsquad_t clientid;
 3071 
 3072         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
 3073         stp->ls_ownerlen = 0;
 3074         stp->ls_op = nd->nd_rp;
 3075         stp->ls_uid = nd->nd_cred->cr_uid;
 3076         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 3077         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 3078             NFSX_STATEIDOTHER);
 3079         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 3080         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
 3081         i = fxdr_unsigned(int, *tl++);
 3082         switch (i) {
 3083         case NFSV4OPEN_ACCESSREAD:
 3084                 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
 3085                 break;
 3086         case NFSV4OPEN_ACCESSWRITE:
 3087                 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
 3088                 break;
 3089         case NFSV4OPEN_ACCESSBOTH:
 3090                 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
 3091                     NFSLCK_DOWNGRADE);
 3092                 break;
 3093         default:
 3094                 nd->nd_repstat = NFSERR_BADXDR;
 3095         };
 3096         i = fxdr_unsigned(int, *tl);
 3097         switch (i) {
 3098         case NFSV4OPEN_DENYNONE:
 3099                 break;
 3100         case NFSV4OPEN_DENYREAD:
 3101                 stp->ls_flags |= NFSLCK_READDENY;
 3102                 break;
 3103         case NFSV4OPEN_DENYWRITE:
 3104                 stp->ls_flags |= NFSLCK_WRITEDENY;
 3105                 break;
 3106         case NFSV4OPEN_DENYBOTH:
 3107                 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
 3108                 break;
 3109         default:
 3110                 nd->nd_repstat = NFSERR_BADXDR;
 3111         };
 3112 
 3113         clientid.lval[0] = stp->ls_stateid.other[0];
 3114         clientid.lval[1] = stp->ls_stateid.other[1];
 3115         if (nd->nd_flag & ND_IMPLIEDCLID) {
 3116                 if (nd->nd_clientid.qval != clientid.qval)
 3117                         printf("EEK! multiple clids\n");
 3118         } else {
 3119                 nd->nd_flag |= ND_IMPLIEDCLID;
 3120                 nd->nd_clientid.qval = clientid.qval;
 3121         }
 3122         if (!nd->nd_repstat)
 3123                 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
 3124                     nd, p);
 3125         if (!nd->nd_repstat) {
 3126                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 3127                 *tl++ = txdr_unsigned(stateid.seqid);
 3128                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
 3129         }
 3130 nfsmout:
 3131         vput(vp);
 3132         NFSEXITCODE2(error, nd);
 3133         return (error);
 3134 }
 3135 
 3136 /*
 3137  * nfsv4 renew lease service
 3138  */
 3139 APPLESTATIC int
 3140 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
 3141     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 3142 {
 3143         u_int32_t *tl;
 3144         int error = 0;
 3145         nfsquad_t clientid;
 3146 
 3147         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
 3148                 nd->nd_repstat = NFSERR_WRONGSEC;
 3149                 goto nfsmout;
 3150         }
 3151         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 3152         clientid.lval[0] = *tl++;
 3153         clientid.lval[1] = *tl;
 3154         if (nd->nd_flag & ND_IMPLIEDCLID) {
 3155                 if (nd->nd_clientid.qval != clientid.qval)
 3156                         printf("EEK! multiple clids\n");
 3157         } else {
 3158                 nd->nd_flag |= ND_IMPLIEDCLID;
 3159                 nd->nd_clientid.qval = clientid.qval;
 3160         }
 3161         nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
 3162             NULL, (nfsquad_t)((u_quad_t)0), nd, p);
 3163 nfsmout:
 3164         NFSEXITCODE2(error, nd);
 3165         return (error);
 3166 }
 3167 
 3168 /*
 3169  * nfsv4 security info service
 3170  */
 3171 APPLESTATIC int
 3172 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
 3173     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
 3174 {
 3175         u_int32_t *tl;
 3176         int len;
 3177         struct nameidata named;
 3178         vnode_t dirp = NULL, vp;
 3179         struct nfsrvfh fh;
 3180         struct nfsexstuff retnes;
 3181         u_int32_t *sizp;
 3182         int error = 0, savflag, i;
 3183         char *bufp;
 3184         u_long *hashp;
 3185 
 3186         /*
 3187          * All this just to get the export flags for the name.
 3188          */
 3189         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
 3190             LOCKLEAF | SAVESTART);
 3191         nfsvno_setpathbuf(&named, &bufp, &hashp);
 3192         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
 3193         if (error) {
 3194                 vput(dp);
 3195                 nfsvno_relpathbuf(&named);
 3196                 goto out;
 3197         }
 3198         if (!nd->nd_repstat) {
 3199                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
 3200         } else {
 3201                 vput(dp);
 3202                 nfsvno_relpathbuf(&named);
 3203         }
 3204         if (dirp)
 3205                 vrele(dirp);
 3206         if (nd->nd_repstat)
 3207                 goto out;
 3208         vrele(named.ni_startdir);
 3209         nfsvno_relpathbuf(&named);
 3210         fh.nfsrvfh_len = NFSX_MYFH;
 3211         vp = named.ni_vp;
 3212         nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
 3213         vput(vp);
 3214         savflag = nd->nd_flag;
 3215         if (!nd->nd_repstat) {
 3216                 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p);
 3217                 if (vp)
 3218                         vput(vp);
 3219         }
 3220         nd->nd_flag = savflag;
 3221         if (nd->nd_repstat)
 3222                 goto out;
 3223 
 3224         /*
 3225          * Finally have the export flags for name, so we can create
 3226          * the security info.
 3227          */
 3228         len = 0;
 3229         NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
 3230         for (i = 0; i < retnes.nes_numsecflavor; i++) {
 3231                 if (retnes.nes_secflavors[i] == AUTH_SYS) {
 3232                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3233                         *tl = txdr_unsigned(RPCAUTH_UNIX);
 3234                         len++;
 3235                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
 3236                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3237                         *tl++ = txdr_unsigned(RPCAUTH_GSS);
 3238                         (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
 3239                             nfsgss_mechlist[KERBV_MECH].len);
 3240                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 3241                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
 3242                         *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
 3243                         len++;
 3244                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
 3245                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3246                         *tl++ = txdr_unsigned(RPCAUTH_GSS);
 3247                         (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
 3248                             nfsgss_mechlist[KERBV_MECH].len);
 3249                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 3250                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
 3251                         *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
 3252                         len++;
 3253                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
 3254                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3255                         *tl++ = txdr_unsigned(RPCAUTH_GSS);
 3256                         (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
 3257                             nfsgss_mechlist[KERBV_MECH].len);
 3258                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 3259                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
 3260                         *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
 3261                         len++;
 3262                 }
 3263         }
 3264         *sizp = txdr_unsigned(len);
 3265 
 3266 out:
 3267         NFSEXITCODE2(error, nd);
 3268         return (error);
 3269 }
 3270 
 3271 /*
 3272  * nfsv4 set client id service
 3273  */
 3274 APPLESTATIC int
 3275 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
 3276     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 3277 {
 3278         u_int32_t *tl;
 3279         int i;
 3280         int error = 0, idlen;
 3281         struct nfsclient *clp = NULL;
 3282         struct sockaddr_in *rad;
 3283         u_char *verf, *ucp, *ucp2, addrbuf[24];
 3284         nfsquad_t clientid, confirm;
 3285 
 3286         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
 3287                 nd->nd_repstat = NFSERR_WRONGSEC;
 3288                 goto out;
 3289         }
 3290         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
 3291         verf = (u_char *)tl;
 3292         tl += (NFSX_VERF / NFSX_UNSIGNED);
 3293         i = fxdr_unsigned(int, *tl);
 3294         if (i > NFSV4_OPAQUELIMIT || i <= 0) {
 3295                 nd->nd_repstat = NFSERR_BADXDR;
 3296                 goto nfsmout;
 3297         }
 3298         idlen = i;
 3299         if (nd->nd_flag & ND_GSS)
 3300                 i += nd->nd_princlen;
 3301         MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i,
 3302             M_NFSDCLIENT, M_WAITOK);
 3303         NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i);
 3304         NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
 3305         NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
 3306         NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
 3307         clp->lc_req.nr_cred = NULL;
 3308         NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
 3309         clp->lc_idlen = idlen;
 3310         error = nfsrv_mtostr(nd, clp->lc_id, idlen);
 3311         if (error)
 3312                 goto nfsmout;
 3313         if (nd->nd_flag & ND_GSS) {
 3314                 clp->lc_flags = LCL_GSS;
 3315                 if (nd->nd_flag & ND_GSSINTEGRITY)
 3316                         clp->lc_flags |= LCL_GSSINTEGRITY;
 3317                 else if (nd->nd_flag & ND_GSSPRIVACY)
 3318                         clp->lc_flags |= LCL_GSSPRIVACY;
 3319         } else {
 3320                 clp->lc_flags = 0;
 3321         }
 3322         if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
 3323                 clp->lc_flags |= LCL_NAME;
 3324                 clp->lc_namelen = nd->nd_princlen;
 3325                 clp->lc_name = &clp->lc_id[idlen];
 3326                 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
 3327         } else {
 3328                 clp->lc_uid = nd->nd_cred->cr_uid;
 3329                 clp->lc_gid = nd->nd_cred->cr_gid;
 3330         }
 3331         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3332         clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
 3333         error = nfsrv_getclientipaddr(nd, clp);
 3334         if (error)
 3335                 goto nfsmout;
 3336         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3337         clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
 3338 
 3339         /*
 3340          * nfsrv_setclient() does the actual work of adding it to the
 3341          * client list. If there is no error, the structure has been
 3342          * linked into the client list and clp should no longer be used
 3343          * here. When an error is returned, it has not been linked in,
 3344          * so it should be free'd.
 3345          */
 3346         nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
 3347         if (nd->nd_repstat == NFSERR_CLIDINUSE) {
 3348                 if (clp->lc_flags & LCL_TCPCALLBACK)
 3349                         (void) nfsm_strtom(nd, "tcp", 3);
 3350                 else 
 3351                         (void) nfsm_strtom(nd, "udp", 3);
 3352                 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
 3353                 ucp = (u_char *)&rad->sin_addr.s_addr;
 3354                 ucp2 = (u_char *)&rad->sin_port;
 3355                 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
 3356                     ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
 3357                     ucp2[0] & 0xff, ucp2[1] & 0xff);
 3358                 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
 3359         }
 3360         if (clp) {
 3361                 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
 3362                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
 3363                 free((caddr_t)clp, M_NFSDCLIENT);
 3364         }
 3365         if (!nd->nd_repstat) {
 3366                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
 3367                 *tl++ = clientid.lval[0];
 3368                 *tl++ = clientid.lval[1];
 3369                 *tl++ = confirm.lval[0];
 3370                 *tl = confirm.lval[1];
 3371         }
 3372 
 3373 out:
 3374         NFSEXITCODE2(0, nd);
 3375         return (0);
 3376 nfsmout:
 3377         if (clp) {
 3378                 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
 3379                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
 3380                 free((caddr_t)clp, M_NFSDCLIENT);
 3381         }
 3382         NFSEXITCODE2(error, nd);
 3383         return (error);
 3384 }
 3385 
 3386 /*
 3387  * nfsv4 set client id confirm service
 3388  */
 3389 APPLESTATIC int
 3390 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
 3391     __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
 3392     __unused struct nfsexstuff *exp)
 3393 {
 3394         u_int32_t *tl;
 3395         int error = 0;
 3396         nfsquad_t clientid, confirm;
 3397 
 3398         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
 3399                 nd->nd_repstat = NFSERR_WRONGSEC;
 3400                 goto nfsmout;
 3401         }
 3402         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
 3403         clientid.lval[0] = *tl++;
 3404         clientid.lval[1] = *tl++;
 3405         confirm.lval[0] = *tl++;
 3406         confirm.lval[1] = *tl;
 3407 
 3408         /*
 3409          * nfsrv_getclient() searches the client list for a match and
 3410          * returns the appropriate NFSERR status.
 3411          */
 3412         nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
 3413             NULL, confirm, nd, p);
 3414 nfsmout:
 3415         NFSEXITCODE2(error, nd);
 3416         return (error);
 3417 }
 3418 
 3419 /*
 3420  * nfsv4 verify service
 3421  */
 3422 APPLESTATIC int
 3423 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
 3424     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 3425 {
 3426         int error = 0, ret, fhsize = NFSX_MYFH;
 3427         struct nfsvattr nva;
 3428         struct statfs sf;
 3429         struct nfsfsinfo fs;
 3430         fhandle_t fh;
 3431 
 3432         nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
 3433         if (!nd->nd_repstat)
 3434                 nd->nd_repstat = nfsvno_statfs(vp, &sf);
 3435         if (!nd->nd_repstat)
 3436                 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
 3437         if (!nd->nd_repstat) {
 3438                 nfsvno_getfs(&fs, isdgram);
 3439                 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
 3440                     &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
 3441                 if (!error) {
 3442                         if (nd->nd_procnum == NFSV4OP_NVERIFY) {
 3443                                 if (ret == 0)
 3444                                         nd->nd_repstat = NFSERR_SAME;
 3445                                 else if (ret != NFSERR_NOTSAME)
 3446                                         nd->nd_repstat = ret;
 3447                         } else if (ret)
 3448                                 nd->nd_repstat = ret;
 3449                 }
 3450         }
 3451         vput(vp);
 3452         NFSEXITCODE2(error, nd);
 3453         return (error);
 3454 }
 3455 
 3456 /*
 3457  * nfs openattr rpc
 3458  */
 3459 APPLESTATIC int
 3460 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
 3461     vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
 3462     __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
 3463 {
 3464         u_int32_t *tl;
 3465         int error = 0, createdir;
 3466 
 3467         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3468         createdir = fxdr_unsigned(int, *tl);
 3469         nd->nd_repstat = NFSERR_NOTSUPP;
 3470 nfsmout:
 3471         vrele(dp);
 3472         NFSEXITCODE2(error, nd);
 3473         return (error);
 3474 }
 3475 
 3476 /*
 3477  * nfsv4 release lock owner service
 3478  */
 3479 APPLESTATIC int
 3480 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
 3481     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 3482 {
 3483         u_int32_t *tl;
 3484         struct nfsstate *stp = NULL;
 3485         int error = 0, len;
 3486         nfsquad_t clientid;
 3487 
 3488         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
 3489                 nd->nd_repstat = NFSERR_WRONGSEC;
 3490                 goto nfsmout;
 3491         }
 3492         NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 3493         len = fxdr_unsigned(int, *(tl + 2));
 3494         if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
 3495                 nd->nd_repstat = NFSERR_BADXDR;
 3496                 goto nfsmout;
 3497         }
 3498         MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
 3499             M_NFSDSTATE, M_WAITOK);
 3500         stp->ls_ownerlen = len;
 3501         stp->ls_op = NULL;
 3502         stp->ls_flags = NFSLCK_RELEASE;
 3503         stp->ls_uid = nd->nd_cred->cr_uid;
 3504         clientid.lval[0] = *tl++;
 3505         clientid.lval[1] = *tl;
 3506         if (nd->nd_flag & ND_IMPLIEDCLID) {
 3507                 if (nd->nd_clientid.qval != clientid.qval)
 3508                         printf("EEK! multiple clids\n");
 3509         } else {
 3510                 nd->nd_flag |= ND_IMPLIEDCLID;
 3511                 nd->nd_clientid.qval = clientid.qval;
 3512         }
 3513         error = nfsrv_mtostr(nd, stp->ls_owner, len);
 3514         if (error)
 3515                 goto nfsmout;
 3516         nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
 3517         FREE((caddr_t)stp, M_NFSDSTATE);
 3518 
 3519         NFSEXITCODE2(0, nd);
 3520         return (0);
 3521 nfsmout:
 3522         if (stp)
 3523                 free((caddr_t)stp, M_NFSDSTATE);
 3524         NFSEXITCODE2(error, nd);
 3525         return (error);
 3526 }

Cache object: 6d17e19c2d04175a3287ff989462bad2


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.