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

Cache object: 5373877e3a9933bc49755509b6374cbf


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