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