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