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 | * | |
8 | * Redistribution and use in source and binary forms are permitted | |
9 | * provided that the above copyright notice and this paragraph are | |
10 | * duplicated in all such forms and that any documentation, | |
11 | * advertising materials, and other materials related to such | |
12 | * distribution and use acknowledge that the software was developed | |
13 | * by the University of California, Berkeley. The name of the | |
14 | * University may not be used to endorse or promote products derived | |
15 | * from this software without specific prior written permission. | |
16 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
17 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
19 | * | |
170bfd05 | 20 | * @(#)nfs_subs.c 7.27 (Berkeley) %G% |
180c0ba3 KM |
21 | */ |
22 | ||
23 | /* | |
24 | * These functions support the macros and help fiddle mbuf chains for | |
25 | * the nfs op functions. They do things like create the rpc header and | |
26 | * copy data between mbuf chains and uio lists. | |
27 | */ | |
180c0ba3 | 28 | #include "param.h" |
ffe6f482 KM |
29 | #include "user.h" |
30 | #include "proc.h" | |
e587d97d | 31 | #include "systm.h" |
180c0ba3 | 32 | #include "kernel.h" |
e587d97d | 33 | #include "mount.h" |
180c0ba3 KM |
34 | #include "file.h" |
35 | #include "vnode.h" | |
e587d97d KM |
36 | #include "mbuf.h" |
37 | #include "errno.h" | |
9238aa59 | 38 | #include "map.h" |
180c0ba3 KM |
39 | #include "rpcv2.h" |
40 | #include "nfsv2.h" | |
41 | #include "nfsnode.h" | |
42 | #include "nfs.h" | |
9238aa59 | 43 | #include "nfsiom.h" |
180c0ba3 KM |
44 | #include "xdr_subs.h" |
45 | #include "nfsm_subs.h" | |
46 | ||
47 | #define TRUE 1 | |
48 | #define FALSE 0 | |
49 | ||
50 | /* | |
51 | * Data items converted to xdr at startup, since they are constant | |
52 | * This is kinda hokey, but may save a little time doing byte swaps | |
53 | */ | |
54 | u_long nfs_procids[NFS_NPROCS]; | |
55 | u_long nfs_xdrneg1; | |
56 | u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, | |
57 | rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; | |
58 | u_long nfs_vers, nfs_prog, nfs_true, nfs_false; | |
59 | /* And other global data */ | |
60 | static u_long *rpc_uidp = (u_long *)0; | |
61 | static u_long nfs_xid = 1; | |
62 | static char *rpc_unixauth; | |
63 | extern long hostid; | |
d4e5799e | 64 | enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON }; |
f0f1cbaa | 65 | extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; |
9238aa59 | 66 | extern struct map nfsmap[NFS_MSIZ]; |
f0f1cbaa | 67 | extern struct nfsreq nfsreqh; |
180c0ba3 KM |
68 | |
69 | /* Function ret types */ | |
70 | static char *nfs_unixauth(); | |
71 | ||
7a398e6f KM |
72 | /* |
73 | * Maximum number of groups passed through to NFS server. | |
f0f1cbaa | 74 | * According to RFC1057 it should be 16. |
7a398e6f KM |
75 | * For release 3.X systems, the maximum value is 8. |
76 | * For release 4.X systems, the maximum value is 10. | |
77 | */ | |
78 | int numgrps = 8; | |
79 | ||
180c0ba3 KM |
80 | /* |
81 | * Create the header for an rpc request packet | |
82 | * The function nfs_unixauth() creates a unix style authorization string | |
83 | * and returns a ptr to it. | |
84 | * The hsiz is the size of the rest of the nfs request header. | |
85 | * (just used to decide if a cluster is a good idea) | |
0bd503ad | 86 | * nb: Note that the prog, vers and procid args are already in xdr byte order |
180c0ba3 | 87 | */ |
0bd503ad | 88 | struct mbuf *nfsm_reqh(prog, vers, procid, cred, hsiz, bpos, mb, retxid) |
180c0ba3 KM |
89 | u_long prog; |
90 | u_long vers; | |
0bd503ad | 91 | u_long procid; |
180c0ba3 KM |
92 | struct ucred *cred; |
93 | int hsiz; | |
94 | caddr_t *bpos; | |
95 | struct mbuf **mb; | |
96 | u_long *retxid; | |
97 | { | |
98 | register struct mbuf *mreq, *m; | |
99 | register u_long *p; | |
100 | struct mbuf *m1; | |
101 | char *ap; | |
102 | int asiz, siz; | |
103 | ||
104 | NFSMGETHDR(mreq); | |
7a398e6f | 105 | asiz = (((cred->cr_ngroups > numgrps) ? numgrps : cred->cr_ngroups)<<2); |
36c3043b | 106 | #ifdef FILLINHOST |
180c0ba3 | 107 | asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED); |
36c3043b KM |
108 | #else |
109 | asiz += 9*NFSX_UNSIGNED; | |
110 | #endif | |
180c0ba3 KM |
111 | |
112 | /* If we need a lot, alloc a cluster ?? */ | |
113 | if ((asiz+hsiz+RPC_SIZ) > MHLEN) | |
f0f1cbaa | 114 | MCLGET(mreq, M_WAIT); |
180c0ba3 KM |
115 | mreq->m_len = NFSMSIZ(mreq); |
116 | siz = mreq->m_len; | |
117 | m1 = mreq; | |
118 | /* | |
119 | * Alloc enough mbufs | |
120 | * We do it now to avoid all sleeps after the call to nfs_unixauth() | |
121 | */ | |
122 | while ((asiz+RPC_SIZ) > siz) { | |
123 | MGET(m, M_WAIT, MT_DATA); | |
124 | m1->m_next = m; | |
125 | m->m_len = MLEN; | |
126 | siz += MLEN; | |
127 | m1 = m; | |
128 | } | |
129 | p = mtod(mreq, u_long *); | |
130 | *p++ = *retxid = txdr_unsigned(++nfs_xid); | |
131 | *p++ = rpc_call; | |
132 | *p++ = rpc_vers; | |
133 | *p++ = prog; | |
134 | *p++ = vers; | |
0bd503ad | 135 | *p++ = procid; |
180c0ba3 KM |
136 | |
137 | /* Now we can call nfs_unixauth() and copy it in */ | |
138 | ap = nfs_unixauth(cred); | |
139 | m = mreq; | |
140 | siz = m->m_len-RPC_SIZ; | |
141 | if (asiz <= siz) { | |
142 | bcopy(ap, (caddr_t)p, asiz); | |
143 | m->m_len = asiz+RPC_SIZ; | |
144 | } else { | |
145 | bcopy(ap, (caddr_t)p, siz); | |
146 | ap += siz; | |
147 | asiz -= siz; | |
148 | while (asiz > 0) { | |
149 | siz = (asiz > MLEN) ? MLEN : asiz; | |
150 | m = m->m_next; | |
151 | bcopy(ap, mtod(m, caddr_t), siz); | |
152 | m->m_len = siz; | |
153 | asiz -= siz; | |
154 | ap += siz; | |
155 | } | |
156 | } | |
157 | ||
158 | /* Finally, return values */ | |
159 | *mb = m; | |
160 | *bpos = mtod(m, caddr_t)+m->m_len; | |
161 | return (mreq); | |
162 | } | |
163 | ||
164 | /* | |
165 | * copies mbuf chain to the uio scatter/gather list | |
166 | */ | |
167 | nfsm_mbuftouio(mrep, uiop, siz, dpos) | |
168 | struct mbuf **mrep; | |
170bfd05 | 169 | register struct uio *uiop; |
180c0ba3 KM |
170 | int siz; |
171 | caddr_t *dpos; | |
172 | { | |
170bfd05 | 173 | register char *mbufcp, *uiocp; |
180c0ba3 KM |
174 | register int xfer, left, len; |
175 | register struct mbuf *mp; | |
180c0ba3 | 176 | long uiosiz, rem; |
f0f1cbaa | 177 | int error = 0; |
180c0ba3 KM |
178 | |
179 | mp = *mrep; | |
180 | mbufcp = *dpos; | |
181 | len = mtod(mp, caddr_t)+mp->m_len-mbufcp; | |
182 | rem = nfsm_rndup(siz)-siz; | |
183 | while (siz > 0) { | |
184 | if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) | |
f0f1cbaa | 185 | return (EFBIG); |
180c0ba3 KM |
186 | left = uiop->uio_iov->iov_len; |
187 | uiocp = uiop->uio_iov->iov_base; | |
188 | if (left > siz) | |
189 | left = siz; | |
190 | uiosiz = left; | |
191 | while (left > 0) { | |
192 | while (len == 0) { | |
193 | mp = mp->m_next; | |
194 | if (mp == NULL) | |
195 | return (EBADRPC); | |
196 | mbufcp = mtod(mp, caddr_t); | |
197 | len = mp->m_len; | |
198 | } | |
199 | xfer = (left > len) ? len : left; | |
200 | #ifdef notdef | |
201 | /* Not Yet.. */ | |
202 | if (uiop->uio_iov->iov_op != NULL) | |
203 | (*(uiop->uio_iov->iov_op)) | |
204 | (mbufcp, uiocp, xfer); | |
205 | else | |
206 | #endif | |
207 | if (uiop->uio_segflg == UIO_SYSSPACE) | |
208 | bcopy(mbufcp, uiocp, xfer); | |
209 | else | |
210 | copyout(mbufcp, uiocp, xfer); | |
211 | left -= xfer; | |
212 | len -= xfer; | |
213 | mbufcp += xfer; | |
214 | uiocp += xfer; | |
24c658f0 | 215 | uiop->uio_offset += xfer; |
180c0ba3 KM |
216 | uiop->uio_resid -= xfer; |
217 | } | |
218 | if (uiop->uio_iov->iov_len <= siz) { | |
219 | uiop->uio_iovcnt--; | |
220 | uiop->uio_iov++; | |
221 | } else { | |
222 | uiop->uio_iov->iov_base += uiosiz; | |
223 | uiop->uio_iov->iov_len -= uiosiz; | |
224 | } | |
225 | siz -= uiosiz; | |
226 | } | |
180c0ba3 KM |
227 | *dpos = mbufcp; |
228 | *mrep = mp; | |
f0f1cbaa KM |
229 | if (rem > 0) { |
230 | if (len < rem) | |
231 | error = nfs_adv(mrep, dpos, rem, len); | |
232 | else | |
233 | *dpos += rem; | |
234 | } | |
235 | return (error); | |
180c0ba3 KM |
236 | } |
237 | ||
238 | /* | |
239 | * copies a uio scatter/gather list to an mbuf chain... | |
240 | */ | |
241 | nfsm_uiotombuf(uiop, mq, siz, bpos) | |
242 | register struct uio *uiop; | |
243 | struct mbuf **mq; | |
244 | int siz; | |
245 | caddr_t *bpos; | |
246 | { | |
170bfd05 KM |
247 | register char *uiocp; |
248 | register struct mbuf *mp, *mp2; | |
249 | register int xfer, left, len; | |
250 | int uiosiz, clflg, rem; | |
251 | char *cp; | |
180c0ba3 KM |
252 | |
253 | if (siz > MLEN) /* or should it >= MCLBYTES ?? */ | |
254 | clflg = 1; | |
255 | else | |
256 | clflg = 0; | |
257 | rem = nfsm_rndup(siz)-siz; | |
258 | mp2 = *mq; | |
259 | while (siz > 0) { | |
260 | if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) | |
f0f1cbaa | 261 | return (EINVAL); |
180c0ba3 KM |
262 | left = uiop->uio_iov->iov_len; |
263 | uiocp = uiop->uio_iov->iov_base; | |
264 | if (left > siz) | |
265 | left = siz; | |
266 | uiosiz = left; | |
267 | while (left > 0) { | |
268 | MGET(mp, M_WAIT, MT_DATA); | |
269 | if (clflg) | |
f0f1cbaa | 270 | MCLGET(mp, M_WAIT); |
180c0ba3 KM |
271 | mp->m_len = NFSMSIZ(mp); |
272 | mp2->m_next = mp; | |
273 | mp2 = mp; | |
274 | xfer = (left > mp->m_len) ? mp->m_len : left; | |
275 | #ifdef notdef | |
276 | /* Not Yet.. */ | |
277 | if (uiop->uio_iov->iov_op != NULL) | |
278 | (*(uiop->uio_iov->iov_op)) | |
279 | (uiocp, mtod(mp, caddr_t), xfer); | |
280 | else | |
281 | #endif | |
282 | if (uiop->uio_segflg == UIO_SYSSPACE) | |
283 | bcopy(uiocp, mtod(mp, caddr_t), xfer); | |
284 | else | |
285 | copyin(uiocp, mtod(mp, caddr_t), xfer); | |
286 | len = mp->m_len; | |
287 | mp->m_len = xfer; | |
288 | left -= xfer; | |
289 | uiocp += xfer; | |
24c658f0 | 290 | uiop->uio_offset += xfer; |
180c0ba3 KM |
291 | uiop->uio_resid -= xfer; |
292 | } | |
293 | if (uiop->uio_iov->iov_len <= siz) { | |
294 | uiop->uio_iovcnt--; | |
295 | uiop->uio_iov++; | |
296 | } else { | |
297 | uiop->uio_iov->iov_base += uiosiz; | |
298 | uiop->uio_iov->iov_len -= uiosiz; | |
299 | } | |
300 | siz -= uiosiz; | |
301 | } | |
302 | if (rem > 0) { | |
303 | if (rem > (len-mp->m_len)) { | |
304 | MGET(mp, M_WAIT, MT_DATA); | |
305 | mp->m_len = 0; | |
306 | mp2->m_next = mp; | |
307 | } | |
308 | cp = mtod(mp, caddr_t)+mp->m_len; | |
309 | for (left = 0; left < rem; left++) | |
310 | *cp++ = '\0'; | |
311 | mp->m_len += rem; | |
312 | *bpos = cp; | |
313 | } else | |
314 | *bpos = mtod(mp, caddr_t)+mp->m_len; | |
315 | *mq = mp; | |
f0f1cbaa | 316 | return (0); |
180c0ba3 KM |
317 | } |
318 | ||
319 | /* | |
320 | * Help break down an mbuf chain by setting the first siz bytes contiguous | |
321 | * pointed to by returned val. | |
322 | * If Updateflg == True we can overwrite the first part of the mbuf data | |
323 | * This is used by the macros nfsm_disect and nfsm_disecton for tough | |
324 | * cases. (The macros use the vars. dpos and dpos2) | |
325 | */ | |
326 | nfsm_disct(mdp, dposp, siz, left, updateflg, cp2) | |
327 | struct mbuf **mdp; | |
328 | caddr_t *dposp; | |
329 | int siz; | |
330 | int left; | |
331 | int updateflg; | |
332 | caddr_t *cp2; | |
333 | { | |
334 | register struct mbuf *mp, *mp2; | |
335 | register int siz2, xfer; | |
336 | register caddr_t p; | |
180c0ba3 KM |
337 | |
338 | mp = *mdp; | |
339 | while (left == 0) { | |
340 | *mdp = mp = mp->m_next; | |
341 | if (mp == NULL) | |
f0f1cbaa | 342 | return (EBADRPC); |
180c0ba3 KM |
343 | left = mp->m_len; |
344 | *dposp = mtod(mp, caddr_t); | |
345 | } | |
346 | if (left >= siz) { | |
347 | *cp2 = *dposp; | |
348 | *dposp += siz; | |
180c0ba3 | 349 | } else if (mp->m_next == NULL) { |
f0f1cbaa KM |
350 | return (EBADRPC); |
351 | } else if (siz > MHLEN) { | |
180c0ba3 KM |
352 | panic("nfs S too big"); |
353 | } else { | |
354 | /* Iff update, you can overwrite, else must alloc new mbuf */ | |
355 | if (updateflg) { | |
356 | NFSMINOFF(mp); | |
357 | } else { | |
358 | MGET(mp2, M_WAIT, MT_DATA); | |
359 | mp2->m_next = mp->m_next; | |
360 | mp->m_next = mp2; | |
361 | mp->m_len -= left; | |
362 | mp = mp2; | |
363 | } | |
180c0ba3 KM |
364 | *cp2 = p = mtod(mp, caddr_t); |
365 | bcopy(*dposp, p, left); /* Copy what was left */ | |
366 | siz2 = siz-left; | |
367 | p += left; | |
368 | mp2 = mp->m_next; | |
f0f1cbaa | 369 | /* Loop around copying up the siz2 bytes */ |
180c0ba3 KM |
370 | while (siz2 > 0) { |
371 | if (mp2 == NULL) | |
372 | return (EBADRPC); | |
373 | xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; | |
f0f1cbaa KM |
374 | if (xfer > 0) { |
375 | bcopy(mtod(mp2, caddr_t), p, xfer); | |
376 | NFSMADV(mp2, xfer); | |
377 | mp2->m_len -= xfer; | |
378 | p += xfer; | |
379 | siz2 -= xfer; | |
380 | } | |
180c0ba3 KM |
381 | if (siz2 > 0) |
382 | mp2 = mp2->m_next; | |
383 | } | |
384 | mp->m_len = siz; | |
385 | *mdp = mp2; | |
386 | *dposp = mtod(mp2, caddr_t); | |
180c0ba3 | 387 | } |
0bd503ad | 388 | return (0); |
180c0ba3 KM |
389 | } |
390 | ||
391 | /* | |
f0f1cbaa | 392 | * Advance the position in the mbuf chain. |
180c0ba3 KM |
393 | */ |
394 | nfs_adv(mdp, dposp, offs, left) | |
395 | struct mbuf **mdp; | |
396 | caddr_t *dposp; | |
397 | int offs; | |
398 | int left; | |
399 | { | |
400 | register struct mbuf *m; | |
401 | register int s; | |
402 | ||
403 | m = *mdp; | |
404 | s = left; | |
405 | while (s < offs) { | |
406 | offs -= s; | |
407 | m = m->m_next; | |
408 | if (m == NULL) | |
f0f1cbaa | 409 | return (EBADRPC); |
180c0ba3 KM |
410 | s = m->m_len; |
411 | } | |
412 | *mdp = m; | |
413 | *dposp = mtod(m, caddr_t)+offs; | |
f0f1cbaa | 414 | return (0); |
180c0ba3 KM |
415 | } |
416 | ||
417 | /* | |
418 | * Copy a string into mbufs for the hard cases... | |
419 | */ | |
420 | nfsm_strtmbuf(mb, bpos, cp, siz) | |
421 | struct mbuf **mb; | |
422 | char **bpos; | |
423 | char *cp; | |
424 | long siz; | |
425 | { | |
426 | register struct mbuf *m1, *m2; | |
427 | long left, xfer, len, tlen; | |
428 | u_long *p; | |
429 | int putsize; | |
430 | ||
431 | putsize = 1; | |
432 | m2 = *mb; | |
433 | left = NFSMSIZ(m2)-m2->m_len; | |
434 | if (left > 0) { | |
435 | p = ((u_long *)(*bpos)); | |
436 | *p++ = txdr_unsigned(siz); | |
437 | putsize = 0; | |
438 | left -= NFSX_UNSIGNED; | |
439 | m2->m_len += NFSX_UNSIGNED; | |
440 | if (left > 0) { | |
441 | bcopy(cp, (caddr_t) p, left); | |
442 | siz -= left; | |
443 | cp += left; | |
444 | m2->m_len += left; | |
445 | left = 0; | |
446 | } | |
447 | } | |
448 | /* Loop arround adding mbufs */ | |
449 | while (siz > 0) { | |
450 | MGET(m1, M_WAIT, MT_DATA); | |
451 | if (siz > MLEN) | |
f0f1cbaa | 452 | MCLGET(m1, M_WAIT); |
180c0ba3 KM |
453 | m1->m_len = NFSMSIZ(m1); |
454 | m2->m_next = m1; | |
455 | m2 = m1; | |
456 | p = mtod(m1, u_long *); | |
457 | tlen = 0; | |
458 | if (putsize) { | |
459 | *p++ = txdr_unsigned(siz); | |
460 | m1->m_len -= NFSX_UNSIGNED; | |
461 | tlen = NFSX_UNSIGNED; | |
462 | putsize = 0; | |
463 | } | |
464 | if (siz < m1->m_len) { | |
465 | len = nfsm_rndup(siz); | |
466 | xfer = siz; | |
467 | if (xfer < len) | |
468 | *(p+(xfer>>2)) = 0; | |
469 | } else { | |
470 | xfer = len = m1->m_len; | |
471 | } | |
472 | bcopy(cp, (caddr_t) p, xfer); | |
473 | m1->m_len = len+tlen; | |
474 | siz -= xfer; | |
475 | cp += xfer; | |
476 | } | |
477 | *mb = m1; | |
478 | *bpos = mtod(m1, caddr_t)+m1->m_len; | |
f0f1cbaa | 479 | return (0); |
180c0ba3 KM |
480 | } |
481 | ||
482 | /* | |
483 | * Called once to initialize data structures... | |
484 | */ | |
e16a8c9b | 485 | nfs_init() |
180c0ba3 KM |
486 | { |
487 | register int i; | |
488 | ||
489 | rpc_vers = txdr_unsigned(RPC_VER2); | |
490 | rpc_call = txdr_unsigned(RPC_CALL); | |
491 | rpc_reply = txdr_unsigned(RPC_REPLY); | |
492 | rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); | |
493 | rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); | |
494 | rpc_mismatch = txdr_unsigned(RPC_MISMATCH); | |
495 | rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); | |
496 | nfs_vers = txdr_unsigned(NFS_VER2); | |
497 | nfs_prog = txdr_unsigned(NFS_PROG); | |
498 | nfs_true = txdr_unsigned(TRUE); | |
499 | nfs_false = txdr_unsigned(FALSE); | |
500 | /* Loop thru nfs procids */ | |
501 | for (i = 0; i < NFS_NPROCS; i++) | |
502 | nfs_procids[i] = txdr_unsigned(i); | |
ffe6f482 | 503 | /* Ensure async daemons disabled */ |
f0f1cbaa | 504 | for (i = 0; i < NFS_MAXASYNCDAEMON; i++) |
ffe6f482 | 505 | nfs_iodwant[i] = (struct proc *)0; |
180c0ba3 KM |
506 | nfs_xdrneg1 = txdr_unsigned(-1); |
507 | nfs_nhinit(); /* Init the nfsnode table */ | |
e8540f59 | 508 | nfsrv_initcache(); /* Init the server request cache */ |
9238aa59 | 509 | rminit(nfsmap, (long)NFS_MAPREG, (long)1, "nfs mapreg", NFS_MSIZ); |
f0f1cbaa KM |
510 | |
511 | /* | |
512 | * Initialize reply list and start timer | |
513 | */ | |
514 | nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh; | |
180c0ba3 KM |
515 | nfs_timer(); |
516 | } | |
517 | ||
518 | /* | |
519 | * Fill in the rest of the rpc_unixauth and return it | |
520 | */ | |
521 | static char *nfs_unixauth(cr) | |
522 | register struct ucred *cr; | |
523 | { | |
524 | register u_long *p; | |
525 | register int i; | |
526 | int ngr; | |
527 | ||
528 | /* Maybe someday there should be a cache of AUTH_SHORT's */ | |
529 | if ((p = rpc_uidp) == NULL) { | |
36c3043b | 530 | #ifdef FILLINHOST |
180c0ba3 | 531 | i = nfsm_rndup(hostnamelen)+(19*NFSX_UNSIGNED); |
36c3043b KM |
532 | #else |
533 | i = 19*NFSX_UNSIGNED; | |
534 | #endif | |
180c0ba3 KM |
535 | MALLOC(p, u_long *, i, M_TEMP, M_WAITOK); |
536 | bzero((caddr_t)p, i); | |
537 | rpc_unixauth = (caddr_t)p; | |
538 | *p++ = txdr_unsigned(RPCAUTH_UNIX); | |
539 | p++; /* Fill in size later */ | |
540 | *p++ = hostid; | |
36c3043b | 541 | #ifdef FILLINHOST |
180c0ba3 KM |
542 | *p++ = txdr_unsigned(hostnamelen); |
543 | i = nfsm_rndup(hostnamelen); | |
544 | bcopy(hostname, (caddr_t)p, hostnamelen); | |
545 | p += (i>>2); | |
36c3043b KM |
546 | #else |
547 | *p++ = 0; | |
548 | #endif | |
180c0ba3 KM |
549 | rpc_uidp = p; |
550 | } | |
551 | *p++ = txdr_unsigned(cr->cr_uid); | |
552 | *p++ = txdr_unsigned(cr->cr_groups[0]); | |
7a398e6f | 553 | ngr = (cr->cr_ngroups > numgrps) ? numgrps : cr->cr_ngroups; |
180c0ba3 KM |
554 | *p++ = txdr_unsigned(ngr); |
555 | for (i = 0; i < ngr; i++) | |
556 | *p++ = txdr_unsigned(cr->cr_groups[i]); | |
557 | /* And add the AUTH_NULL */ | |
558 | *p++ = 0; | |
559 | *p = 0; | |
560 | i = (((caddr_t)p)-rpc_unixauth)-12; | |
561 | p = (u_long *)(rpc_unixauth+4); | |
562 | *p = txdr_unsigned(i); | |
f0f1cbaa | 563 | return (rpc_unixauth); |
180c0ba3 KM |
564 | } |
565 | ||
566 | /* | |
567 | * Attribute cache routines. | |
568 | * nfs_loadattrcache() - loads or updates the cache contents from attributes | |
569 | * that are on the mbuf list | |
570 | * nfs_getattrcache() - returns valid attributes if found in cache, returns | |
571 | * error otherwise | |
572 | */ | |
573 | ||
574 | /* | |
e16a8c9b | 575 | * Load the attribute cache (that lives in the nfsnode entry) with |
180c0ba3 KM |
576 | * the values on the mbuf list and |
577 | * Iff vap not NULL | |
578 | * copy the attributes to *vaper | |
579 | */ | |
610357c6 KM |
580 | nfs_loadattrcache(vpp, mdp, dposp, vaper) |
581 | struct vnode **vpp; | |
180c0ba3 KM |
582 | struct mbuf **mdp; |
583 | caddr_t *dposp; | |
584 | struct vattr *vaper; | |
585 | { | |
610357c6 | 586 | register struct vnode *vp = *vpp; |
180c0ba3 | 587 | register struct vattr *vap; |
9238aa59 | 588 | register struct nfsv2_fattr *fp; |
e16a8c9b | 589 | extern struct vnodeops spec_nfsv2nodeops; |
610357c6 | 590 | register struct nfsnode *np; |
0bd503ad KM |
591 | register long t1; |
592 | caddr_t dpos, cp2; | |
593 | int error = 0; | |
594 | struct mbuf *md; | |
e16a8c9b | 595 | enum vtype type; |
d4e5799e | 596 | long rdev; |
e16a8c9b KM |
597 | struct timeval mtime; |
598 | struct vnode *nvp; | |
180c0ba3 KM |
599 | |
600 | md = *mdp; | |
601 | dpos = *dposp; | |
602 | t1 = (mtod(md, caddr_t)+md->m_len)-dpos; | |
603 | if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2)) | |
604 | return (error); | |
9238aa59 | 605 | fp = (struct nfsv2_fattr *)cp2; |
e16a8c9b | 606 | type = nfstov_type(fp->fa_type); |
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; |
9238aa59 RM |
656 | vap->va_mode = nfstov_mode(fp->fa_mode); |
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); | |
661 | if ((np->n_flag & NMODIFIED) == 0 || vap->va_size > np->n_size) | |
662 | np->n_size = vap->va_size; | |
8fae943a | 663 | vap->va_size_rsv = 0; |
9238aa59 | 664 | vap->va_blocksize = fxdr_unsigned(long, fp->fa_blocksize); |
d4e5799e KM |
665 | vap->va_rdev = (dev_t)rdev; |
666 | vap->va_bytes = fxdr_unsigned(long, fp->fa_blocks) * NFS_FABLKSIZE; | |
8fae943a | 667 | vap->va_bytes_rsv = 0; |
a12d9e5a | 668 | vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; |
9238aa59 | 669 | vap->va_fileid = fxdr_unsigned(long, fp->fa_fileid); |
e8540f59 KM |
670 | vap->va_atime.tv_sec = fxdr_unsigned(long, fp->fa_atime.tv_sec); |
671 | vap->va_atime.tv_usec = 0; | |
672 | vap->va_flags = fxdr_unsigned(u_long, fp->fa_atime.tv_usec); | |
e16a8c9b | 673 | vap->va_mtime = mtime; |
e8540f59 KM |
674 | vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa_ctime.tv_sec); |
675 | vap->va_ctime.tv_usec = 0; | |
676 | vap->va_gen = fxdr_unsigned(u_long, fp->fa_ctime.tv_usec); | |
180c0ba3 KM |
677 | np->n_attrstamp = time.tv_sec; |
678 | *dposp = dpos; | |
679 | *mdp = md; | |
9238aa59 | 680 | if (vaper != NULL) { |
180c0ba3 | 681 | bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); |
9238aa59 RM |
682 | if ((np->n_flag & NMODIFIED) && (np->n_size > vap->va_size)) |
683 | vaper->va_size = np->n_size; | |
684 | } | |
180c0ba3 KM |
685 | return (0); |
686 | } | |
687 | ||
688 | /* | |
689 | * Check the time stamp | |
690 | * If the cache is valid, copy contents to *vap and return 0 | |
691 | * otherwise return an error | |
692 | */ | |
693 | nfs_getattrcache(vp, vap) | |
694 | register struct vnode *vp; | |
695 | struct vattr *vap; | |
696 | { | |
697 | register struct nfsnode *np; | |
698 | ||
699 | np = VTONFS(vp); | |
700 | if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) { | |
701 | nfsstats.attrcache_hits++; | |
702 | bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr)); | |
00b72154 KM |
703 | if ((np->n_flag & NMODIFIED) == 0) |
704 | np->n_size = vap->va_size; | |
705 | else if (np->n_size > vap->va_size) | |
9238aa59 | 706 | vap->va_size = np->n_size; |
180c0ba3 KM |
707 | return (0); |
708 | } else { | |
709 | nfsstats.attrcache_misses++; | |
710 | return (ENOENT); | |
711 | } | |
712 | } | |
713 | ||
180c0ba3 | 714 | /* |
f0f1cbaa | 715 | * Set up nameidata for a namei() call and do it |
180c0ba3 KM |
716 | */ |
717 | nfs_namei(ndp, fhp, len, mdp, dposp) | |
718 | register struct nameidata *ndp; | |
719 | fhandle_t *fhp; | |
720 | int len; | |
721 | struct mbuf **mdp; | |
722 | caddr_t *dposp; | |
723 | { | |
724 | register int i, rem; | |
725 | register struct mbuf *md; | |
726 | register char *cp; | |
f0f1cbaa | 727 | struct vnode *dp; |
180c0ba3 | 728 | int flag; |
f0f1cbaa | 729 | int error; |
180c0ba3 | 730 | |
d4e5799e KM |
731 | if ((ndp->ni_nameiop & HASBUF) == 0) { |
732 | flag = ndp->ni_nameiop & OPFLAG; | |
733 | /* | |
734 | * Copy the name from the mbuf list to the d_name field of ndp | |
735 | * and set the various ndp fields appropriately. | |
736 | */ | |
737 | cp = *dposp; | |
738 | md = *mdp; | |
739 | rem = mtod(md, caddr_t)+md->m_len-cp; | |
740 | ndp->ni_hash = 0; | |
741 | for (i = 0; i < len;) { | |
742 | while (rem == 0) { | |
743 | md = md->m_next; | |
744 | if (md == NULL) | |
745 | return (EBADRPC); | |
746 | cp = mtod(md, caddr_t); | |
747 | rem = md->m_len; | |
748 | } | |
749 | if (*cp == '\0' || *cp == '/') | |
180c0ba3 | 750 | return (EINVAL); |
d4e5799e KM |
751 | if (*cp & 0200) |
752 | if ((*cp&0377) == ('/'|0200) || flag != DELETE) | |
753 | return (EINVAL); | |
754 | ndp->ni_dent.d_name[i++] = *cp; | |
755 | ndp->ni_hash += (unsigned char)*cp * i; | |
756 | cp++; | |
757 | rem--; | |
758 | } | |
759 | *mdp = md; | |
760 | *dposp = cp; | |
761 | len = nfsm_rndup(len)-len; | |
762 | if (len > 0) { | |
763 | if (rem < len) { | |
764 | if (error = nfs_adv(mdp, dposp, len, rem)) | |
765 | return (error); | |
766 | } else | |
767 | *dposp += len; | |
768 | } | |
769 | } else | |
770 | i = len; | |
180c0ba3 KM |
771 | ndp->ni_namelen = i; |
772 | ndp->ni_dent.d_namlen = i; | |
773 | ndp->ni_dent.d_name[i] = '\0'; | |
d4e5799e | 774 | ndp->ni_segflg = UIO_SYSSPACE; |
36c3043b | 775 | ndp->ni_pathlen = 1; |
f0f1cbaa | 776 | ndp->ni_pnbuf = ndp->ni_dirp = ndp->ni_ptr = &ndp->ni_dent.d_name[0]; |
180c0ba3 | 777 | ndp->ni_next = &ndp->ni_dent.d_name[i]; |
f0f1cbaa | 778 | ndp->ni_nameiop |= (NOCROSSMOUNT | REMOTE | HASBUF); |
180c0ba3 | 779 | |
f0f1cbaa | 780 | if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cred)) |
180c0ba3 | 781 | return (error); |
36c3043b | 782 | if (dp->v_type != VDIR) { |
f0f1cbaa | 783 | vrele(dp); |
36c3043b KM |
784 | return (ENOTDIR); |
785 | } | |
ffe6f482 KM |
786 | /* |
787 | * Must set current directory here to avoid confusion in namei() | |
788 | * called from rename() | |
789 | */ | |
36c3043b | 790 | ndp->ni_cdir = dp; |
54fb9dc2 | 791 | ndp->ni_rdir = NULLVP; |
180c0ba3 KM |
792 | |
793 | /* | |
f0f1cbaa | 794 | * And call namei() to do the real work |
180c0ba3 | 795 | */ |
f0f1cbaa KM |
796 | error = namei(ndp); |
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 | } |