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: releng/10.0/sys/fs/nfsserver/nfs_nfsdserv.c 264267 2014-04-08 18:27:46Z delphij $");
   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_MAXDATA || 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         } else if (vnode_vtype(vp) == VLNK) {
 1624                 if (nd->nd_flag & ND_NFSV2)
 1625                         nd->nd_repstat = NFSERR_INVAL;
 1626                 else
 1627                         nd->nd_repstat = NFSERR_NOTSUPP;
 1628                 if (tovp)
 1629                         vrele(tovp);
 1630         }
 1631         if (!nd->nd_repstat) {
 1632                 if (nd->nd_flag & ND_NFSV4) {
 1633                         dp = tovp;
 1634                         tnes = *toexp;
 1635                 } else {
 1636                         error = nfsrv_mtofh(nd, &dfh);
 1637                         if (error) {
 1638                                 vrele(vp);
 1639                                 /* tovp is always NULL unless NFSv4 */
 1640                                 goto out;
 1641                         }
 1642                         nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0,
 1643                             p);
 1644                         if (dp)
 1645                                 NFSVOPUNLOCK(dp, 0);
 1646                 }
 1647         }
 1648         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
 1649             LOCKPARENT | SAVENAME);
 1650         if (!nd->nd_repstat) {
 1651                 nfsvno_setpathbuf(&named, &bufp, &hashp);
 1652                 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
 1653                 if (error) {
 1654                         vrele(vp);
 1655                         if (dp)
 1656                                 vrele(dp);
 1657                         nfsvno_relpathbuf(&named);
 1658                         goto out;
 1659                 }
 1660                 if (!nd->nd_repstat) {
 1661                         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
 1662                             p, &dirp);
 1663                 } else {
 1664                         if (dp)
 1665                                 vrele(dp);
 1666                         nfsvno_relpathbuf(&named);
 1667                 }
 1668         }
 1669         if (dirp) {
 1670                 if (nd->nd_flag & ND_NFSV2) {
 1671                         vrele(dirp);
 1672                         dirp = NULL;
 1673                 } else {
 1674                         dirfor_ret = nfsvno_getattr(dirp, &dirfor,
 1675                             nd->nd_cred, p, 0);
 1676                 }
 1677         }
 1678         if (!nd->nd_repstat)
 1679                 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
 1680         if (nd->nd_flag & ND_NFSV3)
 1681                 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
 1682         if (dirp) {
 1683                 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
 1684                 vrele(dirp);
 1685         }
 1686         vrele(vp);
 1687         if (nd->nd_flag & ND_NFSV3) {
 1688                 nfsrv_postopattr(nd, getret, &at);
 1689                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1690         } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
 1691                 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 1692                 *tl++ = newnfs_false;
 1693                 txdr_hyper(dirfor.na_filerev, tl);
 1694                 tl += 2;
 1695                 txdr_hyper(diraft.na_filerev, tl);
 1696         }
 1697 
 1698 out:
 1699         NFSEXITCODE2(error, nd);
 1700         return (error);
 1701 }
 1702 
 1703 /*
 1704  * nfs symbolic link service
 1705  */
 1706 APPLESTATIC int
 1707 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
 1708     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
 1709     struct nfsexstuff *exp)
 1710 {
 1711         struct nfsvattr nva, dirfor, diraft;
 1712         struct nameidata named;
 1713         int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
 1714         vnode_t dirp = NULL;
 1715         char *bufp, *pathcp = NULL;
 1716         u_long *hashp;
 1717 
 1718         if (nd->nd_repstat) {
 1719                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1720                 goto out;
 1721         }
 1722         if (vpp)
 1723                 *vpp = NULL;
 1724         NFSVNO_ATTRINIT(&nva);
 1725         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
 1726             LOCKPARENT | SAVESTART);
 1727         nfsvno_setpathbuf(&named, &bufp, &hashp);
 1728         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
 1729         if (!error && !nd->nd_repstat)
 1730                 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
 1731         if (error) {
 1732                 vrele(dp);
 1733                 nfsvno_relpathbuf(&named);
 1734                 goto out;
 1735         }
 1736         if (!nd->nd_repstat) {
 1737                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
 1738         } else {
 1739                 vrele(dp);
 1740                 nfsvno_relpathbuf(&named);
 1741         }
 1742         if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
 1743                 vrele(dirp);
 1744                 dirp = NULL;
 1745         }
 1746 
 1747         /*
 1748          * And call nfsrvd_symlinksub() to do the common code. It will
 1749          * return EBADRPC upon a parsing error, 0 otherwise.
 1750          */
 1751         if (!nd->nd_repstat) {
 1752                 if (dirp != NULL)
 1753                         dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
 1754                             p, 0);
 1755                 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
 1756                     &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
 1757                     pathcp, pathlen);
 1758         } else if (dirp != NULL) {
 1759                 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
 1760                 vrele(dirp);
 1761         }
 1762         if (pathcp)
 1763                 FREE(pathcp, M_TEMP);
 1764 
 1765         if (nd->nd_flag & ND_NFSV3) {
 1766                 if (!nd->nd_repstat) {
 1767                         (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
 1768                         nfsrv_postopattr(nd, 0, &nva);
 1769                 }
 1770                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1771         }
 1772 
 1773 out:
 1774         NFSEXITCODE2(error, nd);
 1775         return (error);
 1776 }
 1777 
 1778 /*
 1779  * Common code for creating a symbolic link.
 1780  */
 1781 static void
 1782 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
 1783     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
 1784     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
 1785     int *diraft_retp, nfsattrbit_t *attrbitp,
 1786     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
 1787     int pathlen)
 1788 {
 1789         u_int32_t *tl;
 1790 
 1791         nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
 1792             !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
 1793         if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
 1794                 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
 1795                 if (nd->nd_flag & ND_NFSV3) {
 1796                         nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
 1797                         if (!nd->nd_repstat)
 1798                                 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
 1799                                     nvap, nd->nd_cred, p, 1);
 1800                 }
 1801                 if (vpp != NULL && nd->nd_repstat == 0) {
 1802                         NFSVOPUNLOCK(ndp->ni_vp, 0);
 1803                         *vpp = ndp->ni_vp;
 1804                 } else
 1805                         vput(ndp->ni_vp);
 1806         }
 1807         if (dirp) {
 1808                 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
 1809                 vrele(dirp);
 1810         }
 1811         if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
 1812                 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 1813                 *tl++ = newnfs_false;
 1814                 txdr_hyper(dirforp->na_filerev, tl);
 1815                 tl += 2;
 1816                 txdr_hyper(diraftp->na_filerev, tl);
 1817                 (void) nfsrv_putattrbit(nd, attrbitp);
 1818         }
 1819 
 1820         NFSEXITCODE2(0, nd);
 1821 }
 1822 
 1823 /*
 1824  * nfs mkdir service
 1825  */
 1826 APPLESTATIC int
 1827 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
 1828     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
 1829     struct nfsexstuff *exp)
 1830 {
 1831         struct nfsvattr nva, dirfor, diraft;
 1832         struct nameidata named;
 1833         u_int32_t *tl;
 1834         int error = 0, dirfor_ret = 1, diraft_ret = 1;
 1835         vnode_t dirp = NULL;
 1836         char *bufp;
 1837         u_long *hashp;
 1838 
 1839         if (nd->nd_repstat) {
 1840                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1841                 goto out;
 1842         }
 1843         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
 1844             LOCKPARENT | SAVENAME);
 1845         nfsvno_setpathbuf(&named, &bufp, &hashp);
 1846         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
 1847         if (error)
 1848                 goto nfsmout;
 1849         if (!nd->nd_repstat) {
 1850                 NFSVNO_ATTRINIT(&nva);
 1851                 if (nd->nd_flag & ND_NFSV3) {
 1852                         error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
 1853                         if (error)
 1854                                 goto nfsmout;
 1855                 } else {
 1856                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1857                         nva.na_mode = nfstov_mode(*tl++);
 1858                 }
 1859         }
 1860         if (!nd->nd_repstat) {
 1861                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
 1862         } else {
 1863                 vrele(dp);
 1864                 nfsvno_relpathbuf(&named);
 1865         }
 1866         if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
 1867                 vrele(dirp);
 1868                 dirp = NULL;
 1869         }
 1870         if (nd->nd_repstat) {
 1871                 if (dirp != NULL) {
 1872                         dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
 1873                             p, 0);
 1874                         vrele(dirp);
 1875                 }
 1876                 if (nd->nd_flag & ND_NFSV3)
 1877                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
 1878                             &diraft);
 1879                 goto out;
 1880         }
 1881         if (dirp != NULL)
 1882                 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
 1883 
 1884         /*
 1885          * Call nfsrvd_mkdirsub() for the code common to V4 as well.
 1886          */
 1887         nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
 1888             &diraft_ret, NULL, NULL, p, exp);
 1889 
 1890         if (nd->nd_flag & ND_NFSV3) {
 1891                 if (!nd->nd_repstat) {
 1892                         (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
 1893                         nfsrv_postopattr(nd, 0, &nva);
 1894                 }
 1895                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1896         } else if (!nd->nd_repstat) {
 1897                 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
 1898                 nfsrv_fillattr(nd, &nva);
 1899         }
 1900 
 1901 out:
 1902         NFSEXITCODE2(0, nd);
 1903         return (0);
 1904 nfsmout:
 1905         vrele(dp);
 1906         nfsvno_relpathbuf(&named);
 1907         NFSEXITCODE2(error, nd);
 1908         return (error);
 1909 }
 1910 
 1911 /*
 1912  * Code common to mkdir for V2,3 and 4.
 1913  */
 1914 static void
 1915 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
 1916     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
 1917     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
 1918     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
 1919     NFSPROC_T *p, struct nfsexstuff *exp)
 1920 {
 1921         vnode_t vp;
 1922         u_int32_t *tl;
 1923 
 1924         NFSVNO_SETATTRVAL(nvap, type, VDIR);
 1925         nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
 1926             nd->nd_cred, p, exp);
 1927         if (!nd->nd_repstat) {
 1928                 vp = ndp->ni_vp;
 1929                 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
 1930                 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
 1931                 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
 1932                         nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
 1933                             p, 1);
 1934                 if (vpp && !nd->nd_repstat) {
 1935                         NFSVOPUNLOCK(vp, 0);
 1936                         *vpp = vp;
 1937                 } else {
 1938                         vput(vp);
 1939                 }
 1940         }
 1941         if (dirp) {
 1942                 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
 1943                 vrele(dirp);
 1944         }
 1945         if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
 1946                 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 1947                 *tl++ = newnfs_false;
 1948                 txdr_hyper(dirforp->na_filerev, tl);
 1949                 tl += 2;
 1950                 txdr_hyper(diraftp->na_filerev, tl);
 1951                 (void) nfsrv_putattrbit(nd, attrbitp);
 1952         }
 1953 
 1954         NFSEXITCODE2(0, nd);
 1955 }
 1956 
 1957 /*
 1958  * nfs commit service
 1959  */
 1960 APPLESTATIC int
 1961 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
 1962     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 1963 {
 1964         struct nfsvattr bfor, aft;
 1965         u_int32_t *tl;
 1966         int error = 0, for_ret = 1, aft_ret = 1, cnt;
 1967         u_int64_t off;
 1968 
 1969         if (nd->nd_repstat) {
 1970                 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
 1971                 goto out;
 1972         }
 1973         NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 1974         /*
 1975          * XXX At this time VOP_FSYNC() does not accept offset and byte
 1976          * count parameters, so these arguments are useless (someday maybe).
 1977          */
 1978         off = fxdr_hyper(tl);
 1979         tl += 2;
 1980         cnt = fxdr_unsigned(int, *tl);
 1981         if (nd->nd_flag & ND_NFSV3)
 1982                 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
 1983         nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
 1984         if (nd->nd_flag & ND_NFSV3) {
 1985                 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
 1986                 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
 1987         }
 1988         vput(vp);
 1989         if (!nd->nd_repstat) {
 1990                 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
 1991                 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
 1992                 *tl = txdr_unsigned(nfsboottime.tv_usec);
 1993         }
 1994 
 1995 out:
 1996         NFSEXITCODE2(0, nd);
 1997         return (0);
 1998 nfsmout:
 1999         vput(vp);
 2000         NFSEXITCODE2(error, nd);
 2001         return (error);
 2002 }
 2003 
 2004 /*
 2005  * nfs statfs service
 2006  */
 2007 APPLESTATIC int
 2008 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
 2009     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 2010 {
 2011         struct statfs *sf;
 2012         u_int32_t *tl;
 2013         int getret = 1;
 2014         struct nfsvattr at;
 2015         struct statfs sfs;
 2016         u_quad_t tval;
 2017 
 2018         if (nd->nd_repstat) {
 2019                 nfsrv_postopattr(nd, getret, &at);
 2020                 goto out;
 2021         }
 2022         sf = &sfs;
 2023         nd->nd_repstat = nfsvno_statfs(vp, sf);
 2024         getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
 2025         vput(vp);
 2026         if (nd->nd_flag & ND_NFSV3)
 2027                 nfsrv_postopattr(nd, getret, &at);
 2028         if (nd->nd_repstat)
 2029                 goto out;
 2030         if (nd->nd_flag & ND_NFSV2) {
 2031                 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
 2032                 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
 2033                 *tl++ = txdr_unsigned(sf->f_bsize);
 2034                 *tl++ = txdr_unsigned(sf->f_blocks);
 2035                 *tl++ = txdr_unsigned(sf->f_bfree);
 2036                 *tl = txdr_unsigned(sf->f_bavail);
 2037         } else {
 2038                 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
 2039                 tval = (u_quad_t)sf->f_blocks;
 2040                 tval *= (u_quad_t)sf->f_bsize;
 2041                 txdr_hyper(tval, tl); tl += 2;
 2042                 tval = (u_quad_t)sf->f_bfree;
 2043                 tval *= (u_quad_t)sf->f_bsize;
 2044                 txdr_hyper(tval, tl); tl += 2;
 2045                 tval = (u_quad_t)sf->f_bavail;
 2046                 tval *= (u_quad_t)sf->f_bsize;
 2047                 txdr_hyper(tval, tl); tl += 2;
 2048                 tval = (u_quad_t)sf->f_files;
 2049                 txdr_hyper(tval, tl); tl += 2;
 2050                 tval = (u_quad_t)sf->f_ffree;
 2051                 txdr_hyper(tval, tl); tl += 2;
 2052                 tval = (u_quad_t)sf->f_ffree;
 2053                 txdr_hyper(tval, tl); tl += 2;
 2054                 *tl = 0;
 2055         }
 2056 
 2057 out:
 2058         NFSEXITCODE2(0, nd);
 2059         return (0);
 2060 }
 2061 
 2062 /*
 2063  * nfs fsinfo service
 2064  */
 2065 APPLESTATIC int
 2066 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
 2067     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 2068 {
 2069         u_int32_t *tl;
 2070         struct nfsfsinfo fs;
 2071         int getret = 1;
 2072         struct nfsvattr at;
 2073 
 2074         if (nd->nd_repstat) {
 2075                 nfsrv_postopattr(nd, getret, &at);
 2076                 goto out;
 2077         }
 2078         getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
 2079         nfsvno_getfs(&fs, isdgram);
 2080         vput(vp);
 2081         nfsrv_postopattr(nd, getret, &at);
 2082         NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
 2083         *tl++ = txdr_unsigned(fs.fs_rtmax);
 2084         *tl++ = txdr_unsigned(fs.fs_rtpref);
 2085         *tl++ = txdr_unsigned(fs.fs_rtmult);
 2086         *tl++ = txdr_unsigned(fs.fs_wtmax);
 2087         *tl++ = txdr_unsigned(fs.fs_wtpref);
 2088         *tl++ = txdr_unsigned(fs.fs_wtmult);
 2089         *tl++ = txdr_unsigned(fs.fs_dtpref);
 2090         txdr_hyper(fs.fs_maxfilesize, tl);
 2091         tl += 2;
 2092         txdr_nfsv3time(&fs.fs_timedelta, tl);
 2093         tl += 2;
 2094         *tl = txdr_unsigned(fs.fs_properties);
 2095 
 2096 out:
 2097         NFSEXITCODE2(0, nd);
 2098         return (0);
 2099 }
 2100 
 2101 /*
 2102  * nfs pathconf service
 2103  */
 2104 APPLESTATIC int
 2105 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
 2106     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 2107 {
 2108         struct nfsv3_pathconf *pc;
 2109         int getret = 1;
 2110         register_t linkmax, namemax, chownres, notrunc;
 2111         struct nfsvattr at;
 2112 
 2113         if (nd->nd_repstat) {
 2114                 nfsrv_postopattr(nd, getret, &at);
 2115                 goto out;
 2116         }
 2117         nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
 2118             nd->nd_cred, p);
 2119         if (!nd->nd_repstat)
 2120                 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
 2121                     nd->nd_cred, p);
 2122         if (!nd->nd_repstat)
 2123                 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
 2124                     &chownres, nd->nd_cred, p);
 2125         if (!nd->nd_repstat)
 2126                 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, &notrunc,
 2127                     nd->nd_cred, p);
 2128         getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
 2129         vput(vp);
 2130         nfsrv_postopattr(nd, getret, &at);
 2131         if (!nd->nd_repstat) {
 2132                 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
 2133                 pc->pc_linkmax = txdr_unsigned(linkmax);
 2134                 pc->pc_namemax = txdr_unsigned(namemax);
 2135                 pc->pc_notrunc = txdr_unsigned(notrunc);
 2136                 pc->pc_chownrestricted = txdr_unsigned(chownres);
 2137 
 2138                 /*
 2139                  * These should probably be supported by VOP_PATHCONF(), but
 2140                  * until msdosfs is exportable (why would you want to?), the
 2141                  * Unix defaults should be ok.
 2142                  */
 2143                 pc->pc_caseinsensitive = newnfs_false;
 2144                 pc->pc_casepreserving = newnfs_true;
 2145         }
 2146 
 2147 out:
 2148         NFSEXITCODE2(0, nd);
 2149         return (0);
 2150 }
 2151 
 2152 /*
 2153  * nfsv4 lock service
 2154  */
 2155 APPLESTATIC int
 2156 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
 2157     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
 2158 {
 2159         u_int32_t *tl;
 2160         int i;
 2161         struct nfsstate *stp = NULL;
 2162         struct nfslock *lop;
 2163         struct nfslockconflict cf;
 2164         int error = 0;
 2165         u_short flags = NFSLCK_LOCK, lflags;
 2166         u_int64_t offset, len;
 2167         nfsv4stateid_t stateid;
 2168         nfsquad_t clientid;
 2169 
 2170         NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
 2171         i = fxdr_unsigned(int, *tl++);
 2172         switch (i) {
 2173         case NFSV4LOCKT_READW:
 2174                 flags |= NFSLCK_BLOCKING;
 2175         case NFSV4LOCKT_READ:
 2176                 lflags = NFSLCK_READ;
 2177                 break;
 2178         case NFSV4LOCKT_WRITEW:
 2179                 flags |= NFSLCK_BLOCKING;
 2180         case NFSV4LOCKT_WRITE:
 2181                 lflags = NFSLCK_WRITE;
 2182                 break;
 2183         default:
 2184                 nd->nd_repstat = NFSERR_BADXDR;
 2185                 goto nfsmout;
 2186         };
 2187         if (*tl++ == newnfs_true)
 2188                 flags |= NFSLCK_RECLAIM;
 2189         offset = fxdr_hyper(tl);
 2190         tl += 2;
 2191         len = fxdr_hyper(tl);
 2192         tl += 2;
 2193         if (*tl == newnfs_true)
 2194                 flags |= NFSLCK_OPENTOLOCK;
 2195         if (flags & NFSLCK_OPENTOLOCK) {
 2196                 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
 2197                 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
 2198                 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
 2199                         nd->nd_repstat = NFSERR_BADXDR;
 2200                         goto nfsmout;
 2201                 }
 2202                 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
 2203                         M_NFSDSTATE, M_WAITOK);
 2204                 stp->ls_ownerlen = i;
 2205                 stp->ls_op = nd->nd_rp;
 2206                 stp->ls_seq = fxdr_unsigned(int, *tl++);
 2207                 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 2208                 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 2209                         NFSX_STATEIDOTHER);
 2210                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 2211                 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
 2212                 clientid.lval[0] = *tl++;
 2213                 clientid.lval[1] = *tl++;
 2214                 if (nd->nd_flag & ND_IMPLIEDCLID) {
 2215                         if (nd->nd_clientid.qval != clientid.qval)
 2216                                 printf("EEK! multiple clids\n");
 2217                 } else {
 2218                         nd->nd_flag |= ND_IMPLIEDCLID;
 2219                         nd->nd_clientid.qval = clientid.qval;
 2220                 }
 2221                 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
 2222                 if (error)
 2223                         goto nfsmout;
 2224         } else {
 2225                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
 2226                 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
 2227                         M_NFSDSTATE, M_WAITOK);
 2228                 stp->ls_ownerlen = 0;
 2229                 stp->ls_op = nd->nd_rp;
 2230                 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 2231                 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 2232                         NFSX_STATEIDOTHER);
 2233                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 2234                 stp->ls_seq = fxdr_unsigned(int, *tl);
 2235                 clientid.lval[0] = stp->ls_stateid.other[0];
 2236                 clientid.lval[1] = stp->ls_stateid.other[1];
 2237                 if (nd->nd_flag & ND_IMPLIEDCLID) {
 2238                         if (nd->nd_clientid.qval != clientid.qval)
 2239                                 printf("EEK! multiple clids\n");
 2240                 } else {
 2241                         nd->nd_flag |= ND_IMPLIEDCLID;
 2242                         nd->nd_clientid.qval = clientid.qval;
 2243                 }
 2244         }
 2245         MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
 2246                 M_NFSDLOCK, M_WAITOK);
 2247         lop->lo_first = offset;
 2248         if (len == NFS64BITSSET) {
 2249                 lop->lo_end = NFS64BITSSET;
 2250         } else {
 2251                 lop->lo_end = offset + len;
 2252                 if (lop->lo_end <= lop->lo_first)
 2253                         nd->nd_repstat = NFSERR_INVAL;
 2254         }
 2255         lop->lo_flags = lflags;
 2256         stp->ls_flags = flags;
 2257         stp->ls_uid = nd->nd_cred->cr_uid;
 2258 
 2259         /*
 2260          * Do basic access checking.
 2261          */
 2262         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
 2263             if (vnode_vtype(vp) == VDIR)
 2264                 nd->nd_repstat = NFSERR_ISDIR;
 2265             else
 2266                 nd->nd_repstat = NFSERR_INVAL;
 2267         }
 2268         if (!nd->nd_repstat) {
 2269             if (lflags & NFSLCK_WRITE) {
 2270                 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
 2271                     nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
 2272                     NFSACCCHK_VPISLOCKED, NULL);
 2273             } else {
 2274                 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
 2275                     nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
 2276                     NFSACCCHK_VPISLOCKED, NULL);
 2277                 if (nd->nd_repstat)
 2278                     nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
 2279                         nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
 2280                         NFSACCCHK_VPISLOCKED, NULL);
 2281             }
 2282         }
 2283 
 2284         /*
 2285          * We call nfsrv_lockctrl() even if nd_repstat set, so that the
 2286          * seqid# gets updated. nfsrv_lockctrl() will return the value
 2287          * of nd_repstat, if it gets that far.
 2288          */
 2289         nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 
 2290                 &stateid, exp, nd, p);
 2291         if (lop)
 2292                 FREE((caddr_t)lop, M_NFSDLOCK);
 2293         if (stp)
 2294                 FREE((caddr_t)stp, M_NFSDSTATE);
 2295         if (!nd->nd_repstat) {
 2296                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 2297                 *tl++ = txdr_unsigned(stateid.seqid);
 2298                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
 2299         } else if (nd->nd_repstat == NFSERR_DENIED) {
 2300                 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
 2301                 txdr_hyper(cf.cl_first, tl);
 2302                 tl += 2;
 2303                 if (cf.cl_end == NFS64BITSSET)
 2304                         len = NFS64BITSSET;
 2305                 else
 2306                         len = cf.cl_end - cf.cl_first;
 2307                 txdr_hyper(len, tl);
 2308                 tl += 2;
 2309                 if (cf.cl_flags == NFSLCK_WRITE)
 2310                         *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
 2311                 else
 2312                         *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
 2313                 *tl++ = stateid.other[0];
 2314                 *tl = stateid.other[1];
 2315                 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
 2316         }
 2317         vput(vp);
 2318         NFSEXITCODE2(0, nd);
 2319         return (0);
 2320 nfsmout:
 2321         vput(vp);
 2322         if (stp)
 2323                 free((caddr_t)stp, M_NFSDSTATE);
 2324         NFSEXITCODE2(error, nd);
 2325         return (error);
 2326 }
 2327 
 2328 /*
 2329  * nfsv4 lock test service
 2330  */
 2331 APPLESTATIC int
 2332 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
 2333     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
 2334 {
 2335         u_int32_t *tl;
 2336         int i;
 2337         struct nfsstate *stp = NULL;
 2338         struct nfslock lo, *lop = &lo;
 2339         struct nfslockconflict cf;
 2340         int error = 0;
 2341         nfsv4stateid_t stateid;
 2342         nfsquad_t clientid;
 2343         u_int64_t len;
 2344 
 2345         NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
 2346         i = fxdr_unsigned(int, *(tl + 7));
 2347         if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
 2348                 nd->nd_repstat = NFSERR_BADXDR;
 2349                 goto nfsmout;
 2350         }
 2351         MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
 2352             M_NFSDSTATE, M_WAITOK);
 2353         stp->ls_ownerlen = i;
 2354         stp->ls_op = NULL;
 2355         stp->ls_flags = NFSLCK_TEST;
 2356         stp->ls_uid = nd->nd_cred->cr_uid;
 2357         i = fxdr_unsigned(int, *tl++);
 2358         switch (i) {
 2359         case NFSV4LOCKT_READW:
 2360                 stp->ls_flags |= NFSLCK_BLOCKING;
 2361         case NFSV4LOCKT_READ:
 2362                 lo.lo_flags = NFSLCK_READ;
 2363                 break;
 2364         case NFSV4LOCKT_WRITEW:
 2365                 stp->ls_flags |= NFSLCK_BLOCKING;
 2366         case NFSV4LOCKT_WRITE:
 2367                 lo.lo_flags = NFSLCK_WRITE;
 2368                 break;
 2369         default:
 2370                 nd->nd_repstat = NFSERR_BADXDR;
 2371                 goto nfsmout;
 2372         };
 2373         lo.lo_first = fxdr_hyper(tl);
 2374         tl += 2;
 2375         len = fxdr_hyper(tl);
 2376         if (len == NFS64BITSSET) {
 2377                 lo.lo_end = NFS64BITSSET;
 2378         } else {
 2379                 lo.lo_end = lo.lo_first + len;
 2380                 if (lo.lo_end <= lo.lo_first)
 2381                         nd->nd_repstat = NFSERR_INVAL;
 2382         }
 2383         tl += 2;
 2384         clientid.lval[0] = *tl++;
 2385         clientid.lval[1] = *tl;
 2386         if (nd->nd_flag & ND_IMPLIEDCLID) {
 2387                 if (nd->nd_clientid.qval != clientid.qval)
 2388                         printf("EEK! multiple clids\n");
 2389         } else {
 2390                 nd->nd_flag |= ND_IMPLIEDCLID;
 2391                 nd->nd_clientid.qval = clientid.qval;
 2392         }
 2393         error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
 2394         if (error)
 2395                 goto nfsmout;
 2396         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
 2397             if (vnode_vtype(vp) == VDIR)
 2398                 nd->nd_repstat = NFSERR_ISDIR;
 2399             else
 2400                 nd->nd_repstat = NFSERR_INVAL;
 2401         }
 2402         if (!nd->nd_repstat)
 2403           nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
 2404             &stateid, exp, nd, p);
 2405         if (stp)
 2406                 FREE((caddr_t)stp, M_NFSDSTATE);
 2407         if (nd->nd_repstat) {
 2408             if (nd->nd_repstat == NFSERR_DENIED) {
 2409                 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
 2410                 txdr_hyper(cf.cl_first, tl);
 2411                 tl += 2;
 2412                 if (cf.cl_end == NFS64BITSSET)
 2413                         len = NFS64BITSSET;
 2414                 else
 2415                         len = cf.cl_end - cf.cl_first;
 2416                 txdr_hyper(len, tl);
 2417                 tl += 2;
 2418                 if (cf.cl_flags == NFSLCK_WRITE)
 2419                         *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
 2420                 else
 2421                         *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
 2422                 *tl++ = stp->ls_stateid.other[0];
 2423                 *tl = stp->ls_stateid.other[1];
 2424                 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
 2425             }
 2426         }
 2427         vput(vp);
 2428         NFSEXITCODE2(0, nd);
 2429         return (0);
 2430 nfsmout:
 2431         vput(vp);
 2432         if (stp)
 2433                 free((caddr_t)stp, M_NFSDSTATE);
 2434         NFSEXITCODE2(error, nd);
 2435         return (error);
 2436 }
 2437 
 2438 /*
 2439  * nfsv4 unlock service
 2440  */
 2441 APPLESTATIC int
 2442 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
 2443     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
 2444 {
 2445         u_int32_t *tl;
 2446         int i;
 2447         struct nfsstate *stp;
 2448         struct nfslock *lop;
 2449         int error = 0;
 2450         nfsv4stateid_t stateid;
 2451         nfsquad_t clientid;
 2452         u_int64_t len;
 2453 
 2454         NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
 2455         MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
 2456             M_NFSDSTATE, M_WAITOK);
 2457         MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
 2458             M_NFSDLOCK, M_WAITOK);
 2459         stp->ls_flags = NFSLCK_UNLOCK;
 2460         lop->lo_flags = NFSLCK_UNLOCK;
 2461         stp->ls_op = nd->nd_rp;
 2462         i = fxdr_unsigned(int, *tl++);
 2463         switch (i) {
 2464         case NFSV4LOCKT_READW:
 2465                 stp->ls_flags |= NFSLCK_BLOCKING;
 2466         case NFSV4LOCKT_READ:
 2467                 break;
 2468         case NFSV4LOCKT_WRITEW:
 2469                 stp->ls_flags |= NFSLCK_BLOCKING;
 2470         case NFSV4LOCKT_WRITE:
 2471                 break;
 2472         default:
 2473                 nd->nd_repstat = NFSERR_BADXDR;
 2474                 free(stp, M_NFSDSTATE);
 2475                 free(lop, M_NFSDLOCK);
 2476                 goto nfsmout;
 2477         };
 2478         stp->ls_ownerlen = 0;
 2479         stp->ls_uid = nd->nd_cred->cr_uid;
 2480         stp->ls_seq = fxdr_unsigned(int, *tl++);
 2481         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 2482         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 2483             NFSX_STATEIDOTHER);
 2484         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 2485         lop->lo_first = fxdr_hyper(tl);
 2486         tl += 2;
 2487         len = fxdr_hyper(tl);
 2488         if (len == NFS64BITSSET) {
 2489                 lop->lo_end = NFS64BITSSET;
 2490         } else {
 2491                 lop->lo_end = lop->lo_first + len;
 2492                 if (lop->lo_end <= lop->lo_first)
 2493                         nd->nd_repstat = NFSERR_INVAL;
 2494         }
 2495         clientid.lval[0] = stp->ls_stateid.other[0];
 2496         clientid.lval[1] = stp->ls_stateid.other[1];
 2497         if (nd->nd_flag & ND_IMPLIEDCLID) {
 2498                 if (nd->nd_clientid.qval != clientid.qval)
 2499                         printf("EEK! multiple clids\n");
 2500         } else {
 2501                 nd->nd_flag |= ND_IMPLIEDCLID;
 2502                 nd->nd_clientid.qval = clientid.qval;
 2503         }
 2504         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
 2505             if (vnode_vtype(vp) == VDIR)
 2506                 nd->nd_repstat = NFSERR_ISDIR;
 2507             else
 2508                 nd->nd_repstat = NFSERR_INVAL;
 2509         }
 2510         /*
 2511          * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
 2512          * seqid# gets incremented. nfsrv_lockctrl() will return the
 2513          * value of nd_repstat, if it gets that far.
 2514          */
 2515         nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
 2516             &stateid, exp, nd, p);
 2517         if (stp)
 2518                 FREE((caddr_t)stp, M_NFSDSTATE);
 2519         if (lop)
 2520                 free((caddr_t)lop, M_NFSDLOCK);
 2521         if (!nd->nd_repstat) {
 2522                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 2523                 *tl++ = txdr_unsigned(stateid.seqid);
 2524                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
 2525         }
 2526 nfsmout:
 2527         vput(vp);
 2528         NFSEXITCODE2(error, nd);
 2529         return (error);
 2530 }
 2531 
 2532 /*
 2533  * nfsv4 open service
 2534  */
 2535 APPLESTATIC int
 2536 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
 2537     vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
 2538     struct nfsexstuff *exp)
 2539 {
 2540         u_int32_t *tl;
 2541         int i;
 2542         struct nfsstate *stp = NULL;
 2543         int error = 0, create, claim, exclusive_flag = 0;
 2544         u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
 2545         int how = NFSCREATE_UNCHECKED;
 2546         int32_t cverf[2], tverf[2] = { 0, 0 };
 2547         vnode_t vp = NULL, dirp = NULL;
 2548         struct nfsvattr nva, dirfor, diraft;
 2549         struct nameidata named;
 2550         nfsv4stateid_t stateid, delegstateid;
 2551         nfsattrbit_t attrbits;
 2552         nfsquad_t clientid;
 2553         char *bufp = NULL;
 2554         u_long *hashp;
 2555         NFSACL_T *aclp = NULL;
 2556 
 2557 #ifdef NFS4_ACL_EXTATTR_NAME
 2558         aclp = acl_alloc(M_WAITOK);
 2559         aclp->acl_cnt = 0;
 2560 #endif
 2561         NFSZERO_ATTRBIT(&attrbits);
 2562         named.ni_startdir = NULL;
 2563         named.ni_cnd.cn_nameiop = 0;
 2564         NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
 2565         i = fxdr_unsigned(int, *(tl + 5));
 2566         if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
 2567                 nd->nd_repstat = NFSERR_BADXDR;
 2568                 goto nfsmout;
 2569         }
 2570         MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
 2571             M_NFSDSTATE, M_WAITOK);
 2572         stp->ls_ownerlen = i;
 2573         stp->ls_op = nd->nd_rp;
 2574         stp->ls_flags = NFSLCK_OPEN;
 2575         stp->ls_uid = nd->nd_cred->cr_uid;
 2576         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
 2577         i = fxdr_unsigned(int, *tl++);
 2578         switch (i) {
 2579         case NFSV4OPEN_ACCESSREAD:
 2580                 stp->ls_flags |= NFSLCK_READACCESS;
 2581                 break;
 2582         case NFSV4OPEN_ACCESSWRITE:
 2583                 stp->ls_flags |= NFSLCK_WRITEACCESS;
 2584                 break;
 2585         case NFSV4OPEN_ACCESSBOTH:
 2586                 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
 2587                 break;
 2588         default:
 2589                 nd->nd_repstat = NFSERR_INVAL;
 2590         };
 2591         i = fxdr_unsigned(int, *tl++);
 2592         switch (i) {
 2593         case NFSV4OPEN_DENYNONE:
 2594                 break;
 2595         case NFSV4OPEN_DENYREAD:
 2596                 stp->ls_flags |= NFSLCK_READDENY;
 2597                 break;
 2598         case NFSV4OPEN_DENYWRITE:
 2599                 stp->ls_flags |= NFSLCK_WRITEDENY;
 2600                 break;
 2601         case NFSV4OPEN_DENYBOTH:
 2602                 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
 2603                 break;
 2604         default:
 2605                 nd->nd_repstat = NFSERR_INVAL;
 2606         };
 2607         clientid.lval[0] = *tl++;
 2608         clientid.lval[1] = *tl;
 2609         if (nd->nd_flag & ND_IMPLIEDCLID) {
 2610                 if (nd->nd_clientid.qval != clientid.qval)
 2611                         printf("EEK! multiple clids\n");
 2612         } else {
 2613                 nd->nd_flag |= ND_IMPLIEDCLID;
 2614                 nd->nd_clientid.qval = clientid.qval;
 2615         }
 2616         error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
 2617         if (error)
 2618                 goto nfsmout;
 2619         NFSVNO_ATTRINIT(&nva);
 2620         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2621         create = fxdr_unsigned(int, *tl);
 2622         if (!nd->nd_repstat)
 2623                 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
 2624         if (create == NFSV4OPEN_CREATE) {
 2625                 nva.na_type = VREG;
 2626                 nva.na_mode = 0;
 2627                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2628                 how = fxdr_unsigned(int, *tl);
 2629                 switch (how) {
 2630                 case NFSCREATE_UNCHECKED:
 2631                 case NFSCREATE_GUARDED:
 2632                         error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
 2633                         if (error)
 2634                                 goto nfsmout;
 2635                         /*
 2636                          * If the na_gid being set is the same as that of
 2637                          * the directory it is going in, clear it, since
 2638                          * that is what will be set by default. This allows
 2639                          * a user that isn't in that group to do the create.
 2640                          */
 2641                         if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
 2642                             nva.na_gid == dirfor.na_gid)
 2643                                 NFSVNO_UNSET(&nva, gid);
 2644                         if (!nd->nd_repstat)
 2645                                 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
 2646                         break;
 2647                 case NFSCREATE_EXCLUSIVE:
 2648                         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
 2649                         cverf[0] = *tl++;
 2650                         cverf[1] = *tl;
 2651                         break;
 2652                 default:
 2653                         nd->nd_repstat = NFSERR_BADXDR;
 2654                         goto nfsmout;
 2655                 };
 2656         } else if (create != NFSV4OPEN_NOCREATE) {
 2657                 nd->nd_repstat = NFSERR_BADXDR;
 2658                 goto nfsmout;
 2659         }
 2660 
 2661         /*
 2662          * Now, handle the claim, which usually includes looking up a
 2663          * name in the directory referenced by dp. The exception is
 2664          * NFSV4OPEN_CLAIMPREVIOUS.
 2665          */
 2666         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2667         claim = fxdr_unsigned(int, *tl);
 2668         if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
 2669                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
 2670                 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 2671                 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
 2672                 stp->ls_flags |= NFSLCK_DELEGCUR;
 2673         } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
 2674                 stp->ls_flags |= NFSLCK_DELEGPREV;
 2675         }
 2676         if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
 2677             || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
 2678                 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
 2679                     claim != NFSV4OPEN_CLAIMNULL)
 2680                         nd->nd_repstat = NFSERR_INVAL;
 2681                 if (nd->nd_repstat) {
 2682                         nd->nd_repstat = nfsrv_opencheck(clientid,
 2683                             &stateid, stp, NULL, nd, p, nd->nd_repstat);
 2684                         goto nfsmout;
 2685                 }
 2686                 if (create == NFSV4OPEN_CREATE)
 2687                     NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
 2688                         LOCKPARENT | LOCKLEAF | SAVESTART);
 2689                 else
 2690                     NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
 2691                         LOCKLEAF | SAVESTART);
 2692                 nfsvno_setpathbuf(&named, &bufp, &hashp);
 2693                 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
 2694                 if (error) {
 2695                         vrele(dp);
 2696 #ifdef NFS4_ACL_EXTATTR_NAME
 2697                         acl_free(aclp);
 2698 #endif
 2699                         FREE((caddr_t)stp, M_NFSDSTATE);
 2700                         nfsvno_relpathbuf(&named);
 2701                         NFSEXITCODE2(error, nd);
 2702                         return (error);
 2703                 }
 2704                 if (!nd->nd_repstat) {
 2705                         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
 2706                             p, &dirp);
 2707                 } else {
 2708                         vrele(dp);
 2709                         nfsvno_relpathbuf(&named);
 2710                 }
 2711                 if (create == NFSV4OPEN_CREATE) {
 2712                     switch (how) {
 2713                     case NFSCREATE_UNCHECKED:
 2714                         if (named.ni_vp) {
 2715                                 /*
 2716                                  * Clear the setable attribute bits, except
 2717                                  * for Size, if it is being truncated.
 2718                                  */
 2719                                 NFSZERO_ATTRBIT(&attrbits);
 2720                                 if (NFSVNO_ISSETSIZE(&nva))
 2721                                         NFSSETBIT_ATTRBIT(&attrbits,
 2722                                             NFSATTRBIT_SIZE);
 2723                         }
 2724                         break;
 2725                     case NFSCREATE_GUARDED:
 2726                         if (named.ni_vp && !nd->nd_repstat)
 2727                                 nd->nd_repstat = EEXIST;
 2728                         break;
 2729                     case NFSCREATE_EXCLUSIVE:
 2730                         exclusive_flag = 1;
 2731                         if (!named.ni_vp)
 2732                                 nva.na_mode = 0;
 2733                     };
 2734                 }
 2735                 nfsvno_open(nd, &named, clientid, &stateid, stp,
 2736                     &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
 2737                     nd->nd_cred, p, exp, &vp);
 2738         } else if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
 2739                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2740                 i = fxdr_unsigned(int, *tl);
 2741                 switch (i) {
 2742                 case NFSV4OPEN_DELEGATEREAD:
 2743                         stp->ls_flags |= NFSLCK_DELEGREAD;
 2744                         break;
 2745                 case NFSV4OPEN_DELEGATEWRITE:
 2746                         stp->ls_flags |= NFSLCK_DELEGWRITE;
 2747                 case NFSV4OPEN_DELEGATENONE:
 2748                         break;
 2749                 default:
 2750                         nd->nd_repstat = NFSERR_BADXDR;
 2751                         goto nfsmout;
 2752                 };
 2753                 stp->ls_flags |= NFSLCK_RECLAIM;
 2754                 vp = dp;
 2755                 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
 2756                 if ((vp->v_iflag & VI_DOOMED) == 0)
 2757                         nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
 2758                             stp, vp, nd, p, nd->nd_repstat);
 2759                 else
 2760                         nd->nd_repstat = NFSERR_PERM;
 2761         } else {
 2762                 nd->nd_repstat = NFSERR_BADXDR;
 2763                 goto nfsmout;
 2764         }
 2765 
 2766         /*
 2767          * Do basic access checking.
 2768          */
 2769         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
 2770                 /*
 2771                  * The IETF working group decided that this is the correct
 2772                  * error return for all non-regular files.
 2773                  */
 2774                 nd->nd_repstat = NFSERR_SYMLINK;
 2775         }
 2776         if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
 2777             nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
 2778                 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
 2779         if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
 2780             nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
 2781                 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
 2782             if (nd->nd_repstat)
 2783                 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
 2784                     nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
 2785                     NFSACCCHK_VPISLOCKED, NULL);
 2786         }
 2787 
 2788         if (!nd->nd_repstat) {
 2789                 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
 2790                 if (!nd->nd_repstat) {
 2791                         tverf[0] = nva.na_atime.tv_sec;
 2792                         tverf[1] = nva.na_atime.tv_nsec;
 2793                 }
 2794         }
 2795         if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
 2796             cverf[1] != tverf[1]))
 2797                 nd->nd_repstat = EEXIST;
 2798         /*
 2799          * Do the open locking/delegation stuff.
 2800          */
 2801         if (!nd->nd_repstat)
 2802             nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
 2803                 &delegstateid, &rflags, exp, p, nva.na_filerev);
 2804 
 2805         /*
 2806          * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
 2807          * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
 2808          * (ie: Leave the NFSVOPUNLOCK() about here.)
 2809          */
 2810         if (vp)
 2811                 NFSVOPUNLOCK(vp, 0);
 2812         if (stp)
 2813                 FREE((caddr_t)stp, M_NFSDSTATE);
 2814         if (!nd->nd_repstat && dirp)
 2815                 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
 2816                     0);
 2817         if (!nd->nd_repstat) {
 2818                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
 2819                 *tl++ = txdr_unsigned(stateid.seqid);
 2820                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
 2821                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 2822                 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
 2823                         *tl++ = newnfs_true;
 2824                         *tl++ = 0;
 2825                         *tl++ = 0;
 2826                         *tl++ = 0;
 2827                         *tl++ = 0;
 2828                 } else {
 2829                         *tl++ = newnfs_false;   /* Since dirp is not locked */
 2830                         txdr_hyper(dirfor.na_filerev, tl);
 2831                         tl += 2;
 2832                         txdr_hyper(diraft.na_filerev, tl);
 2833                         tl += 2;
 2834                 }
 2835                 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
 2836                 (void) nfsrv_putattrbit(nd, &attrbits);
 2837                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2838                 if (rflags & NFSV4OPEN_READDELEGATE)
 2839                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
 2840                 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
 2841                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
 2842                 else
 2843                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
 2844                 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
 2845                         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
 2846                         *tl++ = txdr_unsigned(delegstateid.seqid);
 2847                         NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
 2848                             NFSX_STATEIDOTHER);
 2849                         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 2850                         if (rflags & NFSV4OPEN_RECALL)
 2851                                 *tl = newnfs_true;
 2852                         else
 2853                                 *tl = newnfs_false;
 2854                         if (rflags & NFSV4OPEN_WRITEDELEGATE) {
 2855                                 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 2856                                 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
 2857                                 txdr_hyper(nva.na_size, tl);
 2858                         }
 2859                         NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 2860                         *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
 2861                         *tl++ = txdr_unsigned(0x0);
 2862                         acemask = NFSV4ACE_ALLFILESMASK;
 2863                         if (nva.na_mode & S_IRUSR)
 2864                             acemask |= NFSV4ACE_READMASK;
 2865                         if (nva.na_mode & S_IWUSR)
 2866                             acemask |= NFSV4ACE_WRITEMASK;
 2867                         if (nva.na_mode & S_IXUSR)
 2868                             acemask |= NFSV4ACE_EXECUTEMASK;
 2869                         *tl = txdr_unsigned(acemask);
 2870                         (void) nfsm_strtom(nd, "OWNER@", 6);
 2871                 }
 2872                 *vpp = vp;
 2873         } else if (vp) {
 2874                 vrele(vp);
 2875         }
 2876         if (dirp)
 2877                 vrele(dirp);
 2878 #ifdef NFS4_ACL_EXTATTR_NAME
 2879         acl_free(aclp);
 2880 #endif
 2881         NFSEXITCODE2(0, nd);
 2882         return (0);
 2883 nfsmout:
 2884         vrele(dp);
 2885 #ifdef NFS4_ACL_EXTATTR_NAME
 2886         acl_free(aclp);
 2887 #endif
 2888         if (stp)
 2889                 FREE((caddr_t)stp, M_NFSDSTATE);
 2890         NFSEXITCODE2(error, nd);
 2891         return (error);
 2892 }
 2893 
 2894 /*
 2895  * nfsv4 close service
 2896  */
 2897 APPLESTATIC int
 2898 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
 2899     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 2900 {
 2901         u_int32_t *tl;
 2902         struct nfsstate st, *stp = &st;
 2903         int error = 0;
 2904         nfsv4stateid_t stateid;
 2905         nfsquad_t clientid;
 2906 
 2907         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
 2908         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
 2909         stp->ls_ownerlen = 0;
 2910         stp->ls_op = nd->nd_rp;
 2911         stp->ls_uid = nd->nd_cred->cr_uid;
 2912         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 2913         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 2914             NFSX_STATEIDOTHER);
 2915         stp->ls_flags = NFSLCK_CLOSE;
 2916         clientid.lval[0] = stp->ls_stateid.other[0];
 2917         clientid.lval[1] = stp->ls_stateid.other[1];
 2918         if (nd->nd_flag & ND_IMPLIEDCLID) {
 2919                 if (nd->nd_clientid.qval != clientid.qval)
 2920                         printf("EEK! multiple clids\n");
 2921         } else {
 2922                 nd->nd_flag |= ND_IMPLIEDCLID;
 2923                 nd->nd_clientid.qval = clientid.qval;
 2924         }
 2925         nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
 2926         vput(vp);
 2927         if (!nd->nd_repstat) {
 2928                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 2929                 *tl++ = txdr_unsigned(stateid.seqid);
 2930                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
 2931         }
 2932         NFSEXITCODE2(0, nd);
 2933         return (0);
 2934 nfsmout:
 2935         vput(vp);
 2936         NFSEXITCODE2(error, nd);
 2937         return (error);
 2938 }
 2939 
 2940 /*
 2941  * nfsv4 delegpurge service
 2942  */
 2943 APPLESTATIC int
 2944 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
 2945     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
 2946 {
 2947         u_int32_t *tl;
 2948         int error = 0;
 2949         nfsquad_t clientid;
 2950 
 2951         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
 2952                 nd->nd_repstat = NFSERR_WRONGSEC;
 2953                 goto nfsmout;
 2954         }
 2955         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2956         clientid.lval[0] = *tl++;
 2957         clientid.lval[1] = *tl;
 2958         if (nd->nd_flag & ND_IMPLIEDCLID) {
 2959                 if (nd->nd_clientid.qval != clientid.qval)
 2960                         printf("EEK! multiple clids\n");
 2961         } else {
 2962                 nd->nd_flag |= ND_IMPLIEDCLID;
 2963                 nd->nd_clientid.qval = clientid.qval;
 2964         }
 2965         nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL,
 2966             NFSV4OP_DELEGPURGE, nd->nd_cred, p);
 2967 nfsmout:
 2968         NFSEXITCODE2(error, nd);
 2969         return (error);
 2970 }
 2971 
 2972 /*
 2973  * nfsv4 delegreturn service
 2974  */
 2975 APPLESTATIC int
 2976 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
 2977     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 2978 {
 2979         u_int32_t *tl;
 2980         int error = 0;
 2981         nfsv4stateid_t stateid;
 2982         nfsquad_t clientid;
 2983 
 2984         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
 2985         stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 2986         NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
 2987         clientid.lval[0] = stateid.other[0];
 2988         clientid.lval[1] = stateid.other[1];
 2989         if (nd->nd_flag & ND_IMPLIEDCLID) {
 2990                 if (nd->nd_clientid.qval != clientid.qval)
 2991                         printf("EEK! multiple clids\n");
 2992         } else {
 2993                 nd->nd_flag |= ND_IMPLIEDCLID;
 2994                 nd->nd_clientid.qval = clientid.qval;
 2995         }
 2996         nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp,
 2997             NFSV4OP_DELEGRETURN, nd->nd_cred, p);
 2998 nfsmout:
 2999         vput(vp);
 3000         NFSEXITCODE2(error, nd);
 3001         return (error);
 3002 }
 3003 
 3004 /*
 3005  * nfsv4 get file handle service
 3006  */
 3007 APPLESTATIC int
 3008 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
 3009     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 3010 {
 3011         fhandle_t fh;
 3012 
 3013         nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
 3014         vput(vp);
 3015         if (!nd->nd_repstat)
 3016                 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
 3017         NFSEXITCODE2(0, nd);
 3018         return (0);
 3019 }
 3020 
 3021 /*
 3022  * nfsv4 open confirm service
 3023  */
 3024 APPLESTATIC int
 3025 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
 3026     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 3027 {
 3028         u_int32_t *tl;
 3029         struct nfsstate st, *stp = &st;
 3030         int error = 0;
 3031         nfsv4stateid_t stateid;
 3032         nfsquad_t clientid;
 3033 
 3034         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
 3035         stp->ls_ownerlen = 0;
 3036         stp->ls_op = nd->nd_rp;
 3037         stp->ls_uid = nd->nd_cred->cr_uid;
 3038         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 3039         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 3040             NFSX_STATEIDOTHER);
 3041         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 3042         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
 3043         stp->ls_flags = NFSLCK_CONFIRM;
 3044         clientid.lval[0] = stp->ls_stateid.other[0];
 3045         clientid.lval[1] = stp->ls_stateid.other[1];
 3046         if (nd->nd_flag & ND_IMPLIEDCLID) {
 3047                 if (nd->nd_clientid.qval != clientid.qval)
 3048                         printf("EEK! multiple clids\n");
 3049         } else {
 3050                 nd->nd_flag |= ND_IMPLIEDCLID;
 3051                 nd->nd_clientid.qval = clientid.qval;
 3052         }
 3053         nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
 3054         if (!nd->nd_repstat) {
 3055                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 3056                 *tl++ = txdr_unsigned(stateid.seqid);
 3057                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
 3058         }
 3059 nfsmout:
 3060         vput(vp);
 3061         NFSEXITCODE2(error, nd);
 3062         return (error);
 3063 }
 3064 
 3065 /*
 3066  * nfsv4 open downgrade service
 3067  */
 3068 APPLESTATIC int
 3069 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
 3070     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 3071 {
 3072         u_int32_t *tl;
 3073         int i;
 3074         struct nfsstate st, *stp = &st;
 3075         int error = 0;
 3076         nfsv4stateid_t stateid;
 3077         nfsquad_t clientid;
 3078 
 3079         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
 3080         stp->ls_ownerlen = 0;
 3081         stp->ls_op = nd->nd_rp;
 3082         stp->ls_uid = nd->nd_cred->cr_uid;
 3083         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 3084         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 3085             NFSX_STATEIDOTHER);
 3086         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 3087         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
 3088         i = fxdr_unsigned(int, *tl++);
 3089         switch (i) {
 3090         case NFSV4OPEN_ACCESSREAD:
 3091                 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
 3092                 break;
 3093         case NFSV4OPEN_ACCESSWRITE:
 3094                 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
 3095                 break;
 3096         case NFSV4OPEN_ACCESSBOTH:
 3097                 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
 3098                     NFSLCK_DOWNGRADE);
 3099                 break;
 3100         default:
 3101                 nd->nd_repstat = NFSERR_BADXDR;
 3102         };
 3103         i = fxdr_unsigned(int, *tl);
 3104         switch (i) {
 3105         case NFSV4OPEN_DENYNONE:
 3106                 break;
 3107         case NFSV4OPEN_DENYREAD:
 3108                 stp->ls_flags |= NFSLCK_READDENY;
 3109                 break;
 3110         case NFSV4OPEN_DENYWRITE:
 3111                 stp->ls_flags |= NFSLCK_WRITEDENY;
 3112                 break;
 3113         case NFSV4OPEN_DENYBOTH:
 3114                 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
 3115                 break;
 3116         default:
 3117                 nd->nd_repstat = NFSERR_BADXDR;
 3118         };
 3119 
 3120         clientid.lval[0] = stp->ls_stateid.other[0];
 3121         clientid.lval[1] = stp->ls_stateid.other[1];
 3122         if (nd->nd_flag & ND_IMPLIEDCLID) {
 3123                 if (nd->nd_clientid.qval != clientid.qval)
 3124                         printf("EEK! multiple clids\n");
 3125         } else {
 3126                 nd->nd_flag |= ND_IMPLIEDCLID;
 3127                 nd->nd_clientid.qval = clientid.qval;
 3128         }
 3129         if (!nd->nd_repstat)
 3130                 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
 3131                     nd, p);
 3132         if (!nd->nd_repstat) {
 3133                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 3134                 *tl++ = txdr_unsigned(stateid.seqid);
 3135                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
 3136         }
 3137 nfsmout:
 3138         vput(vp);
 3139         NFSEXITCODE2(error, nd);
 3140         return (error);
 3141 }
 3142 
 3143 /*
 3144  * nfsv4 renew lease service
 3145  */
 3146 APPLESTATIC int
 3147 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
 3148     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 3149 {
 3150         u_int32_t *tl;
 3151         int error = 0;
 3152         nfsquad_t clientid;
 3153 
 3154         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
 3155                 nd->nd_repstat = NFSERR_WRONGSEC;
 3156                 goto nfsmout;
 3157         }
 3158         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 3159         clientid.lval[0] = *tl++;
 3160         clientid.lval[1] = *tl;
 3161         if (nd->nd_flag & ND_IMPLIEDCLID) {
 3162                 if (nd->nd_clientid.qval != clientid.qval)
 3163                         printf("EEK! multiple clids\n");
 3164         } else {
 3165                 nd->nd_flag |= ND_IMPLIEDCLID;
 3166                 nd->nd_clientid.qval = clientid.qval;
 3167         }
 3168         nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
 3169             NULL, (nfsquad_t)((u_quad_t)0), nd, p);
 3170 nfsmout:
 3171         NFSEXITCODE2(error, nd);
 3172         return (error);
 3173 }
 3174 
 3175 /*
 3176  * nfsv4 security info service
 3177  */
 3178 APPLESTATIC int
 3179 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
 3180     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
 3181 {
 3182         u_int32_t *tl;
 3183         int len;
 3184         struct nameidata named;
 3185         vnode_t dirp = NULL, vp;
 3186         struct nfsrvfh fh;
 3187         struct nfsexstuff retnes;
 3188         u_int32_t *sizp;
 3189         int error = 0, savflag, i;
 3190         char *bufp;
 3191         u_long *hashp;
 3192 
 3193         /*
 3194          * All this just to get the export flags for the name.
 3195          */
 3196         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
 3197             LOCKLEAF | SAVESTART);
 3198         nfsvno_setpathbuf(&named, &bufp, &hashp);
 3199         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
 3200         if (error) {
 3201                 vput(dp);
 3202                 nfsvno_relpathbuf(&named);
 3203                 goto out;
 3204         }
 3205         if (!nd->nd_repstat) {
 3206                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
 3207         } else {
 3208                 vput(dp);
 3209                 nfsvno_relpathbuf(&named);
 3210         }
 3211         if (dirp)
 3212                 vrele(dirp);
 3213         if (nd->nd_repstat)
 3214                 goto out;
 3215         vrele(named.ni_startdir);
 3216         nfsvno_relpathbuf(&named);
 3217         fh.nfsrvfh_len = NFSX_MYFH;
 3218         vp = named.ni_vp;
 3219         nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
 3220         vput(vp);
 3221         savflag = nd->nd_flag;
 3222         if (!nd->nd_repstat) {
 3223                 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p);
 3224                 if (vp)
 3225                         vput(vp);
 3226         }
 3227         nd->nd_flag = savflag;
 3228         if (nd->nd_repstat)
 3229                 goto out;
 3230 
 3231         /*
 3232          * Finally have the export flags for name, so we can create
 3233          * the security info.
 3234          */
 3235         len = 0;
 3236         NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
 3237         for (i = 0; i < retnes.nes_numsecflavor; i++) {
 3238                 if (retnes.nes_secflavors[i] == AUTH_SYS) {
 3239                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3240                         *tl = txdr_unsigned(RPCAUTH_UNIX);
 3241                         len++;
 3242                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
 3243                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3244                         *tl++ = txdr_unsigned(RPCAUTH_GSS);
 3245                         (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
 3246                             nfsgss_mechlist[KERBV_MECH].len);
 3247                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 3248                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
 3249                         *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
 3250                         len++;
 3251                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
 3252                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3253                         *tl++ = txdr_unsigned(RPCAUTH_GSS);
 3254                         (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
 3255                             nfsgss_mechlist[KERBV_MECH].len);
 3256                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 3257                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
 3258                         *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
 3259                         len++;
 3260                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
 3261                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3262                         *tl++ = txdr_unsigned(RPCAUTH_GSS);
 3263                         (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
 3264                             nfsgss_mechlist[KERBV_MECH].len);
 3265                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 3266                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
 3267                         *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
 3268                         len++;
 3269                 }
 3270         }
 3271         *sizp = txdr_unsigned(len);
 3272 
 3273 out:
 3274         NFSEXITCODE2(error, nd);
 3275         return (error);
 3276 }
 3277 
 3278 /*
 3279  * nfsv4 set client id service
 3280  */
 3281 APPLESTATIC int
 3282 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
 3283     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 3284 {
 3285         u_int32_t *tl;
 3286         int i;
 3287         int error = 0, idlen;
 3288         struct nfsclient *clp = NULL;
 3289         struct sockaddr_in *rad;
 3290         u_char *verf, *ucp, *ucp2, addrbuf[24];
 3291         nfsquad_t clientid, confirm;
 3292 
 3293         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
 3294                 nd->nd_repstat = NFSERR_WRONGSEC;
 3295                 goto out;
 3296         }
 3297         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
 3298         verf = (u_char *)tl;
 3299         tl += (NFSX_VERF / NFSX_UNSIGNED);
 3300         i = fxdr_unsigned(int, *tl);
 3301         if (i > NFSV4_OPAQUELIMIT || i <= 0) {
 3302                 nd->nd_repstat = NFSERR_BADXDR;
 3303                 goto nfsmout;
 3304         }
 3305         idlen = i;
 3306         if (nd->nd_flag & ND_GSS)
 3307                 i += nd->nd_princlen;
 3308         MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i,
 3309             M_NFSDCLIENT, M_WAITOK);
 3310         NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i);
 3311         NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
 3312         NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
 3313         NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
 3314         clp->lc_req.nr_cred = NULL;
 3315         NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
 3316         clp->lc_idlen = idlen;
 3317         error = nfsrv_mtostr(nd, clp->lc_id, idlen);
 3318         if (error)
 3319                 goto nfsmout;
 3320         if (nd->nd_flag & ND_GSS) {
 3321                 clp->lc_flags = LCL_GSS;
 3322                 if (nd->nd_flag & ND_GSSINTEGRITY)
 3323                         clp->lc_flags |= LCL_GSSINTEGRITY;
 3324                 else if (nd->nd_flag & ND_GSSPRIVACY)
 3325                         clp->lc_flags |= LCL_GSSPRIVACY;
 3326         } else {
 3327                 clp->lc_flags = 0;
 3328         }
 3329         if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
 3330                 clp->lc_flags |= LCL_NAME;
 3331                 clp->lc_namelen = nd->nd_princlen;
 3332                 clp->lc_name = &clp->lc_id[idlen];
 3333                 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
 3334         } else {
 3335                 clp->lc_uid = nd->nd_cred->cr_uid;
 3336                 clp->lc_gid = nd->nd_cred->cr_gid;
 3337         }
 3338         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3339         clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
 3340         error = nfsrv_getclientipaddr(nd, clp);
 3341         if (error)
 3342                 goto nfsmout;
 3343         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3344         clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
 3345 
 3346         /*
 3347          * nfsrv_setclient() does the actual work of adding it to the
 3348          * client list. If there is no error, the structure has been
 3349          * linked into the client list and clp should no longer be used
 3350          * here. When an error is returned, it has not been linked in,
 3351          * so it should be free'd.
 3352          */
 3353         nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
 3354         if (nd->nd_repstat == NFSERR_CLIDINUSE) {
 3355                 if (clp->lc_flags & LCL_TCPCALLBACK)
 3356                         (void) nfsm_strtom(nd, "tcp", 3);
 3357                 else 
 3358                         (void) nfsm_strtom(nd, "udp", 3);
 3359                 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
 3360                 ucp = (u_char *)&rad->sin_addr.s_addr;
 3361                 ucp2 = (u_char *)&rad->sin_port;
 3362                 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
 3363                     ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
 3364                     ucp2[0] & 0xff, ucp2[1] & 0xff);
 3365                 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
 3366         }
 3367         if (clp) {
 3368                 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
 3369                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
 3370                 free((caddr_t)clp, M_NFSDCLIENT);
 3371         }
 3372         if (!nd->nd_repstat) {
 3373                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
 3374                 *tl++ = clientid.lval[0];
 3375                 *tl++ = clientid.lval[1];
 3376                 *tl++ = confirm.lval[0];
 3377                 *tl = confirm.lval[1];
 3378         }
 3379 
 3380 out:
 3381         NFSEXITCODE2(0, nd);
 3382         return (0);
 3383 nfsmout:
 3384         if (clp) {
 3385                 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
 3386                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
 3387                 free((caddr_t)clp, M_NFSDCLIENT);
 3388         }
 3389         NFSEXITCODE2(error, nd);
 3390         return (error);
 3391 }
 3392 
 3393 /*
 3394  * nfsv4 set client id confirm service
 3395  */
 3396 APPLESTATIC int
 3397 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
 3398     __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
 3399     __unused struct nfsexstuff *exp)
 3400 {
 3401         u_int32_t *tl;
 3402         int error = 0;
 3403         nfsquad_t clientid, confirm;
 3404 
 3405         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
 3406                 nd->nd_repstat = NFSERR_WRONGSEC;
 3407                 goto nfsmout;
 3408         }
 3409         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
 3410         clientid.lval[0] = *tl++;
 3411         clientid.lval[1] = *tl++;
 3412         confirm.lval[0] = *tl++;
 3413         confirm.lval[1] = *tl;
 3414 
 3415         /*
 3416          * nfsrv_getclient() searches the client list for a match and
 3417          * returns the appropriate NFSERR status.
 3418          */
 3419         nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
 3420             NULL, confirm, nd, p);
 3421 nfsmout:
 3422         NFSEXITCODE2(error, nd);
 3423         return (error);
 3424 }
 3425 
 3426 /*
 3427  * nfsv4 verify service
 3428  */
 3429 APPLESTATIC int
 3430 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
 3431     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 3432 {
 3433         int error = 0, ret, fhsize = NFSX_MYFH;
 3434         struct nfsvattr nva;
 3435         struct statfs sf;
 3436         struct nfsfsinfo fs;
 3437         fhandle_t fh;
 3438 
 3439         nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
 3440         if (!nd->nd_repstat)
 3441                 nd->nd_repstat = nfsvno_statfs(vp, &sf);
 3442         if (!nd->nd_repstat)
 3443                 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
 3444         if (!nd->nd_repstat) {
 3445                 nfsvno_getfs(&fs, isdgram);
 3446                 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
 3447                     &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
 3448                 if (!error) {
 3449                         if (nd->nd_procnum == NFSV4OP_NVERIFY) {
 3450                                 if (ret == 0)
 3451                                         nd->nd_repstat = NFSERR_SAME;
 3452                                 else if (ret != NFSERR_NOTSAME)
 3453                                         nd->nd_repstat = ret;
 3454                         } else if (ret)
 3455                                 nd->nd_repstat = ret;
 3456                 }
 3457         }
 3458         vput(vp);
 3459         NFSEXITCODE2(error, nd);
 3460         return (error);
 3461 }
 3462 
 3463 /*
 3464  * nfs openattr rpc
 3465  */
 3466 APPLESTATIC int
 3467 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
 3468     vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
 3469     __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
 3470 {
 3471         u_int32_t *tl;
 3472         int error = 0, createdir;
 3473 
 3474         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3475         createdir = fxdr_unsigned(int, *tl);
 3476         nd->nd_repstat = NFSERR_NOTSUPP;
 3477 nfsmout:
 3478         vrele(dp);
 3479         NFSEXITCODE2(error, nd);
 3480         return (error);
 3481 }
 3482 
 3483 /*
 3484  * nfsv4 release lock owner service
 3485  */
 3486 APPLESTATIC int
 3487 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
 3488     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 3489 {
 3490         u_int32_t *tl;
 3491         struct nfsstate *stp = NULL;
 3492         int error = 0, len;
 3493         nfsquad_t clientid;
 3494 
 3495         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
 3496                 nd->nd_repstat = NFSERR_WRONGSEC;
 3497                 goto nfsmout;
 3498         }
 3499         NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 3500         len = fxdr_unsigned(int, *(tl + 2));
 3501         if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
 3502                 nd->nd_repstat = NFSERR_BADXDR;
 3503                 goto nfsmout;
 3504         }
 3505         MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
 3506             M_NFSDSTATE, M_WAITOK);
 3507         stp->ls_ownerlen = len;
 3508         stp->ls_op = NULL;
 3509         stp->ls_flags = NFSLCK_RELEASE;
 3510         stp->ls_uid = nd->nd_cred->cr_uid;
 3511         clientid.lval[0] = *tl++;
 3512         clientid.lval[1] = *tl;
 3513         if (nd->nd_flag & ND_IMPLIEDCLID) {
 3514                 if (nd->nd_clientid.qval != clientid.qval)
 3515                         printf("EEK! multiple clids\n");
 3516         } else {
 3517                 nd->nd_flag |= ND_IMPLIEDCLID;
 3518                 nd->nd_clientid.qval = clientid.qval;
 3519         }
 3520         error = nfsrv_mtostr(nd, stp->ls_owner, len);
 3521         if (error)
 3522                 goto nfsmout;
 3523         nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
 3524         FREE((caddr_t)stp, M_NFSDSTATE);
 3525 
 3526         NFSEXITCODE2(0, nd);
 3527         return (0);
 3528 nfsmout:
 3529         if (stp)
 3530                 free((caddr_t)stp, M_NFSDSTATE);
 3531         NFSEXITCODE2(error, nd);
 3532         return (error);
 3533 }

Cache object: 85292a1716a6d2b0ac687872322ea56f


[ 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.