home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / nfs / nfs_subs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-20  |  26.3 KB  |  1,143 lines

  1. /*
  2.  * Copyright (c) 1989 The Regents of the University of California.
  3.  * 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    7.41 (Berkeley) 5/15/91
  37.  */
  38.  
  39. /*
  40.  * These functions support the macros and help fiddle mbuf chains for
  41.  * the nfs op functions. They do things like create the rpc header and
  42.  * copy data between mbuf chains and uio lists.
  43.  */
  44. #include "param.h"
  45. #include "proc.h"
  46. #include "filedesc.h"
  47. #include "systm.h"
  48. #include "kernel.h"
  49. #include "mount.h"
  50. #include "file.h"
  51. #include "vnode.h"
  52. #include "namei.h"
  53. #include "mbuf.h"
  54. #include "map.h"
  55.  
  56. #include "../ufs/quota.h"
  57. #include "../ufs/inode.h"
  58.  
  59. #include "rpcv2.h"
  60. #include "nfsv2.h"
  61. #include "nfsnode.h"
  62. #include "nfs.h"
  63. #include "nfsiom.h"
  64. #include "xdr_subs.h"
  65. #include "nfsm_subs.h"
  66. #include "nfscompress.h"
  67.  
  68. #define TRUE    1
  69. #define    FALSE    0
  70.  
  71. /*
  72.  * Data items converted to xdr at startup, since they are constant
  73.  * This is kinda hokey, but may save a little time doing byte swaps
  74.  */
  75. u_long nfs_procids[NFS_NPROCS];
  76. u_long nfs_xdrneg1;
  77. u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied,
  78.     rpc_mismatch, rpc_auth_unix, rpc_msgaccepted;
  79. u_long nfs_vers, nfs_prog, nfs_true, nfs_false;
  80. /* And other global data */
  81. static u_long *rpc_uidp = (u_long *)0;
  82. static u_long nfs_xid = 1;
  83. static char *rpc_unixauth;
  84. extern long hostid;
  85. enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON };
  86. extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
  87. extern struct map nfsmap[NFS_MSIZ];
  88. extern struct nfsreq nfsreqh;
  89.  
  90. /* Function ret types */
  91. static char *nfs_unixauth();
  92.  
  93. /*
  94.  * Maximum number of groups passed through to NFS server.
  95.  * According to RFC1057 it should be 16.
  96.  * For release 3.X systems, the maximum value is 8.
  97.  * For some other servers, the maximum value is 10.
  98.  */
  99. int numgrps = 8;
  100.  
  101. /*
  102.  * Create the header for an rpc request packet
  103.  * The function nfs_unixauth() creates a unix style authorization string
  104.  * and returns a ptr to it.
  105.  * The hsiz is the size of the rest of the nfs request header.
  106.  * (just used to decide if a cluster is a good idea)
  107.  * nb: Note that the prog, vers and procid args are already in xdr byte order
  108.  */
  109. struct mbuf *nfsm_reqh(prog, vers, procid, cred, hsiz, bpos, mb, retxid)
  110.     u_long prog;
  111.     u_long vers;
  112.     u_long procid;
  113.     struct ucred *cred;
  114.     int hsiz;
  115.     caddr_t *bpos;
  116.     struct mbuf **mb;
  117.     u_long *retxid;
  118. {
  119.     register struct mbuf *mreq, *m;
  120.     register u_long *tl;
  121.     struct mbuf *m1;
  122.     char *ap;
  123.     int asiz, siz;
  124.  
  125.     NFSMGETHDR(mreq);
  126.     asiz = ((((cred->cr_ngroups - 1) > numgrps) ? numgrps :
  127.           (cred->cr_ngroups - 1)) << 2);
  128. #ifdef FILLINHOST
  129.     asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED);
  130. #else
  131.     asiz += 9*NFSX_UNSIGNED;
  132. #endif
  133.  
  134.     /* If we need a lot, alloc a cluster ?? */
  135.     if ((asiz+hsiz+RPC_SIZ) > MHLEN)
  136.         MCLGET(mreq, M_WAIT);
  137.     mreq->m_len = NFSMSIZ(mreq);
  138.     siz = mreq->m_len;
  139.     m1 = mreq;
  140.     /*
  141.      * Alloc enough mbufs
  142.      * We do it now to avoid all sleeps after the call to nfs_unixauth()
  143.      */
  144.     while ((asiz+RPC_SIZ) > siz) {
  145.         MGET(m, M_WAIT, MT_DATA);
  146.         m1->m_next = m;
  147.         m->m_len = MLEN;
  148.         siz += MLEN;
  149.         m1 = m;
  150.     }
  151.     tl = mtod(mreq, u_long *);
  152.     *tl++ = *retxid = txdr_unsigned(++nfs_xid);
  153.     *tl++ = rpc_call;
  154.     *tl++ = rpc_vers;
  155.     *tl++ = prog;
  156.     *tl++ = vers;
  157.     *tl++ = procid;
  158.  
  159.     /* Now we can call nfs_unixauth() and copy it in */
  160.     ap = nfs_unixauth(cred);
  161.     m = mreq;
  162.     siz = m->m_len-RPC_SIZ;
  163.     if (asiz <= siz) {
  164.         bcopy(ap, (caddr_t)tl, asiz);
  165.         m->m_len = asiz+RPC_SIZ;
  166.     } else {
  167.         bcopy(ap, (caddr_t)tl, siz);
  168.         ap += siz;
  169.         asiz -= siz;
  170.         while (asiz > 0) {
  171.             siz = (asiz > MLEN) ? MLEN : asiz;
  172.             m = m->m_next;
  173.             bcopy(ap, mtod(m, caddr_t), siz);
  174.             m->m_len = siz;
  175.             asiz -= siz;
  176.             ap += siz;
  177.         }
  178.     }
  179.     
  180.     /* Finally, return values */
  181.     *mb = m;
  182.     *bpos = mtod(m, caddr_t)+m->m_len;
  183.     return (mreq);
  184. }
  185.  
  186. /*
  187.  * copies mbuf chain to the uio scatter/gather list
  188.  */
  189. nfsm_mbuftouio(mrep, uiop, siz, dpos)
  190.     struct mbuf **mrep;
  191.     register struct uio *uiop;
  192.     int siz;
  193.     caddr_t *dpos;
  194. {
  195.     register char *mbufcp, *uiocp;
  196.     register int xfer, left, len;
  197.     register struct mbuf *mp;
  198.     long uiosiz, rem;
  199.     int error = 0;
  200.  
  201.     mp = *mrep;
  202.     mbufcp = *dpos;
  203.     len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
  204.     rem = nfsm_rndup(siz)-siz;
  205.     while (siz > 0) {
  206.         if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
  207.             return (EFBIG);
  208.         left = uiop->uio_iov->iov_len;
  209.         uiocp = uiop->uio_iov->iov_base;
  210.         if (left > siz)
  211.             left = siz;
  212.         uiosiz = left;
  213.         while (left > 0) {
  214.             while (len == 0) {
  215.                 mp = mp->m_next;
  216.                 if (mp == NULL)
  217.                     return (EBADRPC);
  218.                 mbufcp = mtod(mp, caddr_t);
  219.                 len = mp->m_len;
  220.             }
  221.             xfer = (left > len) ? len : left;
  222. #ifdef notdef
  223.             /* Not Yet.. */
  224.             if (uiop->uio_iov->iov_op != NULL)
  225.                 (*(uiop->uio_iov->iov_op))
  226.                 (mbufcp, uiocp, xfer);
  227.             else
  228. #endif
  229.             if (uiop->uio_segflg == UIO_SYSSPACE)
  230.                 bcopy(mbufcp, uiocp, xfer);
  231.             else
  232.                 copyout(mbufcp, uiocp, xfer);
  233.             left -= xfer;
  234.             len -= xfer;
  235.             mbufcp += xfer;
  236.             uiocp += xfer;
  237.             uiop->uio_offset += xfer;
  238.             uiop->uio_resid -= xfer;
  239.         }
  240.         if (uiop->uio_iov->iov_len <= siz) {
  241.             uiop->uio_iovcnt--;
  242.             uiop->uio_iov++;
  243.         } else {
  244.             uiop->uio_iov->iov_base += uiosiz;
  245.             uiop->uio_iov->iov_len -= uiosiz;
  246.         }
  247.         siz -= uiosiz;
  248.     }
  249.     *dpos = mbufcp;
  250.     *mrep = mp;
  251.     if (rem > 0) {
  252.         if (len < rem)
  253.             error = nfs_adv(mrep, dpos, rem, len);
  254.         else
  255.             *dpos += rem;
  256.     }
  257.     return (error);
  258. }
  259.  
  260. /*
  261.  * copies a uio scatter/gather list to an mbuf chain...
  262.  */
  263. nfsm_uiotombuf(uiop, mq, siz, bpos)
  264.     register struct uio *uiop;
  265.     struct mbuf **mq;
  266.     int siz;
  267.     caddr_t *bpos;
  268. {
  269.     register char *uiocp;
  270.     register struct mbuf *mp, *mp2;
  271.     register int xfer, left, len;
  272.     int uiosiz, clflg, rem;
  273.     char *cp;
  274.  
  275.     if (siz > MLEN)        /* or should it >= MCLBYTES ?? */
  276.         clflg = 1;
  277.     else
  278.         clflg = 0;
  279.     rem = nfsm_rndup(siz)-siz;
  280.     mp2 = *mq;
  281.     while (siz > 0) {
  282.         if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
  283.             return (EINVAL);
  284.         left = uiop->uio_iov->iov_len;
  285.         uiocp = uiop->uio_iov->iov_base;
  286.         if (left > siz)
  287.             left = siz;
  288.         uiosiz = left;
  289.         while (left > 0) {
  290.             MGET(mp, M_WAIT, MT_DATA);
  291.             if (clflg)
  292.                 MCLGET(mp, M_WAIT);
  293.             mp->m_len = NFSMSIZ(mp);
  294.             mp2->m_next = mp;
  295.             mp2 = mp;
  296.             xfer = (left > mp->m_len) ? mp->m_len : left;
  297. #ifdef notdef
  298.             /* Not Yet.. */
  299.             if (uiop->uio_iov->iov_op != NULL)
  300.                 (*(uiop->uio_iov->iov_op))
  301.                 (uiocp, mtod(mp, caddr_t), xfer);
  302.             else
  303. #endif
  304.             if (uiop->uio_segflg == UIO_SYSSPACE)
  305.                 bcopy(uiocp, mtod(mp, caddr_t), xfer);
  306.             else
  307.                 copyin(uiocp, mtod(mp, caddr_t), xfer);
  308.             len = mp->m_len;
  309.             mp->m_len = xfer;
  310.             left -= xfer;
  311.             uiocp += xfer;
  312.             uiop->uio_offset += xfer;
  313.             uiop->uio_resid -= xfer;
  314.         }
  315.         if (uiop->uio_iov->iov_len <= siz) {
  316.             uiop->uio_iovcnt--;
  317.             uiop->uio_iov++;
  318.         } else {
  319.             uiop->uio_iov->iov_base += uiosiz;
  320.             uiop->uio_iov->iov_len -= uiosiz;
  321.         }
  322.         siz -= uiosiz;
  323.     }
  324.     if (rem > 0) {
  325.         if (rem > (len-mp->m_len)) {
  326.             MGET(mp, M_WAIT, MT_DATA);
  327.             mp->m_len = 0;
  328.             mp2->m_next = mp;
  329.         }
  330.         cp = mtod(mp, caddr_t)+mp->m_len;
  331.         for (left = 0; left < rem; left++)
  332.             *cp++ = '\0';
  333.         mp->m_len += rem;
  334.         *bpos = cp;
  335.     } else
  336.         *bpos = mtod(mp, caddr_t)+mp->m_len;
  337.     *mq = mp;
  338.     return (0);
  339. }
  340.  
  341. /*
  342.  * Help break down an mbuf chain by setting the first siz bytes contiguous
  343.  * pointed to by returned val.
  344.  * If Updateflg == True we can overwrite the first part of the mbuf data
  345.  * This is used by the macros nfsm_disect and nfsm_disecton for tough
  346.  * cases. (The macros use the vars. dpos and dpos2)
  347.  */
  348. nfsm_disct(mdp, dposp, siz, left, updateflg, cp2)
  349.     struct mbuf **mdp;
  350.     caddr_t *dposp;
  351.     int siz;
  352.     int left;
  353.     int updateflg;
  354.     caddr_t *cp2;
  355. {
  356.     register struct mbuf *mp, *mp2;
  357.     register int siz2, xfer;
  358.     register caddr_t tl;
  359.  
  360.     mp = *mdp;
  361.     while (left == 0) {
  362.         *mdp = mp = mp->m_next;
  363.         if (mp == NULL)
  364.             return (EBADRPC);
  365.         left = mp->m_len;
  366.         *dposp = mtod(mp, caddr_t);
  367.     }
  368.     if (left >= siz) {
  369.         *cp2 = *dposp;
  370.         *dposp += siz;
  371.     } else if (mp->m_next == NULL) {
  372.         return (EBADRPC);
  373.     } else if (siz > MHLEN) {
  374.         panic("nfs S too big");
  375.     } else {
  376.         /* Iff update, you can overwrite, else must alloc new mbuf */
  377.         if (updateflg) {
  378.             NFSMINOFF(mp);
  379.         } else {
  380.             MGET(mp2, M_WAIT, MT_DATA);
  381.             mp2->m_next = mp->m_next;
  382.             mp->m_next = mp2;
  383.             mp->m_len -= left;
  384.             mp = mp2;
  385.         }
  386.         *cp2 = tl = mtod(mp, caddr_t);
  387.         bcopy(*dposp, tl, left);        /* Copy what was left */
  388.         siz2 = siz-left;
  389.         tl += left;
  390.         mp2 = mp->m_next;
  391.         /* Loop around copying up the siz2 bytes */
  392.         while (siz2 > 0) {
  393.             if (mp2 == NULL)
  394.                 return (EBADRPC);
  395.             xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
  396.             if (xfer > 0) {
  397.                 bcopy(mtod(mp2, caddr_t), tl, xfer);
  398.                 NFSMADV(mp2, xfer);
  399.                 mp2->m_len -= xfer;
  400.                 tl += xfer;
  401.                 siz2 -= xfer;
  402.             }
  403.             if (siz2 > 0)
  404.                 mp2 = mp2->m_next;
  405.         }
  406.         mp->m_len = siz;
  407.         *mdp = mp2;
  408.         *dposp = mtod(mp2, caddr_t);
  409.     }
  410.     return (0);
  411. }
  412.  
  413. /*
  414.  * Advance the position in the mbuf chain.
  415.  */
  416. nfs_adv(mdp, dposp, offs, left)
  417.     struct mbuf **mdp;
  418.     caddr_t *dposp;
  419.     int offs;
  420.     int left;
  421. {
  422.     register struct mbuf *m;
  423.     register int s;
  424.  
  425.     m = *mdp;
  426.     s = left;
  427.     while (s < offs) {
  428.         offs -= s;
  429.         m = m->m_next;
  430.         if (m == NULL)
  431.             return (EBADRPC);
  432.         s = m->m_len;
  433.     }
  434.     *mdp = m;
  435.     *dposp = mtod(m, caddr_t)+offs;
  436.     return (0);
  437. }
  438.  
  439. /*
  440.  * Copy a string into mbufs for the hard cases...
  441.  */
  442. nfsm_strtmbuf(mb, bpos, cp, siz)
  443.     struct mbuf **mb;
  444.     char **bpos;
  445.     char *cp;
  446.     long siz;
  447. {
  448.     register struct mbuf *m1, *m2;
  449.     long left, xfer, len, tlen;
  450.     u_long *tl;
  451.     int putsize;
  452.  
  453.     putsize = 1;
  454.     m2 = *mb;
  455.     left = NFSMSIZ(m2)-m2->m_len;
  456.     if (left > 0) {
  457.         tl = ((u_long *)(*bpos));
  458.         *tl++ = txdr_unsigned(siz);
  459.         putsize = 0;
  460.         left -= NFSX_UNSIGNED;
  461.         m2->m_len += NFSX_UNSIGNED;
  462.         if (left > 0) {
  463.             bcopy(cp, (caddr_t) tl, left);
  464.             siz -= left;
  465.             cp += left;
  466.             m2->m_len += left;
  467.             left = 0;
  468.         }
  469.     }
  470.     /* Loop arround adding mbufs */
  471.     while (siz > 0) {
  472.         MGET(m1, M_WAIT, MT_DATA);
  473.         if (siz > MLEN)
  474.             MCLGET(m1, M_WAIT);
  475.         m1->m_len = NFSMSIZ(m1);
  476.         m2->m_next = m1;
  477.         m2 = m1;
  478.         tl = mtod(m1, u_long *);
  479.         tlen = 0;
  480.         if (putsize) {
  481.             *tl++ = txdr_unsigned(siz);
  482.             m1->m_len -= NFSX_UNSIGNED;
  483.             tlen = NFSX_UNSIGNED;
  484.             putsize = 0;
  485.         }
  486.         if (siz < m1->m_len) {
  487.             len = nfsm_rndup(siz);
  488.             xfer = siz;
  489.             if (xfer < len)
  490.                 *(tl+(xfer>>2)) = 0;
  491.         } else {
  492.             xfer = len = m1->m_len;
  493.         }
  494.         bcopy(cp, (caddr_t) tl, xfer);
  495.         m1->m_len = len+tlen;
  496.         siz -= xfer;
  497.         cp += xfer;
  498.     }
  499.     *mb = m1;
  500.     *bpos = mtod(m1, caddr_t)+m1->m_len;
  501.     return (0);
  502. }
  503.  
  504. /*
  505.  * Called once to initialize data structures...
  506.  */
  507. nfs_init()
  508. {
  509.     register int i;
  510.  
  511.     rpc_vers = txdr_unsigned(RPC_VER2);
  512.     rpc_call = txdr_unsigned(RPC_CALL);
  513.     rpc_reply = txdr_unsigned(RPC_REPLY);
  514.     rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
  515.     rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
  516.     rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
  517.     rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
  518.     nfs_vers = txdr_unsigned(NFS_VER2);
  519.     nfs_prog = txdr_unsigned(NFS_PROG);
  520.     nfs_true = txdr_unsigned(TRUE);
  521.     nfs_false = txdr_unsigned(FALSE);
  522.     /* Loop thru nfs procids */
  523.     for (i = 0; i < NFS_NPROCS; i++)
  524.         nfs_procids[i] = txdr_unsigned(i);
  525.     /* Ensure async daemons disabled */
  526.     for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
  527.         nfs_iodwant[i] = (struct proc *)0;
  528.     nfs_xdrneg1 = txdr_unsigned(-1);
  529.     nfs_nhinit();            /* Init the nfsnode table */
  530.     nfsrv_initcache();        /* Init the server request cache */
  531.     rminit(nfsmap, (long)NFS_MAPREG, (long)1, "nfs mapreg", NFS_MSIZ);
  532.  
  533.     /*
  534.      * Initialize reply list and start timer
  535.      */
  536.     nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh;
  537.     nfs_timer();
  538. }
  539.  
  540. /*
  541.  * Fill in the rest of the rpc_unixauth and return it
  542.  */
  543. static char *nfs_unixauth(cr)
  544.     register struct ucred *cr;
  545. {
  546.     register u_long *tl;
  547.     register int i;
  548.     int ngr;
  549.  
  550.     /* Maybe someday there should be a cache of AUTH_SHORT's */
  551.     if ((tl = rpc_uidp) == NULL) {
  552. #ifdef FILLINHOST
  553.         i = nfsm_rndup(hostnamelen)+(25*NFSX_UNSIGNED);
  554. #else
  555.         i = 25*NFSX_UNSIGNED;
  556. #endif
  557.         MALLOC(tl, u_long *, i, M_TEMP, M_WAITOK);
  558.         bzero((caddr_t)tl, i);
  559.         rpc_unixauth = (caddr_t)tl;
  560.         *tl++ = txdr_unsigned(RPCAUTH_UNIX);
  561.         tl++;    /* Fill in size later */
  562.         *tl++ = hostid;
  563. #ifdef FILLINHOST
  564.         *tl++ = txdr_unsigned(hostnamelen);
  565.         i = nfsm_rndup(hostnamelen);
  566.         bcopy(hostname, (caddr_t)tl, hostnamelen);
  567.         tl += (i>>2);
  568. #else
  569.         *tl++ = 0;
  570. #endif
  571.         rpc_uidp = tl;
  572.     }
  573.     *tl++ = txdr_unsigned(cr->cr_uid);
  574.     *tl++ = txdr_unsigned(cr->cr_groups[0]);
  575.     ngr = ((cr->cr_ngroups - 1) > numgrps) ? numgrps : (cr->cr_ngroups - 1);
  576.     *tl++ = txdr_unsigned(ngr);
  577.     for (i = 1; i <= ngr; i++)
  578.         *tl++ = txdr_unsigned(cr->cr_groups[i]);
  579.     /* And add the AUTH_NULL */
  580.     *tl++ = 0;
  581.     *tl = 0;
  582.     i = (((caddr_t)tl)-rpc_unixauth)-12;
  583.     tl = (u_long *)(rpc_unixauth+4);
  584.     *tl = txdr_unsigned(i);
  585.     return (rpc_unixauth);
  586. }
  587.  
  588. /*
  589.  * Attribute cache routines.
  590.  * nfs_loadattrcache() - loads or updates the cache contents from attributes
  591.  *    that are on the mbuf list
  592.  * nfs_getattrcache() - returns valid attributes if found in cache, returns
  593.  *    error otherwise
  594.  */
  595.  
  596. /*
  597.  * Load the attribute cache (that lives in the nfsnode entry) with
  598.  * the values on the mbuf list and
  599.  * Iff vap not NULL
  600.  *    copy the attributes to *vaper
  601.  */
  602. nfs_loadattrcache(vpp, mdp, dposp, vaper)
  603.     struct vnode **vpp;
  604.     struct mbuf **mdp;
  605.     caddr_t *dposp;
  606.     struct vattr *vaper;
  607. {
  608.     register struct vnode *vp = *vpp;
  609.     register struct vattr *vap;
  610.     register struct nfsv2_fattr *fp;
  611.     extern struct vnodeops spec_nfsv2nodeops;
  612.     register struct nfsnode *np;
  613.     register long t1;
  614.     caddr_t dpos, cp2;
  615.     int error = 0;
  616.     struct mbuf *md;
  617.     enum vtype type;
  618.     u_short mode;
  619.     long rdev;
  620.     struct timeval mtime;
  621.     struct vnode *nvp;
  622.  
  623.     md = *mdp;
  624.     dpos = *dposp;
  625.     t1 = (mtod(md, caddr_t)+md->m_len)-dpos;
  626.     if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2))
  627.         return (error);
  628.     fp = (struct nfsv2_fattr *)cp2;
  629.     type = nfstov_type(fp->fa_type);
  630.     mode = fxdr_unsigned(u_short, fp->fa_mode);
  631.     if (type == VNON)
  632.         type = IFTOVT(mode);
  633.     rdev = fxdr_unsigned(long, fp->fa_rdev);
  634.     fxdr_time(&fp->fa_mtime, &mtime);
  635.     /*
  636.      * If v_type == VNON it is a new node, so fill in the v_type,
  637.      * n_mtime fields. Check to see if it represents a special 
  638.      * device, and if so, check for a possible alias. Once the
  639.      * correct vnode has been obtained, fill in the rest of the
  640.      * information.
  641.      */
  642.     np = VTONFS(vp);
  643.     if (vp->v_type == VNON) {
  644.         if (type == VCHR && rdev == 0xffffffff)
  645.             vp->v_type = type = VFIFO;
  646.         else
  647.             vp->v_type = type;
  648.         if (vp->v_type == VFIFO) {
  649. #ifdef FIFO
  650.             extern struct vnodeops fifo_nfsv2nodeops;
  651.             vp->v_op = &fifo_nfsv2nodeops;
  652. #else
  653.             return (EOPNOTSUPP);
  654. #endif /* FIFO */
  655.         }
  656.         if (vp->v_type == VCHR || vp->v_type == VBLK) {
  657.             vp->v_op = &spec_nfsv2nodeops;
  658.             if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) {
  659.                 /*
  660.                  * Reinitialize aliased node.
  661.                  */
  662.                 np = VTONFS(nvp);
  663.                 np->n_vnode = nvp;
  664.                 np->n_flag = 0;
  665.                 nfs_lock(nvp);
  666.                 bcopy((caddr_t)&VTONFS(vp)->n_fh,
  667.                     (caddr_t)&np->n_fh, NFSX_FH);
  668.                 insque(np, nfs_hash(&np->n_fh));
  669.                 np->n_attrstamp = 0;
  670.                 np->n_sillyrename = (struct sillyrename *)0;
  671.                 /*
  672.                  * Discard unneeded vnode and update actual one
  673.                  */
  674.                 vput(vp);
  675.                 *vpp = nvp;
  676.             }
  677.         }
  678.         np->n_mtime = mtime.tv_sec;
  679.     }
  680.     vap = &np->n_vattr;
  681.     vap->va_type = type;
  682.     vap->va_mode = (mode & 07777);
  683.     vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
  684.     vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
  685.     vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
  686.     vap->va_size = fxdr_unsigned(u_long, fp->fa_size);
  687.     if ((np->n_flag & NMODIFIED) == 0 || vap->va_size > np->n_size) {
  688.         np->n_size = vap->va_size;
  689.         vnode_pager_setsize(vp, np->n_size);
  690.     }
  691.     vap->va_size_rsv = 0;
  692.     vap->va_blocksize = fxdr_unsigned(long, fp->fa_blocksize);
  693.     vap->va_rdev = (dev_t)rdev;
  694.     vap->va_bytes = fxdr_unsigned(long, fp->fa_blocks) * NFS_FABLKSIZE;
  695.     vap->va_bytes_rsv = 0;
  696.     vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
  697.     vap->va_fileid = fxdr_unsigned(long, fp->fa_fileid);
  698.     vap->va_atime.tv_sec = fxdr_unsigned(long, fp->fa_atime.tv_sec);
  699.     vap->va_atime.tv_usec = 0;
  700.     vap->va_flags = fxdr_unsigned(u_long, fp->fa_atime.tv_usec);
  701.     vap->va_mtime = mtime;
  702.     vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa_ctime.tv_sec);
  703.     vap->va_ctime.tv_usec = 0;
  704.     vap->va_gen = fxdr_unsigned(u_long, fp->fa_ctime.tv_usec);
  705.     np->n_attrstamp = time.tv_sec;
  706.     *dposp = dpos;
  707.     *mdp = md;
  708.     if (vaper != NULL) {
  709.         bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
  710.         if ((np->n_flag & NMODIFIED) && (np->n_size > vap->va_size))
  711.             vaper->va_size = np->n_size;
  712.     }
  713.     return (0);
  714. }
  715.  
  716. /*
  717.  * Check the time stamp
  718.  * If the cache is valid, copy contents to *vap and return 0
  719.  * otherwise return an error
  720.  */
  721. nfs_getattrcache(vp, vap)
  722.     register struct vnode *vp;
  723.     struct vattr *vap;
  724. {
  725.     register struct nfsnode *np;
  726.  
  727.     np = VTONFS(vp);
  728.     if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) {
  729.         nfsstats.attrcache_hits++;
  730.         bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr));
  731.         if ((np->n_flag & NMODIFIED) == 0) {
  732.             np->n_size = vap->va_size;
  733.             vnode_pager_setsize(vp, np->n_size);
  734.         } else if (np->n_size > vap->va_size)
  735.             vap->va_size = np->n_size;
  736.         return (0);
  737.     } else {
  738.         nfsstats.attrcache_misses++;
  739.         return (ENOENT);
  740.     }
  741. }
  742.  
  743. /*
  744.  * Set up nameidata for a namei() call and do it
  745.  */
  746. nfs_namei(ndp, fhp, len, mdp, dposp, p)
  747.     register struct nameidata *ndp;
  748.     fhandle_t *fhp;
  749.     int len;
  750.     struct mbuf **mdp;
  751.     caddr_t *dposp;
  752.     struct proc *p;
  753. {
  754.     register int i, rem;
  755.     register struct mbuf *md;
  756.     register char *fromcp, *tocp;
  757.     struct vnode *dp;
  758.     int flag;
  759.     int error;
  760.  
  761.     flag = ndp->ni_nameiop & OPMASK;
  762.     MALLOC(ndp->ni_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
  763.     /*
  764.      * Copy the name from the mbuf list to ndp->ni_pnbuf
  765.      * and set the various ndp fields appropriately.
  766.      */
  767.     fromcp = *dposp;
  768.     tocp = ndp->ni_pnbuf;
  769.     md = *mdp;
  770.     rem = mtod(md, caddr_t) + md->m_len - fromcp;
  771.     ndp->ni_hash = 0;
  772.     for (i = 0; i < len; i++) {
  773.         while (rem == 0) {
  774.             md = md->m_next;
  775.             if (md == NULL) {
  776.                 error = EBADRPC;
  777.                 goto out;
  778.             }
  779.             fromcp = mtod(md, caddr_t);
  780.             rem = md->m_len;
  781.         }
  782.         if (*fromcp == '\0' || *fromcp == '/') {
  783.             error = EINVAL;
  784.             goto out;
  785.         }
  786.         if (*fromcp & 0200)
  787.             if ((*fromcp&0377) == ('/'|0200) || flag != DELETE) {
  788.                 error = EINVAL;
  789.                 goto out;
  790.             }
  791.         ndp->ni_hash += (unsigned char)*fromcp;
  792.         *tocp++ = *fromcp++;
  793.         rem--;
  794.     }
  795.     *tocp = '\0';
  796.     *mdp = md;
  797.     *dposp = fromcp;
  798.     len = nfsm_rndup(len)-len;
  799.     if (len > 0) {
  800.         if (rem >= len)
  801.             *dposp += len;
  802.         else if (error = nfs_adv(mdp, dposp, len, rem))
  803.             goto out;
  804.     }
  805.     ndp->ni_pathlen = tocp - ndp->ni_pnbuf;
  806.     ndp->ni_ptr = ndp->ni_pnbuf;
  807.     /*
  808.      * Extract and set starting directory.
  809.      */
  810.     if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cred))
  811.         goto out;
  812.     if (dp->v_type != VDIR) {
  813.         vrele(dp);
  814.         error = ENOTDIR;
  815.         goto out;
  816.     }
  817.     ndp->ni_startdir = dp;
  818.     ndp->ni_nameiop |= (NOCROSSMOUNT | REMOTE);
  819.     /*
  820.      * And call lookup() to do the real work
  821.      */
  822.     if (error = lookup(ndp, p))
  823.         goto out;
  824.     /*
  825.      * Check for encountering a symbolic link
  826.      */
  827.     if (ndp->ni_more) {
  828.         if ((ndp->ni_nameiop & LOCKPARENT) && ndp->ni_pathlen == 1)
  829.             vput(ndp->ni_dvp);
  830.         else
  831.             vrele(ndp->ni_dvp);
  832.         vput(ndp->ni_vp);
  833.         ndp->ni_vp = NULL;
  834.         error = EINVAL;
  835.         goto out;
  836.     }
  837.     /*
  838.      * Check for saved name request
  839.      */
  840.     if (ndp->ni_nameiop & (SAVENAME | SAVESTART)) {
  841.         ndp->ni_nameiop |= HASBUF;
  842.         return (0);
  843.     }
  844. out:
  845.     FREE(ndp->ni_pnbuf, M_NAMEI);
  846.     return (error);
  847. }
  848.  
  849. /*
  850.  * A fiddled version of m_adj() that ensures null fill to a long
  851.  * boundary and only trims off the back end
  852.  */
  853. nfsm_adj(mp, len, nul)
  854.     struct mbuf *mp;
  855.     register int len;
  856.     int nul;
  857. {
  858.     register struct mbuf *m;
  859.     register int count, i;
  860.     register char *cp;
  861.  
  862.     /*
  863.      * Trim from tail.  Scan the mbuf chain,
  864.      * calculating its length and finding the last mbuf.
  865.      * If the adjustment only affects this mbuf, then just
  866.      * adjust and return.  Otherwise, rescan and truncate
  867.      * after the remaining size.
  868.      */
  869.     count = 0;
  870.     m = mp;
  871.     for (;;) {
  872.         count += m->m_len;
  873.         if (m->m_next == (struct mbuf *)0)
  874.             break;
  875.         m = m->m_next;
  876.     }
  877.     if (m->m_len > len) {
  878.         m->m_len -= len;
  879.         if (nul > 0) {
  880.             cp = mtod(m, caddr_t)+m->m_len-nul;
  881.             for (i = 0; i < nul; i++)
  882.                 *cp++ = '\0';
  883.         }
  884.         return;
  885.     }
  886.     count -= len;
  887.     if (count < 0)
  888.         count = 0;
  889.     /*
  890.      * Correct length for chain is "count".
  891.      * Find the mbuf with last data, adjust its length,
  892.      * and toss data from remaining mbufs on chain.
  893.      */
  894.     for (m = mp; m; m = m->m_next) {
  895.         if (m->m_len >= count) {
  896.             m->m_len = count;
  897.             if (nul > 0) {
  898.                 cp = mtod(m, caddr_t)+m->m_len-nul;
  899.                 for (i = 0; i < nul; i++)
  900.                     *cp++ = '\0';
  901.             }
  902.             break;
  903.         }
  904.         count -= m->m_len;
  905.     }
  906.     while (m = m->m_next)
  907.         m->m_len = 0;
  908. }
  909.  
  910. /*
  911.  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
  912.  *     - look up fsid in mount list (if not found ret error)
  913.  *    - check that it is exported
  914.  *    - get vp by calling VFS_FHTOVP() macro
  915.  *    - if not lockflag unlock it with VOP_UNLOCK()
  916.  *    - if cred->cr_uid == 0 set it to m_exroot
  917.  */
  918. nfsrv_fhtovp(fhp, lockflag, vpp, cred)
  919.     fhandle_t *fhp;
  920.     int lockflag;
  921.     struct vnode **vpp;
  922.     struct ucred *cred;
  923. {
  924.     register struct mount *mp;
  925.  
  926.     if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
  927.         return (ESTALE);
  928.     if ((mp->mnt_flag & MNT_EXPORTED) == 0)
  929.         return (EACCES);
  930.     if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp))
  931.         return (ESTALE);
  932.     if (cred->cr_uid == 0)
  933.         cred->cr_uid = mp->mnt_exroot;
  934.     if (!lockflag)
  935.         VOP_UNLOCK(*vpp);
  936.     return (0);
  937. }
  938.  
  939. /*
  940.  * These two functions implement nfs rpc compression.
  941.  * The algorithm is a trivial run length encoding of '\0' bytes. The high
  942.  * order nibble of hex "e" is or'd with the number of zeroes - 2 in four
  943.  * bits. (2 - 17 zeros) Any data byte with a high order nibble of hex "e"
  944.  * is byte stuffed.
  945.  * The compressed data is padded with 0x0 bytes to an even multiple of
  946.  * 4 bytes in length to avoid any weird long pointer alignments.
  947.  * If compression/uncompression is unsuccessful, the original mbuf list
  948.  * is returned.
  949.  * The first four bytes (the XID) are left uncompressed and the fifth
  950.  * byte is set to 0x1 for request and 0x2 for reply.
  951.  * An uncompressed RPC will always have the fifth byte == 0x0.
  952.  */
  953. struct mbuf *
  954. nfs_compress(m0)
  955.     struct mbuf *m0;
  956. {
  957.     register u_char ch, nextch;
  958.     register int i, rlelast;
  959.     register u_char *ip, *op;
  960.     register int ileft, oleft, noteof;
  961.     register struct mbuf *m, *om;
  962.     struct mbuf **mp, *retm;
  963.     int olen, clget;
  964.  
  965.     i = rlelast = 0;
  966.     noteof = 1;
  967.     m = m0;
  968.     if (m->m_len < 12)
  969.         return (m0);
  970.     if (m->m_pkthdr.len >= MINCLSIZE)
  971.         clget = 1;
  972.     else
  973.         clget = 0;
  974.     ileft = m->m_len - 9;
  975.     ip = mtod(m, u_char *);
  976.     MGETHDR(om, M_WAIT, MT_DATA);
  977.     if (clget)
  978.         MCLGET(om, M_WAIT);
  979.     retm = om;
  980.     mp = &om->m_next;
  981.     olen = om->m_len = 5;
  982.     oleft = M_TRAILINGSPACE(om);
  983.     op = mtod(om, u_char *);
  984.     *((u_long *)op) = *((u_long *)ip);
  985.     ip += 7;
  986.     op += 4;
  987.     *op++ = *ip++ + 1;
  988.     nextch = *ip++;
  989.     while (noteof) {
  990.         ch = nextch;
  991.         if (ileft == 0) {
  992.             do {
  993.                 m = m->m_next;
  994.             } while (m && m->m_len == 0);
  995.             if (m) {
  996.                 ileft = m->m_len;
  997.                 ip = mtod(m, u_char *);
  998.             } else {
  999.                 noteof = 0;
  1000.                 nextch = 0x1;
  1001.                 goto doit;
  1002.             }
  1003.         }
  1004.         nextch = *ip++;
  1005.         ileft--;
  1006. doit:
  1007.         if (ch == '\0') {
  1008.             if (++i == NFSC_MAX || nextch != '\0') {
  1009.                 if (i < 2) {
  1010.                     nfscput('\0');
  1011.                 } else {
  1012.                     if (rlelast == i) {
  1013.                         nfscput('\0');
  1014.                         i--;
  1015.                     }
  1016.                     if (NFSCRLE(i) == (nextch & 0xff)) {
  1017.                         i--;
  1018.                         if (i < 2) {
  1019.                             nfscput('\0');
  1020.                         } else {
  1021.                             nfscput(NFSCRLE(i));
  1022.                         }
  1023.                         nfscput('\0');
  1024.                         rlelast = 0;
  1025.                     } else {
  1026.                         nfscput(NFSCRLE(i));
  1027.                         rlelast = i;
  1028.                     }
  1029.                 }
  1030.                 i = 0;
  1031.             }
  1032.         } else {
  1033.             if ((ch & NFSCRL) == NFSCRL) {
  1034.                 nfscput(ch);
  1035.             }
  1036.             nfscput(ch);
  1037.             i = rlelast = 0;
  1038.         }
  1039.     }
  1040.     if (olen < m0->m_pkthdr.len) {
  1041.         m_freem(m0);
  1042.         if (i = (olen & 0x3)) {
  1043.             i = 4 - i;
  1044.             while (i-- > 0) {
  1045.                 nfscput('\0');
  1046.             }
  1047.         }
  1048.         retm->m_pkthdr.len = olen;
  1049.         retm->m_pkthdr.rcvif = (struct ifnet *)0;
  1050.         return (retm);
  1051.     } else {
  1052.         m_freem(retm);
  1053.         return (m0);
  1054.     }
  1055. }
  1056.  
  1057. struct mbuf *
  1058. nfs_uncompress(m0)
  1059.     struct mbuf *m0;
  1060. {
  1061.     register u_char cp, nextcp, *ip, *op;
  1062.     register struct mbuf *m, *om;
  1063.     struct mbuf *retm, **mp;
  1064.     int i, j, noteof, clget, ileft, oleft, olen;
  1065.  
  1066.     m = m0;
  1067.     i = 0;
  1068.     while (m && i < MINCLSIZE) {
  1069.         i += m->m_len;
  1070.         m = m->m_next;
  1071.     }
  1072.     if (i < 6)
  1073.         return (m0);
  1074.     if (i >= MINCLSIZE)
  1075.         clget = 1;
  1076.     else
  1077.         clget = 0;
  1078.     m = m0;
  1079.     MGET(om, M_WAIT, MT_DATA);
  1080.     if (clget)
  1081.         MCLGET(om, M_WAIT);
  1082.     olen = om->m_len = 8;
  1083.     oleft = M_TRAILINGSPACE(om);
  1084.     op = mtod(om, u_char *);
  1085.     retm = om;
  1086.     mp = &om->m_next;
  1087.     if (m->m_len >= 6) {
  1088.         ileft = m->m_len - 6;
  1089.         ip = mtod(m, u_char *);
  1090.         *((u_long *)op) = *((u_long *)ip);
  1091.         bzero(op + 4, 3);
  1092.         ip += 4;
  1093.         op += 7;
  1094.         if (*ip == '\0') {
  1095.             m_freem(om);
  1096.             return (m0);
  1097.         }
  1098.         *op++ = *ip++ - 1;
  1099.         cp = *ip++;
  1100.     } else {
  1101.         ileft = m->m_len;
  1102.         ip = mtod(m, u_char *);
  1103.         nfscget(*op++);
  1104.         nfscget(*op++);
  1105.         nfscget(*op++);
  1106.         nfscget(*op++);
  1107.         bzero(op, 3);
  1108.         op += 3;
  1109.         nfscget(*op);
  1110.         if (*op == '\0') {
  1111.             m_freem(om);
  1112.             return (m0);
  1113.         }
  1114.         (*op)--;
  1115.         op++;
  1116.         nfscget(cp);
  1117.     }
  1118.     noteof = 1;
  1119.     while (noteof) {
  1120.         if ((cp & NFSCRL) == NFSCRL) {
  1121.             nfscget(nextcp);
  1122.             if (cp == nextcp) {
  1123.                 nfscput(cp);
  1124.                 goto readit;
  1125.             } else {
  1126.                 i = (cp & 0xf) + 2;
  1127.                 for (j = 0; j < i; j++) {
  1128.                     nfscput('\0');
  1129.                 }
  1130.                 cp = nextcp;
  1131.             }
  1132.         } else {
  1133.             nfscput(cp);
  1134. readit:
  1135.             nfscget(cp);
  1136.         }
  1137.     }
  1138.     m_freem(m0);
  1139.     if (i = (olen & 0x3))
  1140.         om->m_len -= i;
  1141.     return (retm);
  1142. }
  1143.