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/9.1/sys/nfsserver/nfs_srvsubs.c 222167 2011-05-22 01:07:54Z rmacklem $");
   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 MODULE_DEPEND(nfsserver, nfs_common, 1, 1, 1);
  564 
  565 /*
  566  * Set up nameidata for a lookup() call and do it.
  567  *
  568  * If pubflag is set, this call is done for a lookup operation on the
  569  * public filehandle. In that case we allow crossing mountpoints and
  570  * absolute pathnames. However, the caller is expected to check that
  571  * the lookup result is within the public fs, and deny access if
  572  * it is not.
  573  *
  574  * nfs_namei() clears out garbage fields that namei() might leave garbage.
  575  * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no
  576  * error occurs but the parent was not requested.
  577  *
  578  * dirp may be set whether an error is returned or not, and must be
  579  * released by the caller.
  580  */
  581 int
  582 nfs_namei(struct nameidata *ndp, struct nfsrv_descript *nfsd,
  583     fhandle_t *fhp, int len, struct nfssvc_sock *slp,
  584     struct sockaddr *nam, struct mbuf **mdp,
  585     caddr_t *dposp, struct vnode **retdirp, int v3, struct vattr *retdirattrp,
  586     int *retdirattr_retp, int pubflag)
  587 {
  588         int i, rem;
  589         struct mbuf *md;
  590         char *fromcp, *tocp, *cp;
  591         struct iovec aiov;
  592         struct uio auio;
  593         struct vnode *dp;
  594         int error, rdonly, linklen;
  595         struct componentname *cnp = &ndp->ni_cnd;
  596         int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0;
  597         int dvfslocked;
  598         int vfslocked;
  599 
  600         vfslocked = 0;
  601         dvfslocked = 0;
  602         *retdirp = NULL;
  603         cnp->cn_flags |= NOMACCHECK;
  604         cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
  605 
  606         /*
  607          * Copy the name from the mbuf list to ndp->ni_pnbuf
  608          * and set the various ndp fields appropriately.
  609          */
  610         fromcp = *dposp;
  611         tocp = cnp->cn_pnbuf;
  612         md = *mdp;
  613         rem = mtod(md, caddr_t) + md->m_len - fromcp;
  614         for (i = 0; i < len; i++) {
  615                 while (rem == 0) {
  616                         md = md->m_next;
  617                         if (md == NULL) {
  618                                 error = EBADRPC;
  619                                 goto out;
  620                         }
  621                         fromcp = mtod(md, caddr_t);
  622                         rem = md->m_len;
  623                 }
  624                 if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
  625                         error = EACCES;
  626                         goto out;
  627                 }
  628                 *tocp++ = *fromcp++;
  629                 rem--;
  630         }
  631         *tocp = '\0';
  632         *mdp = md;
  633         *dposp = fromcp;
  634         len = nfsm_rndup(len)-len;
  635         if (len > 0) {
  636                 if (rem >= len)
  637                         *dposp += len;
  638                 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
  639                         goto out;
  640         }
  641 
  642         if (!pubflag && nfs_ispublicfh(fhp))
  643                 return (ESTALE);
  644 
  645         /*
  646          * Extract and set starting directory.
  647          */
  648         error = nfsrv_fhtovp(fhp, 0, &dp, &dvfslocked, nfsd, slp, nam, &rdonly);
  649         if (error)
  650                 goto out;
  651         vfslocked = VFS_LOCK_GIANT(dp->v_mount);
  652         if (dp->v_type != VDIR) {
  653                 vput(dp);
  654                 error = ENOTDIR;
  655                 goto out;
  656         }
  657 
  658         if (rdonly)
  659                 cnp->cn_flags |= RDONLY;
  660 
  661         /*
  662          * Set return directory.  Reference to dp is implicitly transfered
  663          * to the returned pointer
  664          */
  665         *retdirp = dp;
  666         if (v3) {
  667                 *retdirattr_retp = VOP_GETATTR(dp, retdirattrp,
  668                         ndp->ni_cnd.cn_cred);
  669         }
  670 
  671         VOP_UNLOCK(dp, 0);
  672 
  673         if (pubflag) {
  674                 /*
  675                  * Oh joy. For WebNFS, handle those pesky '%' escapes,
  676                  * and the 'native path' indicator.
  677                  */
  678                 cp = uma_zalloc(namei_zone, M_WAITOK);
  679                 fromcp = cnp->cn_pnbuf;
  680                 tocp = cp;
  681                 if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
  682                         switch ((unsigned char)*fromcp) {
  683                         case WEBNFS_NATIVE_CHAR:
  684                                 /*
  685                                  * 'Native' path for us is the same
  686                                  * as a path according to the NFS spec,
  687                                  * just skip the escape char.
  688                                  */
  689                                 fromcp++;
  690                                 break;
  691                         /*
  692                          * More may be added in the future, range 0x80-0xff
  693                          */
  694                         default:
  695                                 error = EIO;
  696                                 uma_zfree(namei_zone, cp);
  697                                 goto out;
  698                         }
  699                 }
  700                 /*
  701                  * Translate the '%' escapes, URL-style.
  702                  */
  703                 while (*fromcp != '\0') {
  704                         if (*fromcp == WEBNFS_ESC_CHAR) {
  705                                 if (fromcp[1] != '\0' && fromcp[2] != '\0') {
  706                                         fromcp++;
  707                                         *tocp++ = HEXSTRTOI(fromcp);
  708                                         fromcp += 2;
  709                                         continue;
  710                                 } else {
  711                                         error = ENOENT;
  712                                         uma_zfree(namei_zone, cp);
  713                                         goto out;
  714                                 }
  715                         } else
  716                                 *tocp++ = *fromcp++;
  717                 }
  718                 *tocp = '\0';
  719                 uma_zfree(namei_zone, cnp->cn_pnbuf);
  720                 cnp->cn_pnbuf = cp;
  721         }
  722 
  723         ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
  724         ndp->ni_segflg = UIO_SYSSPACE;
  725 
  726         if (pubflag) {
  727                 ndp->ni_rootdir = rootvnode;
  728                 ndp->ni_loopcnt = 0;
  729                 if (cnp->cn_pnbuf[0] == '/') {
  730                         int tvfslocked;
  731 
  732                         tvfslocked = VFS_LOCK_GIANT(rootvnode->v_mount);
  733                         VFS_UNLOCK_GIANT(vfslocked);
  734                         dp = rootvnode;
  735                         vfslocked = tvfslocked;
  736                 }
  737         } else {
  738                 cnp->cn_flags |= NOCROSSMOUNT;
  739         }
  740 
  741         /*
  742          * Initialize for scan, set ni_startdir and bump ref on dp again
  743          * because lookup() will dereference ni_startdir.
  744          */
  745 
  746         cnp->cn_thread = curthread;
  747         VREF(dp);
  748         ndp->ni_startdir = dp;
  749 
  750         if (!lockleaf)
  751                 cnp->cn_flags |= LOCKLEAF;
  752         for (;;) {
  753                 cnp->cn_nameptr = cnp->cn_pnbuf;
  754                 /*
  755                  * Call lookup() to do the real work.  If an error occurs,
  756                  * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
  757                  * we do not have to dereference anything before returning.
  758                  * In either case ni_startdir will be dereferenced and NULLed
  759                  * out.
  760                  */
  761                 if (vfslocked)
  762                         ndp->ni_cnd.cn_flags |= GIANTHELD;
  763                 error = lookup(ndp);
  764                 vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0;
  765                 ndp->ni_cnd.cn_flags &= ~GIANTHELD;
  766                 if (error)
  767                         break;
  768 
  769                 /*
  770                  * Check for encountering a symbolic link.  Trivial
  771                  * termination occurs if no symlink encountered.
  772                  * Note: zfree is safe because error is 0, so we will
  773                  * not zfree it again when we break.
  774                  */
  775                 if ((cnp->cn_flags & ISSYMLINK) == 0) {
  776                         if (cnp->cn_flags & (SAVENAME | SAVESTART))
  777                                 cnp->cn_flags |= HASBUF;
  778                         else
  779                                 uma_zfree(namei_zone, cnp->cn_pnbuf);
  780                         if (ndp->ni_vp && !lockleaf)
  781                                 VOP_UNLOCK(ndp->ni_vp, 0);
  782                         break;
  783                 }
  784 
  785                 /*
  786                  * Validate symlink
  787                  */
  788                 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
  789                         VOP_UNLOCK(ndp->ni_dvp, 0);
  790                 if (!pubflag) {
  791                         error = EINVAL;
  792                         goto badlink2;
  793                 }
  794 
  795                 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
  796                         error = ELOOP;
  797                         goto badlink2;
  798                 }
  799                 if (ndp->ni_pathlen > 1)
  800                         cp = uma_zalloc(namei_zone, M_WAITOK);
  801                 else
  802                         cp = cnp->cn_pnbuf;
  803                 aiov.iov_base = cp;
  804                 aiov.iov_len = MAXPATHLEN;
  805                 auio.uio_iov = &aiov;
  806                 auio.uio_iovcnt = 1;
  807                 auio.uio_offset = 0;
  808                 auio.uio_rw = UIO_READ;
  809                 auio.uio_segflg = UIO_SYSSPACE;
  810                 auio.uio_td = NULL;
  811                 auio.uio_resid = MAXPATHLEN;
  812                 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
  813                 if (error) {
  814                 badlink1:
  815                         if (ndp->ni_pathlen > 1)
  816                                 uma_zfree(namei_zone, cp);
  817                 badlink2:
  818                         vput(ndp->ni_vp);
  819                         vrele(ndp->ni_dvp);
  820                         break;
  821                 }
  822                 linklen = MAXPATHLEN - auio.uio_resid;
  823                 if (linklen == 0) {
  824                         error = ENOENT;
  825                         goto badlink1;
  826                 }
  827                 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
  828                         error = ENAMETOOLONG;
  829                         goto badlink1;
  830                 }
  831 
  832                 /*
  833                  * Adjust or replace path
  834                  */
  835                 if (ndp->ni_pathlen > 1) {
  836                         bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
  837                         uma_zfree(namei_zone, cnp->cn_pnbuf);
  838                         cnp->cn_pnbuf = cp;
  839                 } else
  840                         cnp->cn_pnbuf[linklen] = '\0';
  841                 ndp->ni_pathlen += linklen;
  842 
  843                 /*
  844                  * Cleanup refs for next loop and check if root directory
  845                  * should replace current directory.  Normally ni_dvp
  846                  * becomes the new base directory and is cleaned up when
  847                  * we loop.  Explicitly null pointers after invalidation
  848                  * to clarify operation.
  849                  */
  850                 vput(ndp->ni_vp);
  851                 ndp->ni_vp = NULL;
  852 
  853                 if (cnp->cn_pnbuf[0] == '/') {
  854                         vrele(ndp->ni_dvp);
  855                         ndp->ni_dvp = ndp->ni_rootdir;
  856                         VREF(ndp->ni_dvp);
  857                 }
  858                 ndp->ni_startdir = ndp->ni_dvp;
  859                 ndp->ni_dvp = NULL;
  860         }
  861         if (!lockleaf)
  862                 cnp->cn_flags &= ~LOCKLEAF;
  863         if (cnp->cn_flags & GIANTHELD) {
  864                 mtx_unlock(&Giant);
  865                 cnp->cn_flags &= ~GIANTHELD;
  866         }
  867 
  868         /*
  869          * nfs_namei() guarentees that fields will not contain garbage
  870          * whether an error occurs or not.  This allows the caller to track
  871          * cleanup state trivially.
  872          */
  873 out:
  874         if (error) {
  875                 uma_zfree(namei_zone, cnp->cn_pnbuf);
  876                 ndp->ni_vp = NULL;
  877                 ndp->ni_dvp = NULL;
  878                 ndp->ni_startdir = NULL;
  879                 cnp->cn_flags &= ~HASBUF;
  880                 VFS_UNLOCK_GIANT(vfslocked);
  881                 vfslocked = 0;
  882         } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
  883                 ndp->ni_dvp = NULL;
  884         }
  885         /*
  886          * This differs from normal namei() in that even on failure we may
  887          * return with Giant held due to the dirp return.  Make sure we only
  888          * have not recursed however.  The calling code only expects to drop
  889          * one acquire.
  890          */
  891         if (vfslocked || dvfslocked)
  892                 ndp->ni_cnd.cn_flags |= GIANTHELD;
  893         if (vfslocked && dvfslocked)
  894                 VFS_UNLOCK_GIANT(vfslocked);
  895         return (error);
  896 }
  897 
  898 /*
  899  * A fiddled version of m_adj() that ensures null fill to a long
  900  * boundary and only trims off the back end
  901  */
  902 void
  903 nfsm_adj(struct mbuf *mp, int len, int nul)
  904 {
  905         struct mbuf *m;
  906         int count, i;
  907         char *cp;
  908 
  909         /*
  910          * Trim from tail.  Scan the mbuf chain,
  911          * calculating its length and finding the last mbuf.
  912          * If the adjustment only affects this mbuf, then just
  913          * adjust and return.  Otherwise, rescan and truncate
  914          * after the remaining size.
  915          */
  916         count = 0;
  917         m = mp;
  918         for (;;) {
  919                 count += m->m_len;
  920                 if (m->m_next == NULL)
  921                         break;
  922                 m = m->m_next;
  923         }
  924         if (m->m_len > len) {
  925                 m->m_len -= len;
  926                 if (nul > 0) {
  927                         cp = mtod(m, caddr_t)+m->m_len-nul;
  928                         for (i = 0; i < nul; i++)
  929                                 *cp++ = '\0';
  930                 }
  931                 return;
  932         }
  933         count -= len;
  934         if (count < 0)
  935                 count = 0;
  936         /*
  937          * Correct length for chain is "count".
  938          * Find the mbuf with last data, adjust its length,
  939          * and toss data from remaining mbufs on chain.
  940          */
  941         for (m = mp; m; m = m->m_next) {
  942                 if (m->m_len >= count) {
  943                         m->m_len = count;
  944                         if (nul > 0) {
  945                                 cp = mtod(m, caddr_t)+m->m_len-nul;
  946                                 for (i = 0; i < nul; i++)
  947                                         *cp++ = '\0';
  948                         }
  949                         if (m->m_next != NULL) {
  950                                 m_freem(m->m_next);
  951                                 m->m_next = NULL;
  952                         }
  953                         break;
  954                 }
  955                 count -= m->m_len;
  956         }
  957 }
  958 
  959 /*
  960  * Make these functions instead of macros, so that the kernel text size
  961  * doesn't get too big...
  962  */
  963 void
  964 nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
  965     struct vattr *before_vap, int after_ret, struct vattr *after_vap,
  966     struct mbuf **mbp, char **bposp)
  967 {
  968         struct mbuf *mb = *mbp;
  969         char *bpos = *bposp;
  970         u_int32_t *tl;
  971 
  972         if (before_ret) {
  973                 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
  974                 *tl = nfsrv_nfs_false;
  975         } else {
  976                 tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED);
  977                 *tl++ = nfsrv_nfs_true;
  978                 txdr_hyper(before_vap->va_size, tl);
  979                 tl += 2;
  980                 txdr_nfsv3time(&(before_vap->va_mtime), tl);
  981                 tl += 2;
  982                 txdr_nfsv3time(&(before_vap->va_ctime), tl);
  983         }
  984         *bposp = bpos;
  985         *mbp = mb;
  986         nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
  987 }
  988 
  989 void
  990 nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret,
  991     struct vattr *after_vap, struct mbuf **mbp, char **bposp)
  992 {
  993         struct mbuf *mb = *mbp;
  994         char *bpos = *bposp;
  995         u_int32_t *tl;
  996         struct nfs_fattr *fp;
  997 
  998         if (after_ret) {
  999                 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
 1000                 *tl = nfsrv_nfs_false;
 1001         } else {
 1002                 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
 1003                 *tl++ = nfsrv_nfs_true;
 1004                 fp = (struct nfs_fattr *)tl;
 1005                 nfsm_srvfattr(nfsd, after_vap, fp);
 1006         }
 1007         *mbp = mb;
 1008         *bposp = bpos;
 1009 }
 1010 
 1011 void
 1012 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
 1013     struct nfs_fattr *fp)
 1014 {
 1015 
 1016         fp->fa_nlink = txdr_unsigned(vap->va_nlink);
 1017         fp->fa_uid = txdr_unsigned(vap->va_uid);
 1018         fp->fa_gid = txdr_unsigned(vap->va_gid);
 1019         if (nfsd->nd_flag & ND_NFSV3) {
 1020                 fp->fa_type = vtonfsv3_type(vap->va_type);
 1021                 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
 1022                 txdr_hyper(vap->va_size, &fp->fa3_size);
 1023                 txdr_hyper(vap->va_bytes, &fp->fa3_used);
 1024                 fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
 1025                 fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
 1026                 fp->fa3_fsid.nfsuquad[0] = 0;
 1027                 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
 1028                 fp->fa3_fileid.nfsuquad[0] = 0;
 1029                 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
 1030                 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
 1031                 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
 1032                 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
 1033         } else {
 1034                 fp->fa_type = vtonfsv2_type(vap->va_type);
 1035                 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
 1036                 fp->fa2_size = txdr_unsigned(vap->va_size);
 1037                 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
 1038                 if (vap->va_type == VFIFO)
 1039                         fp->fa2_rdev = 0xffffffff;
 1040                 else
 1041                         fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
 1042                 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
 1043                 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
 1044                 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
 1045                 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
 1046                 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
 1047                 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
 1048         }
 1049 }
 1050 
 1051 /*
 1052  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
 1053  *      - look up fsid in mount list (if not found ret error)
 1054  *      - get vp and export rights by calling VFS_FHTOVP()
 1055  *      - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
 1056  */
 1057 int
 1058 nfsrv_fhtovp(fhandle_t *fhp, int flags, struct vnode **vpp, int *vfslockedp,
 1059     struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
 1060     struct sockaddr *nam, int *rdonlyp)
 1061 {
 1062         struct mount *mp;
 1063         int i;
 1064         struct ucred *cred, *credanon;
 1065         int error, exflags;
 1066 #ifdef MNT_EXNORESPORT          /* XXX needs mountd and /etc/exports help yet */
 1067         struct sockaddr_int *saddr;
 1068 #endif
 1069         int credflavor;
 1070         int vfslocked;
 1071         int numsecflavors, *secflavors;
 1072         int authsys;
 1073         int v3 = nfsd->nd_flag & ND_NFSV3;
 1074         int mountreq;
 1075 
 1076         *vfslockedp = 0;
 1077         *vpp = NULL;
 1078 
 1079         if (nfs_ispublicfh(fhp)) {
 1080                 if (!nfs_pub.np_valid)
 1081                         return (ESTALE);
 1082                 fhp = &nfs_pub.np_handle;
 1083         }
 1084 
 1085         mp = vfs_busyfs(&fhp->fh_fsid);
 1086         if (!mp)
 1087                 return (ESTALE);
 1088         vfslocked = VFS_LOCK_GIANT(mp);
 1089         error = VFS_CHECKEXP(mp, nam, &exflags, &credanon,
 1090             &numsecflavors, &secflavors);
 1091         if (error) {
 1092                 vfs_unbusy(mp);
 1093                 goto out;
 1094         }
 1095         if (numsecflavors == 0) {
 1096                 /*
 1097                  * This can happen if the system is running with an
 1098                  * old mountd that doesn't pass in a secflavor list.
 1099                  */
 1100                 numsecflavors = 1;
 1101                 authsys = AUTH_SYS;
 1102                 secflavors = &authsys;
 1103         }
 1104         credflavor = nfsd->nd_credflavor;
 1105         for (i = 0; i < numsecflavors; i++) {
 1106                 if (secflavors[i] == credflavor)
 1107                         break;
 1108         }
 1109         if (i == numsecflavors) {
 1110                 /*
 1111                  * RFC 2623 section 2.3.2 - allow certain procedures
 1112                  * used at NFS client mount time even if they have
 1113                  * weak authentication.
 1114                  */
 1115                 mountreq = FALSE;
 1116                 if (v3) {
 1117                         if (nfsd->nd_procnum == NFSPROC_FSINFO
 1118                             || nfsd->nd_procnum == NFSPROC_GETATTR)
 1119                                 mountreq = TRUE;
 1120                 } else {
 1121                         if (nfsd->nd_procnum == NFSPROC_FSSTAT
 1122                             || nfsd->nd_procnum == NFSPROC_GETATTR)
 1123                                 mountreq = TRUE;
 1124                 }
 1125                 if (!mountreq) {
 1126                         error = NFSERR_AUTHERR | AUTH_TOOWEAK;
 1127                         vfs_unbusy(mp);
 1128                         goto out;
 1129                 }
 1130         }
 1131         error = VFS_FHTOVP(mp, &fhp->fh_fid, LK_EXCLUSIVE, vpp);
 1132         if (error) {
 1133                 /* Make sure the server replies ESTALE to the client. */
 1134                 error = ESTALE;
 1135                 vfs_unbusy(mp);
 1136                 goto out;
 1137         }
 1138 #ifdef MNT_EXNORESPORT
 1139         if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
 1140                 saddr = (struct sockaddr_in *)nam;
 1141                 if ((saddr->sin_family == AF_INET ||
 1142                      saddr->sin_family == AF_INET6) &&
 1143         /* same code for INET and INET6: sin*_port at same offet */
 1144                     ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
 1145                         vput(*vpp);
 1146                         *vpp = NULL;
 1147                         error = NFSERR_AUTHERR | AUTH_TOOWEAK;
 1148                         vfs_unbusy(mp);
 1149                         goto out;
 1150                 }
 1151         }
 1152 #endif
 1153         /*
 1154          * Check/setup credentials.
 1155          */
 1156         cred = nfsd->nd_cr;
 1157         if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
 1158                 cred->cr_uid = credanon->cr_uid;
 1159                 crsetgroups(cred, credanon->cr_ngroups, credanon->cr_groups);
 1160         }
 1161         if (exflags & MNT_EXRDONLY)
 1162                 *rdonlyp = 1;
 1163         else
 1164                 *rdonlyp = 0;
 1165 
 1166         if (!(flags & NFSRV_FLAG_BUSY))
 1167                 vfs_unbusy(mp);
 1168 out:
 1169         if (credanon != NULL)
 1170                 crfree(credanon);
 1171 
 1172         if (error)
 1173                 VFS_UNLOCK_GIANT(vfslocked);
 1174         else
 1175                 *vfslockedp = vfslocked;
 1176         return (error);
 1177 }
 1178 
 1179 
 1180 /*
 1181  * WebNFS: check if a filehandle is a public filehandle. For v3, this
 1182  * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
 1183  * transformed this to all zeroes in both cases, so check for it.
 1184  */
 1185 int
 1186 nfs_ispublicfh(fhandle_t *fhp)
 1187 {
 1188         char *cp = (char *)fhp;
 1189         int i;
 1190 
 1191         NFSD_LOCK_DONTCARE();
 1192 
 1193         for (i = 0; i < NFSX_V3FH; i++)
 1194                 if (*cp++ != 0)
 1195                         return (FALSE);
 1196         return (TRUE);
 1197 }
 1198 
 1199 /*
 1200  * Map errnos to NFS error numbers. For Version 3 also filter out error
 1201  * numbers not specified for the associated procedure.
 1202  */
 1203 int
 1204 nfsrv_errmap(struct nfsrv_descript *nd, int err)
 1205 {
 1206         const short *defaulterrp, *errp;
 1207         int e;
 1208 
 1209 
 1210         if (nd->nd_flag & ND_NFSV3) {
 1211             if (nd->nd_procnum <= NFSPROC_COMMIT) {
 1212                 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
 1213                 while (*++errp) {
 1214                         if (*errp == err)
 1215                                 return (err);
 1216                         else if (*errp > err)
 1217                                 break;
 1218                 }
 1219                 return ((int)*defaulterrp);
 1220             } else
 1221                 return (err & 0xffff);
 1222         }
 1223         e = 0;
 1224         if (err <= ELAST)
 1225                 e = nfsrv_v2errmap[err - 1];
 1226         if (e != 0)
 1227                 return (e);
 1228         return (NFSERR_IO);
 1229 }
 1230 
 1231 /*
 1232  * Sort the group list in increasing numerical order.
 1233  * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
 1234  *  that used to be here.)
 1235  */
 1236 void
 1237 nfsrvw_sort(gid_t *list, int num)
 1238 {
 1239         int i, j;
 1240         gid_t v;
 1241 
 1242         /* Insertion sort. */
 1243         for (i = 1; i < num; i++) {
 1244                 v = list[i];
 1245                 /* find correct slot for value v, moving others up */
 1246                 for (j = i; --j >= 0 && v < list[j];)
 1247                         list[j + 1] = list[j];
 1248                 list[j + 1] = v;
 1249         }
 1250 }
 1251 
 1252 /*
 1253  * Helper functions for macros.
 1254  */
 1255 
 1256 void
 1257 nfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos)
 1258 {
 1259         u_int32_t *tl;
 1260 
 1261         if (v3) {
 1262                 tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
 1263                 *tl++ = txdr_unsigned(NFSX_V3FH);
 1264                 bcopy(f, tl, NFSX_V3FH);
 1265         } else {
 1266                 tl = nfsm_build_xx(NFSX_V2FH, mb, bpos);
 1267                 bcopy(f, tl, NFSX_V2FH);
 1268         }
 1269 }
 1270 
 1271 void
 1272 nfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos)
 1273 {
 1274         u_int32_t *tl;
 1275 
 1276         tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
 1277         *tl++ = nfsrv_nfs_true;
 1278         *tl++ = txdr_unsigned(NFSX_V3FH);
 1279         bcopy(f, tl, NFSX_V3FH);
 1280 }
 1281 
 1282 int
 1283 nfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
 1284 {
 1285         u_int32_t *tl;
 1286 
 1287         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1288         if (tl == NULL)
 1289                 return EBADRPC;
 1290         *s = fxdr_unsigned(int32_t, *tl);
 1291         if (*s > m || *s <= 0)
 1292                 return EBADRPC;
 1293         return 0;
 1294 }
 1295 
 1296 int
 1297 nfsm_srvnamesiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
 1298 {
 1299         u_int32_t *tl;
 1300 
 1301         NFSD_LOCK_DONTCARE();
 1302 
 1303         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1304         if (tl == NULL)
 1305                 return EBADRPC;
 1306         *s = fxdr_unsigned(int32_t, *tl);
 1307         if (*s > m)
 1308                 return NFSERR_NAMETOL;
 1309         if (*s <= 0)
 1310                 return EBADRPC;
 1311         return 0;
 1312 }
 1313 
 1314 int
 1315 nfsm_srvnamesiz0_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
 1316 {
 1317         u_int32_t *tl;
 1318 
 1319         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1320         if (tl == NULL)
 1321                 return EBADRPC;
 1322         *s = fxdr_unsigned(int32_t, *tl);
 1323         if (*s > m)
 1324                 return NFSERR_NAMETOL;
 1325         if (*s < 0)
 1326                 return EBADRPC;
 1327         return 0;
 1328 }
 1329 
 1330 void
 1331 nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
 1332     char **bp, char **be, caddr_t bpos)
 1333 {
 1334         struct mbuf *nmp;
 1335 
 1336         NFSD_UNLOCK_ASSERT();
 1337 
 1338         if (*bp >= *be) {
 1339                 if (*mp == mb)
 1340                         (*mp)->m_len += *bp - bpos;
 1341                 MGET(nmp, M_WAIT, MT_DATA);
 1342                 MCLGET(nmp, M_WAIT);
 1343                 nmp->m_len = NFSMSIZ(nmp);
 1344                 (*mp)->m_next = nmp;
 1345                 *mp = nmp;
 1346                 *bp = mtod(*mp, caddr_t);
 1347                 *be = *bp + (*mp)->m_len;
 1348         }
 1349         *tl = (u_int32_t *)*bp;
 1350 }
 1351 
 1352 int
 1353 nfsm_srvmtofh_xx(fhandle_t *f, int v3, struct mbuf **md, caddr_t *dpos)
 1354 {
 1355         u_int32_t *tl;
 1356         int fhlen;
 1357 
 1358         if (v3) {
 1359                 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1360                 if (tl == NULL)
 1361                         return EBADRPC;
 1362                 fhlen = fxdr_unsigned(int, *tl);
 1363                 if (fhlen != 0 && fhlen != NFSX_V3FH)
 1364                         return EBADRPC;
 1365         } else {
 1366                 fhlen = NFSX_V2FH;
 1367         }
 1368         if (fhlen != 0) {
 1369                 tl = nfsm_dissect_xx_nonblock(fhlen, md, dpos);
 1370                 if (tl == NULL)
 1371                         return EBADRPC;
 1372                 bcopy((caddr_t)tl, (caddr_t)(f), fhlen);
 1373         } else {
 1374                 bzero((caddr_t)(f), NFSX_V3FH);
 1375         }
 1376         return 0;
 1377 }
 1378 
 1379 int
 1380 nfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos)
 1381 {
 1382         u_int32_t *tl;
 1383         int toclient = 0;
 1384 
 1385         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1386         if (tl == NULL)
 1387                 return EBADRPC;
 1388         if (*tl == nfsrv_nfs_true) {
 1389                 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1390                 if (tl == NULL)
 1391                         return EBADRPC;
 1392                 (a)->va_mode = nfstov_mode(*tl);
 1393         }
 1394         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1395         if (tl == NULL)
 1396                 return EBADRPC;
 1397         if (*tl == nfsrv_nfs_true) {
 1398                 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1399                 if (tl == NULL)
 1400                         return EBADRPC;
 1401                 (a)->va_uid = fxdr_unsigned(uid_t, *tl);
 1402         }
 1403         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1404         if (tl == NULL)
 1405                 return EBADRPC;
 1406         if (*tl == nfsrv_nfs_true) {
 1407                 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1408                 if (tl == NULL)
 1409                         return EBADRPC;
 1410                 (a)->va_gid = fxdr_unsigned(gid_t, *tl);
 1411         }
 1412         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1413         if (tl == NULL)
 1414                 return EBADRPC;
 1415         if (*tl == nfsrv_nfs_true) {
 1416                 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
 1417                 if (tl == NULL)
 1418                         return EBADRPC;
 1419                 (a)->va_size = fxdr_hyper(tl);
 1420         }
 1421         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1422         if (tl == NULL)
 1423                 return EBADRPC;
 1424         switch (fxdr_unsigned(int, *tl)) {
 1425         case NFSV3SATTRTIME_TOCLIENT:
 1426                 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
 1427                 if (tl == NULL)
 1428                         return EBADRPC;
 1429                 fxdr_nfsv3time(tl, &(a)->va_atime);
 1430                 toclient = 1;
 1431                 break;
 1432         case NFSV3SATTRTIME_TOSERVER:
 1433                 getnanotime(&(a)->va_atime);
 1434                 a->va_vaflags |= VA_UTIMES_NULL;
 1435                 break;
 1436         }
 1437         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
 1438         if (tl == NULL)
 1439                 return EBADRPC;
 1440         switch (fxdr_unsigned(int, *tl)) {
 1441         case NFSV3SATTRTIME_TOCLIENT:
 1442                 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
 1443                 if (tl == NULL)
 1444                         return EBADRPC;
 1445                 fxdr_nfsv3time(tl, &(a)->va_mtime);
 1446                 a->va_vaflags &= ~VA_UTIMES_NULL;
 1447                 break;
 1448         case NFSV3SATTRTIME_TOSERVER:
 1449                 getnanotime(&(a)->va_mtime);
 1450                 if (toclient == 0)
 1451                         a->va_vaflags |= VA_UTIMES_NULL;
 1452                 break;
 1453         }
 1454         return 0;
 1455 }

Cache object: 6f71f5ea9b8afd53ff77b0e9cbfccec2


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