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

Cache object: 6b2de753e947e50a6ac68c88e44a89de


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