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