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

Cache object: 1045603c1f023802dd21a111f938bf8d


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