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

Cache object: 10938404ecb1401f1fce15ed49641825


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