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/nfsserver/nfs_srvsubs.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  *      @(#)nfs_subs.c  8.8 (Berkeley) 5/22/95
   33  */
   34 
   35 #include <sys/cdefs.h>
   36 __FBSDID("$FreeBSD: releng/8.0/sys/nfsserver/nfs_srvsubs.c 195202 2009-06-30 19:03:27Z dfr $");
   37 
   38 /*
   39  * These functions support the macros and help fiddle mbuf chains for
   40  * the nfs op functions. They do things like create the rpc header and
   41  * copy data between mbuf chains and uio lists.
   42  */
   43 
   44 #include "opt_inet6.h"
   45 
   46 #include <sys/param.h>
   47 #include <sys/systm.h>
   48 #include <sys/kernel.h>
   49 #include <sys/bio.h>
   50 #include <sys/buf.h>
   51 #include <sys/proc.h>
   52 #include <sys/mount.h>
   53 #include <sys/vnode.h>
   54 #include <sys/namei.h>
   55 #include <sys/mbuf.h>
   56 #include <sys/refcount.h>
   57 #include <sys/socket.h>
   58 #include <sys/stat.h>
   59 #include <sys/malloc.h>
   60 #include <sys/module.h>
   61 #include <sys/sysent.h>
   62 #include <sys/syscall.h>
   63 #include <sys/sysproto.h>
   64 
   65 #include <vm/vm.h>
   66 #include <vm/vm_object.h>
   67 #include <vm/vm_extern.h>
   68 #include <vm/uma.h>
   69 
   70 #include <rpc/rpc.h>
   71 
   72 #include <nfs/nfsproto.h>
   73 #include <nfsserver/nfs.h>
   74 #include <nfs/xdr_subs.h>
   75 #include <nfsserver/nfsm_subs.h>
   76 
   77 #include <netinet/in.h>
   78 
   79 /*
   80  * Data items converted to xdr at startup, since they are constant
   81  * This is kinda hokey, but may save a little time doing byte swaps
   82  */
   83 u_int32_t nfsrv_nfs_xdrneg1;
   84 u_int32_t nfsrv_nfs_true, nfsrv_nfs_false;
   85 
   86 /* And other global data */
   87 static const nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR,
   88                                        NFLNK, NFNON, NFCHR, NFNON };
   89 #define vtonfsv2_type(a)        txdr_unsigned(nfsv2_type[((int32_t)(a))])
   90 #define vtonfsv3_mode(m)        txdr_unsigned((m) & ALLPERMS)
   91 
   92 int nfsrv_ticks;
   93 
   94 struct mtx nfsd_mtx;
   95 
   96 /*
   97  * Mapping of old NFS Version 2 RPC numbers to generic numbers.
   98  */
   99 const int nfsrv_nfsv3_procid[NFS_NPROCS] = {
  100         NFSPROC_NULL,
  101         NFSPROC_GETATTR,
  102         NFSPROC_SETATTR,
  103         NFSPROC_NOOP,
  104         NFSPROC_LOOKUP,
  105         NFSPROC_READLINK,
  106         NFSPROC_READ,
  107         NFSPROC_NOOP,
  108         NFSPROC_WRITE,
  109         NFSPROC_CREATE,
  110         NFSPROC_REMOVE,
  111         NFSPROC_RENAME,
  112         NFSPROC_LINK,
  113         NFSPROC_SYMLINK,
  114         NFSPROC_MKDIR,
  115         NFSPROC_RMDIR,
  116         NFSPROC_READDIR,
  117         NFSPROC_FSSTAT,
  118         NFSPROC_NOOP,
  119         NFSPROC_NOOP,
  120         NFSPROC_NOOP,
  121         NFSPROC_NOOP,
  122         NFSPROC_NOOP,
  123 };
  124 
  125 /*
  126  * and the reverse mapping from generic to Version 2 procedure numbers
  127  */
  128 const int nfsrvv2_procid[NFS_NPROCS] = {
  129         NFSV2PROC_NULL,
  130         NFSV2PROC_GETATTR,
  131         NFSV2PROC_SETATTR,
  132         NFSV2PROC_LOOKUP,
  133         NFSV2PROC_NOOP,
  134         NFSV2PROC_READLINK,
  135         NFSV2PROC_READ,
  136         NFSV2PROC_WRITE,
  137         NFSV2PROC_CREATE,
  138         NFSV2PROC_MKDIR,
  139         NFSV2PROC_SYMLINK,
  140         NFSV2PROC_CREATE,
  141         NFSV2PROC_REMOVE,
  142         NFSV2PROC_RMDIR,
  143         NFSV2PROC_RENAME,
  144         NFSV2PROC_LINK,
  145         NFSV2PROC_READDIR,
  146         NFSV2PROC_NOOP,
  147         NFSV2PROC_STATFS,
  148         NFSV2PROC_NOOP,
  149         NFSV2PROC_NOOP,
  150         NFSV2PROC_NOOP,
  151         NFSV2PROC_NOOP,
  152 };
  153 
  154 /*
  155  * Maps errno values to nfs error numbers.
  156  * Use 0 (which gets converted to NFSERR_IO) as the catch all for ones not
  157  * specifically defined in RFC 1094.
  158  */
  159 static const u_char nfsrv_v2errmap[ELAST] = {
  160   NFSERR_PERM,  NFSERR_NOENT,   0,              0,              0,      
  161   NFSERR_NXIO,  0,              0,              0,              0,      
  162   0,            0,              NFSERR_ACCES,   0,              0,      
  163   0,            NFSERR_EXIST,   0,              NFSERR_NODEV,   NFSERR_NOTDIR,
  164   NFSERR_ISDIR, 0,              0,              0,              0,      
  165   0,            NFSERR_FBIG,    NFSERR_NOSPC,   0,              NFSERR_ROFS,
  166   0,            0,              0,              0,              0,      
  167   0,            0,              0,              0,              0,      
  168   0,            0,              0,              0,              0,      
  169   0,            0,              0,              0,              0,      
  170   0,            0,              0,              0,              0,      
  171   0,            0,              0,              0,              0,      
  172   0,            0,              NFSERR_NAMETOL, 0,              0,      
  173   NFSERR_NOTEMPTY, 0,           0,              NFSERR_DQUOT,   NFSERR_STALE,
  174   0
  175 };
  176 
  177 /*
  178  * Maps errno values to nfs error numbers.
  179  * Although it is not obvious whether or not NFS clients really care if
  180  * a returned error value is in the specified list for the procedure, the
  181  * safest thing to do is filter them appropriately. For Version 2, the
  182  * X/Open XNFS document is the only specification that defines error values
  183  * for each RPC (The RFC simply lists all possible error values for all RPCs),
  184  * so I have decided to not do this for Version 2.
  185  * The first entry is the default error return and the rest are the valid
  186  * errors for that RPC in increasing numeric order.
  187  */
  188 static const short nfsv3err_null[] = {
  189         0,
  190         0,
  191 };
  192 
  193 static const short nfsv3err_getattr[] = {
  194         NFSERR_IO,
  195         NFSERR_IO,
  196         NFSERR_STALE,
  197         NFSERR_BADHANDLE,
  198         NFSERR_SERVERFAULT,
  199         0,
  200 };
  201 
  202 static const short nfsv3err_setattr[] = {
  203         NFSERR_IO,
  204         NFSERR_PERM,
  205         NFSERR_IO,
  206         NFSERR_ACCES,
  207         NFSERR_INVAL,
  208         NFSERR_NOSPC,
  209         NFSERR_ROFS,
  210         NFSERR_DQUOT,
  211         NFSERR_STALE,
  212         NFSERR_BADHANDLE,
  213         NFSERR_NOT_SYNC,
  214         NFSERR_SERVERFAULT,
  215         0,
  216 };
  217 
  218 static const short nfsv3err_lookup[] = {
  219         NFSERR_IO,
  220         NFSERR_NOENT,
  221         NFSERR_IO,
  222         NFSERR_ACCES,
  223         NFSERR_NOTDIR,
  224         NFSERR_NAMETOL,
  225         NFSERR_STALE,
  226         NFSERR_BADHANDLE,
  227         NFSERR_SERVERFAULT,
  228         0,
  229 };
  230 
  231 static const short nfsv3err_access[] = {
  232         NFSERR_IO,
  233         NFSERR_IO,
  234         NFSERR_STALE,
  235         NFSERR_BADHANDLE,
  236         NFSERR_SERVERFAULT,
  237         0,
  238 };
  239 
  240 static const short nfsv3err_readlink[] = {
  241         NFSERR_IO,
  242         NFSERR_IO,
  243         NFSERR_ACCES,
  244         NFSERR_INVAL,
  245         NFSERR_STALE,
  246         NFSERR_BADHANDLE,
  247         NFSERR_NOTSUPP,
  248         NFSERR_SERVERFAULT,
  249         0,
  250 };
  251 
  252 static const short nfsv3err_read[] = {
  253         NFSERR_IO,
  254         NFSERR_IO,
  255         NFSERR_NXIO,
  256         NFSERR_ACCES,
  257         NFSERR_INVAL,
  258         NFSERR_STALE,
  259         NFSERR_BADHANDLE,
  260         NFSERR_SERVERFAULT,
  261         0,
  262 };
  263 
  264 static const short nfsv3err_write[] = {
  265         NFSERR_IO,
  266         NFSERR_IO,
  267         NFSERR_ACCES,
  268         NFSERR_INVAL,
  269         NFSERR_FBIG,
  270         NFSERR_NOSPC,
  271         NFSERR_ROFS,
  272         NFSERR_DQUOT,
  273         NFSERR_STALE,
  274         NFSERR_BADHANDLE,
  275         NFSERR_SERVERFAULT,
  276         0,
  277 };
  278 
  279 static const short nfsv3err_create[] = {
  280         NFSERR_IO,
  281         NFSERR_IO,
  282         NFSERR_ACCES,
  283         NFSERR_EXIST,
  284         NFSERR_NOTDIR,
  285         NFSERR_NOSPC,
  286         NFSERR_ROFS,
  287         NFSERR_NAMETOL,
  288         NFSERR_DQUOT,
  289         NFSERR_STALE,
  290         NFSERR_BADHANDLE,
  291         NFSERR_NOTSUPP,
  292         NFSERR_SERVERFAULT,
  293         0,
  294 };
  295 
  296 static const short nfsv3err_mkdir[] = {
  297         NFSERR_IO,
  298         NFSERR_IO,
  299         NFSERR_ACCES,
  300         NFSERR_EXIST,
  301         NFSERR_NOTDIR,
  302         NFSERR_NOSPC,
  303         NFSERR_ROFS,
  304         NFSERR_NAMETOL,
  305         NFSERR_DQUOT,
  306         NFSERR_STALE,
  307         NFSERR_BADHANDLE,
  308         NFSERR_NOTSUPP,
  309         NFSERR_SERVERFAULT,
  310         0,
  311 };
  312 
  313 static const short nfsv3err_symlink[] = {
  314         NFSERR_IO,
  315         NFSERR_IO,
  316         NFSERR_ACCES,
  317         NFSERR_EXIST,
  318         NFSERR_NOTDIR,
  319         NFSERR_NOSPC,
  320         NFSERR_ROFS,
  321         NFSERR_NAMETOL,
  322         NFSERR_DQUOT,
  323         NFSERR_STALE,
  324         NFSERR_BADHANDLE,
  325         NFSERR_NOTSUPP,
  326         NFSERR_SERVERFAULT,
  327         0,
  328 };
  329 
  330 static const short nfsv3err_mknod[] = {
  331         NFSERR_IO,
  332         NFSERR_IO,
  333         NFSERR_ACCES,
  334         NFSERR_EXIST,
  335         NFSERR_NOTDIR,
  336         NFSERR_NOSPC,
  337         NFSERR_ROFS,
  338         NFSERR_NAMETOL,
  339         NFSERR_DQUOT,
  340         NFSERR_STALE,
  341         NFSERR_BADHANDLE,
  342         NFSERR_NOTSUPP,
  343         NFSERR_SERVERFAULT,
  344         NFSERR_BADTYPE,
  345         0,
  346 };
  347 
  348 static const short nfsv3err_remove[] = {
  349         NFSERR_IO,
  350         NFSERR_NOENT,
  351         NFSERR_IO,
  352         NFSERR_ACCES,
  353         NFSERR_NOTDIR,
  354         NFSERR_ROFS,
  355         NFSERR_NAMETOL,
  356         NFSERR_STALE,
  357         NFSERR_BADHANDLE,
  358         NFSERR_SERVERFAULT,
  359         0,
  360 };
  361 
  362 static const short nfsv3err_rmdir[] = {
  363         NFSERR_IO,
  364         NFSERR_NOENT,
  365         NFSERR_IO,
  366         NFSERR_ACCES,
  367         NFSERR_EXIST,
  368         NFSERR_NOTDIR,
  369         NFSERR_INVAL,
  370         NFSERR_ROFS,
  371         NFSERR_NAMETOL,
  372         NFSERR_NOTEMPTY,
  373         NFSERR_STALE,
  374         NFSERR_BADHANDLE,
  375         NFSERR_NOTSUPP,
  376         NFSERR_SERVERFAULT,
  377         0,
  378 };
  379 
  380 static const short nfsv3err_rename[] = {
  381         NFSERR_IO,
  382         NFSERR_NOENT,
  383         NFSERR_IO,
  384         NFSERR_ACCES,
  385         NFSERR_EXIST,
  386         NFSERR_XDEV,
  387         NFSERR_NOTDIR,
  388         NFSERR_ISDIR,
  389         NFSERR_INVAL,
  390         NFSERR_NOSPC,
  391         NFSERR_ROFS,
  392         NFSERR_MLINK,
  393         NFSERR_NAMETOL,
  394         NFSERR_NOTEMPTY,
  395         NFSERR_DQUOT,
  396         NFSERR_STALE,
  397         NFSERR_BADHANDLE,
  398         NFSERR_NOTSUPP,
  399         NFSERR_SERVERFAULT,
  400         0,
  401 };
  402 
  403 static const short nfsv3err_link[] = {
  404         NFSERR_IO,
  405         NFSERR_IO,
  406         NFSERR_ACCES,
  407         NFSERR_EXIST,
  408         NFSERR_XDEV,
  409         NFSERR_NOTDIR,
  410         NFSERR_INVAL,
  411         NFSERR_NOSPC,
  412         NFSERR_ROFS,
  413         NFSERR_MLINK,
  414         NFSERR_NAMETOL,
  415         NFSERR_DQUOT,
  416         NFSERR_STALE,
  417         NFSERR_BADHANDLE,
  418         NFSERR_NOTSUPP,
  419         NFSERR_SERVERFAULT,
  420         0,
  421 };
  422 
  423 static const short nfsv3err_readdir[] = {
  424         NFSERR_IO,
  425         NFSERR_IO,
  426         NFSERR_ACCES,
  427         NFSERR_NOTDIR,
  428         NFSERR_STALE,
  429         NFSERR_BADHANDLE,
  430         NFSERR_BAD_COOKIE,
  431         NFSERR_TOOSMALL,
  432         NFSERR_SERVERFAULT,
  433         0,
  434 };
  435 
  436 static const short nfsv3err_readdirplus[] = {
  437         NFSERR_IO,
  438         NFSERR_IO,
  439         NFSERR_ACCES,
  440         NFSERR_NOTDIR,
  441         NFSERR_STALE,
  442         NFSERR_BADHANDLE,
  443         NFSERR_BAD_COOKIE,
  444         NFSERR_NOTSUPP,
  445         NFSERR_TOOSMALL,
  446         NFSERR_SERVERFAULT,
  447         0,
  448 };
  449 
  450 static const short nfsv3err_fsstat[] = {
  451         NFSERR_IO,
  452         NFSERR_IO,
  453         NFSERR_STALE,
  454         NFSERR_BADHANDLE,
  455         NFSERR_SERVERFAULT,
  456         0,
  457 };
  458 
  459 static const short nfsv3err_fsinfo[] = {
  460         NFSERR_STALE,
  461         NFSERR_STALE,
  462         NFSERR_BADHANDLE,
  463         NFSERR_SERVERFAULT,
  464         0,
  465 };
  466 
  467 static const short nfsv3err_pathconf[] = {
  468         NFSERR_STALE,
  469         NFSERR_STALE,
  470         NFSERR_BADHANDLE,
  471         NFSERR_SERVERFAULT,
  472         0,
  473 };
  474 
  475 static const short nfsv3err_commit[] = {
  476         NFSERR_IO,
  477         NFSERR_IO,
  478         NFSERR_STALE,
  479         NFSERR_BADHANDLE,
  480         NFSERR_SERVERFAULT,
  481         0,
  482 };
  483 
  484 static const short *nfsrv_v3errmap[] = {
  485         nfsv3err_null,
  486         nfsv3err_getattr,
  487         nfsv3err_setattr,
  488         nfsv3err_lookup,
  489         nfsv3err_access,
  490         nfsv3err_readlink,
  491         nfsv3err_read,
  492         nfsv3err_write,
  493         nfsv3err_create,
  494         nfsv3err_mkdir,
  495         nfsv3err_symlink,
  496         nfsv3err_mknod,
  497         nfsv3err_remove,
  498         nfsv3err_rmdir,
  499         nfsv3err_rename,
  500         nfsv3err_link,
  501         nfsv3err_readdir,
  502         nfsv3err_readdirplus,
  503         nfsv3err_fsstat,
  504         nfsv3err_fsinfo,
  505         nfsv3err_pathconf,
  506         nfsv3err_commit,
  507 };
  508 
  509 extern int (*nfsd_call_nfsserver)(struct thread *, struct nfssvc_args *);
  510 
  511 /*
  512  * Called once to initialize data structures...
  513  */
  514 static int
  515 nfsrv_modevent(module_t mod, int type, void *data)
  516 {
  517         int error = 0;
  518 
  519         switch (type) {
  520         case MOD_LOAD:
  521                 mtx_init(&nfsd_mtx, "nfsd_mtx", NULL, MTX_DEF);
  522                 nfsrv_nfs_true = txdr_unsigned(TRUE);
  523                 nfsrv_nfs_false = txdr_unsigned(FALSE);
  524                 nfsrv_nfs_xdrneg1 = txdr_unsigned(-1);
  525                 nfsrv_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
  526                 if (nfsrv_ticks < 1)
  527                         nfsrv_ticks = 1;
  528 
  529                 NFSD_LOCK();
  530                 nfsrv_init(0);          /* Init server data structures */
  531                 NFSD_UNLOCK();
  532 
  533                 nfsd_call_nfsserver = nfssvc_nfsserver;
  534                 break;
  535 
  536         case MOD_UNLOAD:
  537                 if (nfsrv_numnfsd != 0) {
  538                         error = EBUSY;
  539                         break;
  540                 }
  541 
  542                 nfsd_call_nfsserver = NULL;
  543                 callout_drain(&nfsrv_callout);
  544                 mtx_destroy(&nfsd_mtx);
  545                 break;
  546         default:
  547                 error = EOPNOTSUPP;
  548                 break;
  549         }
  550         return error;
  551 }
  552 static moduledata_t nfsserver_mod = {
  553         "nfsserver",
  554         nfsrv_modevent,
  555         NULL,
  556 };
  557 DECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY);
  558 
  559 /* So that loader and kldload(2) can find us, wherever we are.. */
  560 MODULE_VERSION(nfsserver, 1);
  561 MODULE_DEPEND(nfsserver, nfssvc, 1, 1, 1);
  562 MODULE_DEPEND(nfsserver, krpc, 1, 1, 1);
  563 
  564 /*
  565  * Set up nameidata for a lookup() call and do it.
  566  *
  567  * If pubflag is set, this call is done for a lookup operation on the
  568  * public filehandle. In that case we allow crossing mountpoints and
  569  * absolute pathnames. However, the caller is expected to check that
  570  * the lookup result is within the public fs, and deny access if
  571  * it is not.
  572  *
  573  * nfs_namei() clears out garbage fields that namei() might leave garbage.
  574  * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no
  575  * error occurs but the parent was not requested.
  576  *
  577  * dirp may be set whether an error is returned or not, and must be
  578  * released by the caller.
  579  */
  580 int
  581 nfs_namei(struct nameidata *ndp, struct nfsrv_descript *nfsd,
  582     fhandle_t *fhp, int len, struct nfssvc_sock *slp,
  583     struct sockaddr *nam, struct mbuf **mdp,
  584     caddr_t *dposp, struct vnode **retdirp, int v3, struct vattr *retdirattrp,
  585     int *retdirattr_retp, int pubflag)
  586 {
  587         int i, rem;
  588         struct mbuf *md;
  589         char *fromcp, *tocp, *cp;
  590         struct iovec aiov;
  591         struct uio auio;
  592         struct vnode *dp;
  593         int error, rdonly, linklen;
  594         struct componentname *cnp = &ndp->ni_cnd;
  595         int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0;
  596         int dvfslocked;
  597         int vfslocked;
  598 
  599         vfslocked = 0;
  600         dvfslocked = 0;
  601         *retdirp = NULL;
  602         cnp->cn_flags |= NOMACCHECK;
  603         cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
  604 
  605         /*
  606          * Copy the name from the mbuf list to ndp->ni_pnbuf
  607          * and set the various ndp fields appropriately.
  608          */
  609         fromcp = *dposp;
  610         tocp = cnp->cn_pnbuf;
  611         md = *mdp;
  612         rem = mtod(md, caddr_t) + md->m_len - fromcp;
  613         for (i = 0; i < len; i++) {
  614                 while (rem == 0) {
  615                         md = md->m_next;
  616                         if (md == NULL) {
  617                                 error = EBADRPC;
  618                                 goto out;
  619                         }
  620                         fromcp = mtod(md, caddr_t);
  621                         rem = md->m_len;
  622                 }
  623                 if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
  624                         error = EACCES;
  625                         goto out;
  626                 }
  627                 *tocp++ = *fromcp++;
  628                 rem--;
  629         }
  630         *tocp = '\0';
  631         *mdp = md;
  632         *dposp = fromcp;
  633         len = nfsm_rndup(len)-len;
  634         if (len > 0) {
  635                 if (rem >= len)
  636                         *dposp += len;
  637                 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
  638                         goto out;
  639         }
  640 
  641         /*
  642          * Extract and set starting directory.
  643          */
  644         error = nfsrv_fhtovp(fhp, FALSE, &dp, &dvfslocked,
  645             nfsd, slp, nam, &rdonly, pubflag);
  646         if (error)
  647                 goto out;
  648         vfslocked = VFS_LOCK_GIANT(dp->v_mount);
  649         if (dp->v_type != VDIR) {
  650                 vrele(dp);
  651                 error = ENOTDIR;
  652                 goto out;
  653         }
  654 
  655         if (rdonly)
  656                 cnp->cn_flags |= RDONLY;
  657 
  658         /*
  659          * Set return directory.  Reference to dp is implicitly transfered
  660          * to the returned pointer
  661          */
  662         *retdirp = dp;
  663         if (v3) {
  664                 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
  665                 *retdirattr_retp = VOP_GETATTR(dp, retdirattrp,
  666                         ndp->ni_cnd.cn_cred);
  667                 VOP_UNLOCK(dp, 0);
  668         }
  669 
  670         if (pubflag) {
  671                 /*
  672                  * Oh joy. For WebNFS, handle those pesky '%' escapes,
  673                  * and the 'native path' indicator.
  674                  */
  675                 cp = uma_zalloc(namei_zone, M_WAITOK);
  676                 fromcp = cnp->cn_pnbuf;
  677                 tocp = cp;
  678                 if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
  679                         switch ((unsigned char)*fromcp) {
  680                         case WEBNFS_NATIVE_CHAR:
  681                                 /*
  682                                  * 'Native' path for us is the same
  683                                  * as a path according to the NFS spec,
  684                                  * just skip the escape char.
  685                                  */
  686                                 fromcp++;
  687                                 break;
  688                         /*
  689                          * More may be added in the future, range 0x80-0xff
  690                          */
  691                         default:
  692                                 error = EIO;
  693                                 uma_zfree(namei_zone, cp);
  694                                 goto out;
  695                         }
  696                 }
  697                 /*
  698                  * Translate the '%' escapes, URL-style.
  699                  */
  700                 while (*fromcp != '\0') {
  701                         if (*fromcp == WEBNFS_ESC_CHAR) {
  702                                 if (fromcp[1] != '\0' && fromcp[2] != '\0') {
  703                                         fromcp++;
  704                                         *tocp++ = HEXSTRTOI(fromcp);
  705                                         fromcp += 2;
  706                                         continue;
  707                                 } else {
  708                                         error = ENOENT;
  709                                         uma_zfree(namei_zone, cp);
  710                                         goto out;
  711                                 }
  712                         } else
  713                                 *tocp++ = *fromcp++;
  714                 }
  715                 *tocp = '\0';
  716                 uma_zfree(namei_zone, cnp->cn_pnbuf);
  717                 cnp->cn_pnbuf = cp;
  718         }
  719 
  720         ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
  721         ndp->ni_segflg = UIO_SYSSPACE;
  722 
  723         if (pubflag) {
  724                 ndp->ni_rootdir = rootvnode;
  725                 ndp->ni_loopcnt = 0;
  726                 if (cnp->cn_pnbuf[0] == '/') {
  727                         int tvfslocked;
  728 
  729                         tvfslocked = VFS_LOCK_GIANT(rootvnode->v_mount);
  730                         VFS_UNLOCK_GIANT(vfslocked);
  731                         dp = rootvnode;
  732                         vfslocked = tvfslocked;
  733                 }
  734         } else {
  735                 cnp->cn_flags |= NOCROSSMOUNT;
  736         }
  737 
  738         /*
  739          * Initialize for scan, set ni_startdir and bump ref on dp again
  740          * because lookup() will dereference ni_startdir.
  741          */
  742 
  743         cnp->cn_thread = curthread;
  744         VREF(dp);
  745         ndp->ni_startdir = dp;
  746 
  747         if (!lockleaf)
  748                 cnp->cn_flags |= LOCKLEAF;
  749         for (;;) {
  750                 cnp->cn_nameptr = cnp->cn_pnbuf;
  751                 /*
  752                  * Call lookup() to do the real work.  If an error occurs,
  753                  * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
  754                  * we do not have to dereference anything before returning.
  755                  * In either case ni_startdir will be dereferenced and NULLed
  756                  * out.
  757                  */
  758                 if (vfslocked)
  759                         ndp->ni_cnd.cn_flags |= GIANTHELD;
  760                 error = lookup(ndp);
  761                 vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0;
  762                 ndp->ni_cnd.cn_flags &= ~GIANTHELD;
  763                 if (error)
  764                         break;
  765 
  766                 /*
  767                  * Check for encountering a symbolic link.  Trivial
  768                  * termination occurs if no symlink encountered.
  769                  * Note: zfree is safe because error is 0, so we will
  770                  * not zfree it again when we break.
  771                  */
  772                 if ((cnp->cn_flags & ISSYMLINK) == 0) {
  773                         if (cnp->cn_flags & (SAVENAME | SAVESTART))
  774                                 cnp->cn_flags |= HASBUF;
  775                         else
  776                                 uma_zfree(namei_zone, cnp->cn_pnbuf);
  777                         if (ndp->ni_vp && !lockleaf)
  778                                 VOP_UNLOCK(ndp->ni_vp, 0);
  779                         break;
  780                 }
  781 
  782                 /*
  783                  * Validate symlink
  784                  */
  785                 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
  786                         VOP_UNLOCK(ndp->ni_dvp, 0);
  787                 if (!pubflag) {
  788                         error = EINVAL;
  789                         goto badlink2;
  790                 }
  791 
  792                 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
  793                         error = ELOOP;
  794                         goto badlink2;
  795                 }
  796                 if (ndp->ni_pathlen > 1)
  797                         cp = uma_zalloc(namei_zone, M_WAITOK);
  798                 else
  799                         cp = cnp->cn_pnbuf;
  800                 aiov.iov_base = cp;
  801                 aiov.iov_len = MAXPATHLEN;
  802                 auio.uio_iov = &aiov;
  803                 auio.uio_iovcnt = 1;
  804                 auio.uio_offset = 0;
  805                 auio.uio_rw = UIO_READ;
  806                 auio.uio_segflg = UIO_SYSSPACE;
  807                 auio.uio_td = NULL;
  808                 auio.uio_resid = MAXPATHLEN;
  809                 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
  810                 if (error) {
  811                 badlink1:
  812                         if (ndp->ni_pathlen > 1)
  813                                 uma_zfree(namei_zone, cp);
  814                 badlink2:
  815                         vput(ndp->ni_vp);
  816                         vrele(ndp->ni_dvp);
  817                         break;
  818                 }
  819                 linklen = MAXPATHLEN - auio.uio_resid;
  820                 if (linklen == 0) {
  821                         error = ENOENT;
  822                         goto badlink1;
  823                 }
  824                 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
  825                         error = ENAMETOOLONG;
  826                         goto badlink1;
  827                 }
  828 
  829                 /*
  830                  * Adjust or replace path
  831                  */
  832                 if (ndp->ni_pathlen > 1) {
  833                         bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
  834                         uma_zfree(namei_zone, cnp->cn_pnbuf);
  835                         cnp->cn_pnbuf = cp;
  836                 } else
  837                         cnp->cn_pnbuf[linklen] = '\0';
  838                 ndp->ni_pathlen += linklen;
  839 
  840                 /*
  841                  * Cleanup refs for next loop and check if root directory
  842                  * should replace current directory.  Normally ni_dvp
  843                  * becomes the new base directory and is cleaned up when
  844                  * we loop.  Explicitly null pointers after invalidation
  845                  * to clarify operation.
  846                  */
  847                 vput(ndp->ni_vp);
  848                 ndp->ni_vp = NULL;
  849 
  850                 if (cnp->cn_pnbuf[0] == '/') {
  851                         vrele(ndp->ni_dvp);
  852                         ndp->ni_dvp = ndp->ni_rootdir;
  853                         VREF(ndp->ni_dvp);
  854                 }
  855                 ndp->ni_startdir = ndp->ni_dvp;
  856                 ndp->ni_dvp = NULL;
  857         }
  858         if (!lockleaf)
  859                 cnp->cn_flags &= ~LOCKLEAF;
  860         if (cnp->cn_flags & GIANTHELD) {
  861                 mtx_unlock(&Giant);
  862                 cnp->cn_flags &= ~GIANTHELD;
  863         }
  864 
  865         /*
  866          * nfs_namei() guarentees that fields will not contain garbage
  867          * whether an error occurs or not.  This allows the caller to track
  868          * cleanup state trivially.
  869          */
  870 out:
  871         if (error) {
  872                 uma_zfree(namei_zone, cnp->cn_pnbuf);
  873                 ndp->ni_vp = NULL;
  874                 ndp->ni_dvp = NULL;
  875                 ndp->ni_startdir = NULL;
  876                 cnp->cn_flags &= ~HASBUF;
  877                 VFS_UNLOCK_GIANT(vfslocked);
  878                 vfslocked = 0;
  879         } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
  880                 ndp->ni_dvp = NULL;
  881         }
  882         /*
  883          * This differs from normal namei() in that even on failure we may
  884          * return with Giant held due to the dirp return.  Make sure we only
  885          * have not recursed however.  The calling code only expects to drop
  886          * one acquire.
  887          */
  888         if (vfslocked || dvfslocked)
  889                 ndp->ni_cnd.cn_flags |= GIANTHELD;
  890         if (vfslocked && dvfslocked)
  891                 VFS_UNLOCK_GIANT(vfslocked);
  892         return (error);
  893 }
  894 
  895 /*
  896  * A fiddled version of m_adj() that ensures null fill to a long
  897  * boundary and only trims off the back end
  898  */
  899 void
  900 nfsm_adj(struct mbuf *mp, int len, int nul)
  901 {
  902         struct mbuf *m;
  903         int count, i;
  904         char *cp;
  905 
  906         /*
  907          * Trim from tail.  Scan the mbuf chain,
  908          * calculating its length and finding the last mbuf.
  909          * If the adjustment only affects this mbuf, then just
  910          * adjust and return.  Otherwise, rescan and truncate
  911          * after the remaining size.
  912          */
  913         count = 0;
  914         m = mp;
  915         for (;;) {
  916                 count += m->m_len;
  917                 if (m->m_next == NULL)
  918                         break;
  919                 m = m->m_next;
  920         }
  921         if (m->m_len > len) {
  922                 m->m_len -= len;
  923                 if (nul > 0) {
  924                         cp = mtod(m, caddr_t)+m->m_len-nul;
  925                         for (i = 0; i < nul; i++)
  926                                 *cp++ = '\0';
  927                 }
  928                 return;
  929         }
  930         count -= len;
  931         if (count < 0)
  932                 count = 0;
  933         /*
  934          * Correct length for chain is "count".
  935          * Find the mbuf with last data, adjust its length,
  936          * and toss data from remaining mbufs on chain.
  937          */
  938         for (m = mp; m; m = m->m_next) {
  939                 if (m->m_len >= count) {
  940                         m->m_len = count;
  941                         if (nul > 0) {
  942                                 cp = mtod(m, caddr_t)+m->m_len-nul;
  943                                 for (i = 0; i < nul; i++)
  944                                         *cp++ = '\0';
  945                         }
  946                         if (m->m_next != NULL) {
  947                                 m_freem(m->m_next);
  948                                 m->m_next = NULL;
  949                         }
  950                         break;
  951                 }
  952                 count -= m->m_len;
  953         }
  954 }
  955 
  956 /*
  957  * Make these functions instead of macros, so that the kernel text size
  958  * doesn't get too big...
  959  */
  960 void
  961 nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
  962     struct vattr *before_vap, int after_ret, struct vattr *after_vap,
  963     struct mbuf **mbp, char **bposp)
  964 {
  965         struct mbuf *mb = *mbp;
  966         char *bpos = *bposp;
  967         u_int32_t *tl;
  968 
  969         if (before_ret) {
  970                 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
  971                 *tl = nfsrv_nfs_false;
  972         } else {
  973                 tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED);
  974                 *tl++ = nfsrv_nfs_true;
  975                 txdr_hyper(before_vap->va_size, tl);
  976                 tl += 2;
  977                 txdr_nfsv3time(&(before_vap->va_mtime), tl);
  978                 tl += 2;
  979                 txdr_nfsv3time(&(before_vap->va_ctime), tl);
  980         }
  981         *bposp = bpos;
  982         *mbp = mb;
  983         nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
  984 }
  985 
  986 void
  987 nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret,
  988     struct vattr *after_vap, struct mbuf **mbp, char **bposp)
  989 {
  990         struct mbuf *mb = *mbp;
  991         char *bpos = *bposp;
  992         u_int32_t *tl;
  993         struct nfs_fattr *fp;
  994 
  995         if (after_ret) {
  996                 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
  997                 *tl = nfsrv_nfs_false;
  998         } else {
  999                 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
 1000                 *tl++ = nfsrv_nfs_true;
 1001                 fp = (struct nfs_fattr *)tl;
 1002                 nfsm_srvfattr(nfsd, after_vap, fp);
 1003         }
 1004         *mbp = mb;
 1005         *bposp = bpos;
 1006 }
 1007 
 1008 void
 1009 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
 1010     struct nfs_fattr *fp)
 1011 {
 1012 
 1013         fp->fa_nlink = txdr_unsigned(vap->va_nlink);
 1014         fp->fa_uid = txdr_unsigned(vap->va_uid);
 1015         fp->fa_gid = txdr_unsigned(vap->va_gid);
 1016         if (nfsd->nd_flag & ND_NFSV3) {
 1017                 fp->fa_type = vtonfsv3_type(vap->va_type);
 1018                 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
 1019                 txdr_hyper(vap->va_size, &fp->fa3_size);
 1020                 txdr_hyper(vap->va_bytes, &fp->fa3_used);
 1021                 fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
 1022                 fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
 1023                 fp->fa3_fsid.nfsuquad[0] = 0;
 1024                 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
 1025                 fp->fa3_fileid.nfsuquad[0] = 0;
 1026                 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
 1027                 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
 1028                 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
 1029                 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
 1030         } else {
 1031                 fp->fa_type = vtonfsv2_type(vap->va_type);
 1032                 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
 1033                 fp->fa2_size = txdr_unsigned(vap->va_size);
 1034                 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
 1035                 if (vap->va_type == VFIFO)
 1036                         fp->fa2_rdev = 0xffffffff;
 1037                 else
 1038                         fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
 1039                 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
 1040                 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
 1041                 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
 1042                 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
 1043                 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
 1044                 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
 1045         }
 1046 }
 1047 
 1048 /*
 1049  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
 1050  *      - look up fsid in mount list (if not found ret error)
 1051  *      - get vp and export rights by calling VFS_FHTOVP()
 1052  *      - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
 1053  *      - if not lockflag unlock it with VOP_UNLOCK()
 1054  */
 1055 int
 1056 nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, int *vfslockedp,
 1057     struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
 1058     struct sockaddr *nam, int *rdonlyp, int pubflag)
 1059 {
 1060         struct mount *mp;
 1061         int i;
 1062         struct ucred *cred, *credanon;
 1063         int error, exflags;
 1064 #ifdef MNT_EXNORESPORT          /* XXX needs mountd and /etc/exports help yet */
 1065         struct sockaddr_int *saddr;
 1066 #endif
 1067         int credflavor;
 1068         int vfslocked;
 1069         int numsecflavors, *secflavors;
 1070         int authsys;
 1071         int v3 = nfsd->nd_flag & ND_NFSV3;
 1072         int mountreq;
 1073 
 1074         *vfslockedp = 0;
 1075         *vpp = NULL;
 1076 
 1077         if (nfs_ispublicfh(fhp)) {
 1078                 if (!pubflag || !nfs_pub.np_valid)
 1079                         return (ESTALE);
 1080                 fhp = &nfs_pub.np_handle;
 1081         }
 1082 
 1083         mp = vfs_busyfs(&fhp->fh_fsid);
 1084         if (!mp)
 1085                 return (ESTALE);
 1086         vfslocked = VFS_LOCK_GIANT(mp);
 1087         error = VFS_CHECKEXP(mp, nam, &exflags, &credanon,
 1088             &numsecflavors, &secflavors);
 1089         if (error) {
 1090                 vfs_unbusy(mp);
 1091                 goto out;
 1092         }
 1093         if (numsecflavors == 0) {
 1094                 /*
 1095                  * This can happen if the system is running with an
 1096                  * old mountd that doesn't pass in a secflavor list.
 1097                  */
 1098                 numsecflavors = 1;
 1099                 authsys = AUTH_SYS;
 1100                 secflavors = &authsys;
 1101         }
 1102         credflavor = nfsd->nd_credflavor;
 1103         for (i = 0; i < numsecflavors; i++) {
 1104                 if (secflavors[i] == credflavor)
 1105                         break;
 1106         }
 1107         if (i == numsecflavors) {
 1108                 /*
 1109                  * RFC 2623 section 2.3.2 - allow certain procedures
 1110                  * used at NFS client mount time even if they have
 1111                  * weak authentication.
 1112                  */
 1113                 mountreq = FALSE;
 1114                 if (v3) {
 1115                         if (nfsd->nd_procnum == NFSPROC_FSINFO
 1116                             || nfsd->nd_procnum == NFSPROC_GETATTR)
 1117                                 mountreq = TRUE;
 1118                 } else {
 1119                         if (nfsd->nd_procnum == NFSPROC_FSSTAT
 1120                             || nfsd->nd_procnum == NFSPROC_GETATTR)
 1121                                 mountreq = TRUE;
 1122                 }
 1123                 if (!mountreq) {
 1124                         error = NFSERR_AUTHERR | AUTH_TOOWEAK;
 1125                         vfs_unbusy(mp);
 1126                         goto out;
 1127                 }
 1128         }
 1129         error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
 1130         vfs_unbusy(mp);
 1131         if (error)
 1132                 goto out;
 1133 #ifdef MNT_EXNORESPORT
 1134         if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
 1135                 saddr = (struct sockaddr_in *)nam;
 1136                 if ((saddr->sin_family == AF_INET ||
 1137                      saddr->sin_family == AF_INET6) &&
 1138         /* same code for INET and INET6: sin*_port at same offet */
 1139                     ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
 1140                         vput(*vpp);
 1141                         *vpp = NULL;
 1142                         error = NFSERR_AUTHERR | AUTH_TOOWEAK;
 1143                 }
 1144         }
 1145 #endif
 1146         /*
 1147          * Check/setup credentials.
 1148          */
 1149         cred = nfsd->nd_cr;
 1150         if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
 1151                 cred->cr_uid = credanon->cr_uid;
 1152                 crsetgroups(cred, credanon->cr_ngroups, credanon->cr_groups);
 1153         }
 1154         if (exflags & MNT_EXRDONLY)
 1155                 *rdonlyp = 1;
 1156         else
 1157                 *rdonlyp = 0;
 1158 
 1159         if (!lockflag)
 1160                 VOP_UNLOCK(*vpp, 0);
 1161 out:
 1162         if (credanon != NULL)
 1163                 crfree(credanon);
 1164 
 1165         if (error) {
 1166                 VFS_UNLOCK_GIANT(vfslocked);
 1167         } else
 1168                 *vfslockedp = vfslocked;
 1169         return (error);
 1170 }
 1171 
 1172 
 1173 /*
 1174  * WebNFS: check if a filehandle is a public filehandle. For v3, this
 1175  * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
 1176  * transformed this to all zeroes in both cases, so check for it.
 1177  */
 1178 int
 1179 nfs_ispublicfh(fhandle_t *fhp)
 1180 {
 1181         char *cp = (char *)fhp;
 1182         int i;
 1183 
 1184         NFSD_LOCK_DONTCARE();
 1185 
 1186         for (i = 0; i < NFSX_V3FH; i++)
 1187                 if (*cp++ != 0)
 1188                         return (FALSE);
 1189         return (TRUE);
 1190 }
 1191 
 1192 /*
 1193  * Map errnos to NFS error numbers. For Version 3 also filter out error
 1194  * numbers not specified for the associated procedure.
 1195  */
 1196 int
 1197 nfsrv_errmap(struct nfsrv_descript *nd, int err)
 1198 {
 1199         const short *defaulterrp, *errp;
 1200         int e;
 1201 
 1202 
 1203         if (nd->nd_flag & ND_NFSV3) {
 1204             if (nd->nd_procnum <= NFSPROC_COMMIT) {
 1205                 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
 1206                 while (*++errp) {
 1207                         if (*errp == err)
 1208                                 return (err);
 1209                         else if (*errp > err)
 1210                                 break;
 1211                 }
 1212                 return ((int)*defaulterrp);
 1213             } else
 1214                 return (err & 0xffff);
 1215         }
 1216         e = 0;
 1217         if (err <= ELAST)
 1218                 e = nfsrv_v2errmap[err - 1];
 1219         if (e != 0)
 1220                 return (e);
 1221         return (NFSERR_IO);
 1222 }
 1223 
 1224 /*
 1225  * Sort the group list in increasing numerical order.
 1226  * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
 1227  *  that used to be here.)
 1228  */
 1229 void
 1230 nfsrvw_sort(gid_t *list, int num)
 1231 {
 1232         int i, j;
 1233         gid_t v;
 1234 
 1235         /* Insertion sort. */
 1236         for (i = 1; i < num; i++) {
 1237                 v = list[i];
 1238                 /* find correct slot for value v, moving others up */
 1239                 for (j = i; --j >= 0 && v < list[j];)
 1240                         list[j + 1] = list[j];
 1241                 list[j + 1] = v;
 1242         }
 1243 }
 1244 
 1245 /*
 1246  * Helper functions for macros.
 1247  */
 1248 
 1249 void
 1250 nfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos)
 1251 {
 1252         u_int32_t *tl;
 1253 
 1254         if (v3) {
 1255                 tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
 1256                 *tl++ = txdr_unsigned(NFSX_V3FH);
 1257                 bcopy(f, tl, NFSX_V3FH);
 1258         } else {
 1259                 tl = nfsm_build_xx(NFSX_V2FH, mb, bpos);
 1260                 bcopy(f, tl, NFSX_V2FH);
 1261         }
 1262 }
 1263 
 1264 void
 1265 nfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos)
 1266 {
 1267         u_int32_t *tl;
 1268 
 1269         tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
 1270         *tl++ = nfsrv_nfs_true;
 1271         *tl++ = txdr_unsigned(NFSX_V3FH);
 1272         bcopy(f, tl, NFSX_V3FH);
 1273 }
 1274 
 1275 int
 1276 nfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
 1277 {
 1278         u_int32_t *tl;
 1279 
 1280         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1281         if (tl == NULL)
 1282                 return EBADRPC;
 1283         *s = fxdr_unsigned(int32_t, *tl);
 1284         if (*s > m || *s <= 0)
 1285                 return EBADRPC;
 1286         return 0;
 1287 }
 1288 
 1289 int
 1290 nfsm_srvnamesiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
 1291 {
 1292         u_int32_t *tl;
 1293 
 1294         NFSD_LOCK_DONTCARE();
 1295 
 1296         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1297         if (tl == NULL)
 1298                 return EBADRPC;
 1299         *s = fxdr_unsigned(int32_t, *tl);
 1300         if (*s > m)
 1301                 return NFSERR_NAMETOL;
 1302         if (*s <= 0)
 1303                 return EBADRPC;
 1304         return 0;
 1305 }
 1306 
 1307 int
 1308 nfsm_srvnamesiz0_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
 1309 {
 1310         u_int32_t *tl;
 1311 
 1312         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1313         if (tl == NULL)
 1314                 return EBADRPC;
 1315         *s = fxdr_unsigned(int32_t, *tl);
 1316         if (*s > m)
 1317                 return NFSERR_NAMETOL;
 1318         if (*s < 0)
 1319                 return EBADRPC;
 1320         return 0;
 1321 }
 1322 
 1323 void
 1324 nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
 1325     char **bp, char **be, caddr_t bpos)
 1326 {
 1327         struct mbuf *nmp;
 1328 
 1329         NFSD_UNLOCK_ASSERT();
 1330 
 1331         if (*bp >= *be) {
 1332                 if (*mp == mb)
 1333                         (*mp)->m_len += *bp - bpos;
 1334                 MGET(nmp, M_WAIT, MT_DATA);
 1335                 MCLGET(nmp, M_WAIT);
 1336                 nmp->m_len = NFSMSIZ(nmp);
 1337                 (*mp)->m_next = nmp;
 1338                 *mp = nmp;
 1339                 *bp = mtod(*mp, caddr_t);
 1340                 *be = *bp + (*mp)->m_len;
 1341         }
 1342         *tl = (u_int32_t *)*bp;
 1343 }
 1344 
 1345 int
 1346 nfsm_srvmtofh_xx(fhandle_t *f, int v3, struct mbuf **md, caddr_t *dpos)
 1347 {
 1348         u_int32_t *tl;
 1349         int fhlen;
 1350 
 1351         if (v3) {
 1352                 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1353                 if (tl == NULL)
 1354                         return EBADRPC;
 1355                 fhlen = fxdr_unsigned(int, *tl);
 1356                 if (fhlen != 0 && fhlen != NFSX_V3FH)
 1357                         return EBADRPC;
 1358         } else {
 1359                 fhlen = NFSX_V2FH;
 1360         }
 1361         if (fhlen != 0) {
 1362                 tl = nfsm_dissect_xx_nonblock(fhlen, md, dpos);
 1363                 if (tl == NULL)
 1364                         return EBADRPC;
 1365                 bcopy((caddr_t)tl, (caddr_t)(f), fhlen);
 1366         } else {
 1367                 bzero((caddr_t)(f), NFSX_V3FH);
 1368         }
 1369         return 0;
 1370 }
 1371 
 1372 int
 1373 nfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos)
 1374 {
 1375         u_int32_t *tl;
 1376         int toclient = 0;
 1377 
 1378         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1379         if (tl == NULL)
 1380                 return EBADRPC;
 1381         if (*tl == nfsrv_nfs_true) {
 1382                 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1383                 if (tl == NULL)
 1384                         return EBADRPC;
 1385                 (a)->va_mode = nfstov_mode(*tl);
 1386         }
 1387         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1388         if (tl == NULL)
 1389                 return EBADRPC;
 1390         if (*tl == nfsrv_nfs_true) {
 1391                 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1392                 if (tl == NULL)
 1393                         return EBADRPC;
 1394                 (a)->va_uid = fxdr_unsigned(uid_t, *tl);
 1395         }
 1396         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1397         if (tl == NULL)
 1398                 return EBADRPC;
 1399         if (*tl == nfsrv_nfs_true) {
 1400                 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1401                 if (tl == NULL)
 1402                         return EBADRPC;
 1403                 (a)->va_gid = fxdr_unsigned(gid_t, *tl);
 1404         }
 1405         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1406         if (tl == NULL)
 1407                 return EBADRPC;
 1408         if (*tl == nfsrv_nfs_true) {
 1409                 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
 1410                 if (tl == NULL)
 1411                         return EBADRPC;
 1412                 (a)->va_size = fxdr_hyper(tl);
 1413         }
 1414         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1415         if (tl == NULL)
 1416                 return EBADRPC;
 1417         switch (fxdr_unsigned(int, *tl)) {
 1418         case NFSV3SATTRTIME_TOCLIENT:
 1419                 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
 1420                 if (tl == NULL)
 1421                         return EBADRPC;
 1422                 fxdr_nfsv3time(tl, &(a)->va_atime);
 1423                 toclient = 1;
 1424                 break;
 1425         case NFSV3SATTRTIME_TOSERVER:
 1426                 getnanotime(&(a)->va_atime);
 1427                 a->va_vaflags |= VA_UTIMES_NULL;
 1428                 break;
 1429         }
 1430         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1431         if (tl == NULL)
 1432                 return EBADRPC;
 1433         switch (fxdr_unsigned(int, *tl)) {
 1434         case NFSV3SATTRTIME_TOCLIENT:
 1435                 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
 1436                 if (tl == NULL)
 1437                         return EBADRPC;
 1438                 fxdr_nfsv3time(tl, &(a)->va_mtime);
 1439                 a->va_vaflags &= ~VA_UTIMES_NULL;
 1440                 break;
 1441         case NFSV3SATTRTIME_TOSERVER:
 1442                 getnanotime(&(a)->va_mtime);
 1443                 if (toclient == 0)
 1444                         a->va_vaflags |= VA_UTIMES_NULL;
 1445                 break;
 1446         }
 1447         return 0;
 1448 }

Cache object: 90012a0cc7c1ea6f23b0662bde70de8f


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