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

Cache object: 96952afdad675f405b7807f4481972f7


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