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