|
|
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.