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 | * | |
610357c6 | 20 | * @(#)nfs_subs.c 7.11 (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 | */ | |
28 | #include "strings.h" | |
180c0ba3 | 29 | #include "param.h" |
e16a8c9b | 30 | #include "systm.h" |
ffe6f482 KM |
31 | #include "user.h" |
32 | #include "proc.h" | |
180c0ba3 | 33 | #include "mount.h" |
36c3043b | 34 | #include "../ufs/dir.h" |
180c0ba3 KM |
35 | #include "time.h" |
36 | #include "errno.h" | |
37 | #include "kernel.h" | |
38 | #include "malloc.h" | |
39 | #include "mbuf.h" | |
40 | #include "file.h" | |
41 | #include "vnode.h" | |
42 | #include "uio.h" | |
43 | #include "namei.h" | |
44 | #include "ucred.h" | |
9238aa59 | 45 | #include "map.h" |
180c0ba3 KM |
46 | #include "rpcv2.h" |
47 | #include "nfsv2.h" | |
48 | #include "nfsnode.h" | |
49 | #include "nfs.h" | |
9238aa59 | 50 | #include "nfsiom.h" |
180c0ba3 KM |
51 | #include "xdr_subs.h" |
52 | #include "nfsm_subs.h" | |
53 | ||
54 | #define TRUE 1 | |
55 | #define FALSE 0 | |
56 | ||
57 | /* | |
58 | * Data items converted to xdr at startup, since they are constant | |
59 | * This is kinda hokey, but may save a little time doing byte swaps | |
60 | */ | |
61 | u_long nfs_procids[NFS_NPROCS]; | |
62 | u_long nfs_xdrneg1; | |
63 | u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, | |
64 | rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; | |
65 | u_long nfs_vers, nfs_prog, nfs_true, nfs_false; | |
66 | /* And other global data */ | |
67 | static u_long *rpc_uidp = (u_long *)0; | |
68 | static u_long nfs_xid = 1; | |
69 | static char *rpc_unixauth; | |
70 | extern long hostid; | |
71 | extern enum vtype v_type[NFLNK+1]; | |
ffe6f482 | 72 | extern struct proc *nfs_iodwant[MAX_ASYNCDAEMON]; |
9238aa59 | 73 | extern struct map nfsmap[NFS_MSIZ]; |
180c0ba3 KM |
74 | |
75 | /* Function ret types */ | |
76 | static char *nfs_unixauth(); | |
77 | ||
7a398e6f KM |
78 | /* |
79 | * Maximum number of groups passed through to NFS server. | |
80 | * For release 3.X systems, the maximum value is 8. | |
81 | * For release 4.X systems, the maximum value is 10. | |
82 | */ | |
83 | int numgrps = 8; | |
84 | ||
180c0ba3 KM |
85 | /* |
86 | * Create the header for an rpc request packet | |
87 | * The function nfs_unixauth() creates a unix style authorization string | |
88 | * and returns a ptr to it. | |
89 | * The hsiz is the size of the rest of the nfs request header. | |
90 | * (just used to decide if a cluster is a good idea) | |
91 | * nb: Note that the prog, vers and proc args are already in xdr byte order | |
92 | */ | |
93 | struct mbuf *nfsm_reqh(prog, vers, proc, cred, hsiz, bpos, mb, retxid) | |
94 | u_long prog; | |
95 | u_long vers; | |
96 | u_long proc; | |
97 | struct ucred *cred; | |
98 | int hsiz; | |
99 | caddr_t *bpos; | |
100 | struct mbuf **mb; | |
101 | u_long *retxid; | |
102 | { | |
103 | register struct mbuf *mreq, *m; | |
104 | register u_long *p; | |
105 | struct mbuf *m1; | |
106 | char *ap; | |
107 | int asiz, siz; | |
108 | ||
109 | NFSMGETHDR(mreq); | |
7a398e6f | 110 | asiz = (((cred->cr_ngroups > numgrps) ? numgrps : cred->cr_ngroups)<<2); |
36c3043b | 111 | #ifdef FILLINHOST |
180c0ba3 | 112 | asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED); |
36c3043b KM |
113 | #else |
114 | asiz += 9*NFSX_UNSIGNED; | |
115 | #endif | |
180c0ba3 KM |
116 | |
117 | /* If we need a lot, alloc a cluster ?? */ | |
118 | if ((asiz+hsiz+RPC_SIZ) > MHLEN) | |
119 | NFSMCLGET(mreq, M_WAIT); | |
120 | mreq->m_len = NFSMSIZ(mreq); | |
121 | siz = mreq->m_len; | |
122 | m1 = mreq; | |
123 | /* | |
124 | * Alloc enough mbufs | |
125 | * We do it now to avoid all sleeps after the call to nfs_unixauth() | |
126 | */ | |
127 | while ((asiz+RPC_SIZ) > siz) { | |
128 | MGET(m, M_WAIT, MT_DATA); | |
129 | m1->m_next = m; | |
130 | m->m_len = MLEN; | |
131 | siz += MLEN; | |
132 | m1 = m; | |
133 | } | |
134 | p = mtod(mreq, u_long *); | |
135 | *p++ = *retxid = txdr_unsigned(++nfs_xid); | |
136 | *p++ = rpc_call; | |
137 | *p++ = rpc_vers; | |
138 | *p++ = prog; | |
139 | *p++ = vers; | |
140 | *p++ = proc; | |
141 | ||
142 | /* Now we can call nfs_unixauth() and copy it in */ | |
143 | ap = nfs_unixauth(cred); | |
144 | m = mreq; | |
145 | siz = m->m_len-RPC_SIZ; | |
146 | if (asiz <= siz) { | |
147 | bcopy(ap, (caddr_t)p, asiz); | |
148 | m->m_len = asiz+RPC_SIZ; | |
149 | } else { | |
150 | bcopy(ap, (caddr_t)p, siz); | |
151 | ap += siz; | |
152 | asiz -= siz; | |
153 | while (asiz > 0) { | |
154 | siz = (asiz > MLEN) ? MLEN : asiz; | |
155 | m = m->m_next; | |
156 | bcopy(ap, mtod(m, caddr_t), siz); | |
157 | m->m_len = siz; | |
158 | asiz -= siz; | |
159 | ap += siz; | |
160 | } | |
161 | } | |
162 | ||
163 | /* Finally, return values */ | |
164 | *mb = m; | |
165 | *bpos = mtod(m, caddr_t)+m->m_len; | |
166 | return (mreq); | |
167 | } | |
168 | ||
169 | /* | |
170 | * copies mbuf chain to the uio scatter/gather list | |
171 | */ | |
172 | nfsm_mbuftouio(mrep, uiop, siz, dpos) | |
173 | struct mbuf **mrep; | |
174 | struct uio *uiop; | |
175 | int siz; | |
176 | caddr_t *dpos; | |
177 | { | |
178 | register int xfer, left, len; | |
179 | register struct mbuf *mp; | |
180 | register char *mbufcp, *uiocp; | |
181 | long uiosiz, rem; | |
182 | ||
183 | mp = *mrep; | |
184 | mbufcp = *dpos; | |
185 | len = mtod(mp, caddr_t)+mp->m_len-mbufcp; | |
186 | rem = nfsm_rndup(siz)-siz; | |
187 | while (siz > 0) { | |
188 | if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) | |
189 | return(EFBIG); | |
190 | left = uiop->uio_iov->iov_len; | |
191 | uiocp = uiop->uio_iov->iov_base; | |
192 | if (left > siz) | |
193 | left = siz; | |
194 | uiosiz = left; | |
195 | while (left > 0) { | |
196 | while (len == 0) { | |
197 | mp = mp->m_next; | |
198 | if (mp == NULL) | |
199 | return (EBADRPC); | |
200 | mbufcp = mtod(mp, caddr_t); | |
201 | len = mp->m_len; | |
202 | } | |
203 | xfer = (left > len) ? len : left; | |
204 | #ifdef notdef | |
205 | /* Not Yet.. */ | |
206 | if (uiop->uio_iov->iov_op != NULL) | |
207 | (*(uiop->uio_iov->iov_op)) | |
208 | (mbufcp, uiocp, xfer); | |
209 | else | |
210 | #endif | |
211 | if (uiop->uio_segflg == UIO_SYSSPACE) | |
212 | bcopy(mbufcp, uiocp, xfer); | |
213 | else | |
214 | copyout(mbufcp, uiocp, xfer); | |
215 | left -= xfer; | |
216 | len -= xfer; | |
217 | mbufcp += xfer; | |
218 | uiocp += xfer; | |
219 | uiop->uio_resid -= xfer; | |
220 | } | |
221 | if (uiop->uio_iov->iov_len <= siz) { | |
222 | uiop->uio_iovcnt--; | |
223 | uiop->uio_iov++; | |
224 | } else { | |
225 | uiop->uio_iov->iov_base += uiosiz; | |
226 | uiop->uio_iov->iov_len -= uiosiz; | |
227 | } | |
228 | siz -= uiosiz; | |
229 | } | |
230 | if (rem > 0) | |
231 | mbufcp += rem; | |
232 | *dpos = mbufcp; | |
233 | *mrep = mp; | |
234 | return(0); | |
235 | } | |
236 | ||
237 | /* | |
238 | * copies a uio scatter/gather list to an mbuf chain... | |
239 | */ | |
240 | nfsm_uiotombuf(uiop, mq, siz, bpos) | |
241 | register struct uio *uiop; | |
242 | struct mbuf **mq; | |
243 | int siz; | |
244 | caddr_t *bpos; | |
245 | { | |
246 | register struct mbuf *mp; | |
247 | struct mbuf *mp2; | |
248 | long xfer, left, uiosiz, off; | |
249 | int clflg; | |
250 | int rem, len; | |
251 | char *cp, *uiocp; | |
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) | |
261 | return(EINVAL); | |
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) | |
270 | NFSMCLGET(mp, M_WAIT); | |
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; | |
290 | uiop->uio_resid -= xfer; | |
291 | } | |
292 | if (uiop->uio_iov->iov_len <= siz) { | |
293 | uiop->uio_iovcnt--; | |
294 | uiop->uio_iov++; | |
295 | } else { | |
296 | uiop->uio_iov->iov_base += uiosiz; | |
297 | uiop->uio_iov->iov_len -= uiosiz; | |
298 | } | |
299 | siz -= uiosiz; | |
300 | } | |
301 | if (rem > 0) { | |
302 | if (rem > (len-mp->m_len)) { | |
303 | MGET(mp, M_WAIT, MT_DATA); | |
304 | mp->m_len = 0; | |
305 | mp2->m_next = mp; | |
306 | } | |
307 | cp = mtod(mp, caddr_t)+mp->m_len; | |
308 | for (left = 0; left < rem; left++) | |
309 | *cp++ = '\0'; | |
310 | mp->m_len += rem; | |
311 | *bpos = cp; | |
312 | } else | |
313 | *bpos = mtod(mp, caddr_t)+mp->m_len; | |
314 | *mq = mp; | |
315 | return(0); | |
316 | } | |
317 | ||
318 | /* | |
319 | * Help break down an mbuf chain by setting the first siz bytes contiguous | |
320 | * pointed to by returned val. | |
321 | * If Updateflg == True we can overwrite the first part of the mbuf data | |
322 | * This is used by the macros nfsm_disect and nfsm_disecton for tough | |
323 | * cases. (The macros use the vars. dpos and dpos2) | |
324 | */ | |
325 | nfsm_disct(mdp, dposp, siz, left, updateflg, cp2) | |
326 | struct mbuf **mdp; | |
327 | caddr_t *dposp; | |
328 | int siz; | |
329 | int left; | |
330 | int updateflg; | |
331 | caddr_t *cp2; | |
332 | { | |
333 | register struct mbuf *mp, *mp2; | |
334 | register int siz2, xfer; | |
335 | register caddr_t p; | |
336 | caddr_t p2; | |
337 | ||
338 | mp = *mdp; | |
339 | while (left == 0) { | |
340 | *mdp = mp = mp->m_next; | |
341 | if (mp == NULL) | |
342 | return(EBADRPC); | |
343 | left = mp->m_len; | |
344 | *dposp = mtod(mp, caddr_t); | |
345 | } | |
346 | if (left >= siz) { | |
347 | *cp2 = *dposp; | |
348 | *dposp += siz; | |
349 | return(0); | |
350 | } else if (mp->m_next == NULL) { | |
351 | return(EBADRPC); | |
352 | } else if (siz > MCLBYTES) { | |
353 | panic("nfs S too big"); | |
354 | } else { | |
355 | /* Iff update, you can overwrite, else must alloc new mbuf */ | |
356 | if (updateflg) { | |
357 | NFSMINOFF(mp); | |
358 | } else { | |
359 | MGET(mp2, M_WAIT, MT_DATA); | |
360 | mp2->m_next = mp->m_next; | |
361 | mp->m_next = mp2; | |
362 | mp->m_len -= left; | |
363 | mp = mp2; | |
364 | } | |
365 | /* Alloc cluster iff we need it */ | |
366 | if (!M_HASCL(mp) && siz > NFSMSIZ(mp)) { | |
367 | NFSMCLGET(mp, M_WAIT); | |
368 | if (!M_HASCL(mp)) | |
369 | return(ENOBUFS); | |
370 | } | |
371 | *cp2 = p = mtod(mp, caddr_t); | |
372 | bcopy(*dposp, p, left); /* Copy what was left */ | |
373 | siz2 = siz-left; | |
374 | p += left; | |
375 | mp2 = mp->m_next; | |
376 | /* Loop arround copying up the siz2 bytes */ | |
377 | while (siz2 > 0) { | |
378 | if (mp2 == NULL) | |
379 | return (EBADRPC); | |
380 | xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; | |
381 | bcopy(mtod(mp2, caddr_t), p, xfer); | |
382 | NFSMADV(mp2, xfer); | |
383 | mp2->m_len -= xfer; | |
384 | siz2 -= xfer; | |
385 | if (siz2 > 0) | |
386 | mp2 = mp2->m_next; | |
387 | } | |
388 | mp->m_len = siz; | |
389 | *mdp = mp2; | |
390 | *dposp = mtod(mp2, caddr_t); | |
391 | return (0); | |
392 | } | |
393 | } | |
394 | ||
395 | /* | |
396 | * Advance the position in the mbuf chain with/without freeing mbufs | |
397 | */ | |
398 | nfs_adv(mdp, dposp, offs, left) | |
399 | struct mbuf **mdp; | |
400 | caddr_t *dposp; | |
401 | int offs; | |
402 | int left; | |
403 | { | |
404 | register struct mbuf *m; | |
405 | register int s; | |
406 | ||
407 | m = *mdp; | |
408 | s = left; | |
409 | while (s < offs) { | |
410 | offs -= s; | |
411 | m = m->m_next; | |
412 | if (m == NULL) | |
413 | return(EBADRPC); | |
414 | s = m->m_len; | |
415 | } | |
416 | *mdp = m; | |
417 | *dposp = mtod(m, caddr_t)+offs; | |
418 | return(0); | |
419 | } | |
420 | ||
421 | /* | |
422 | * Copy a string into mbufs for the hard cases... | |
423 | */ | |
424 | nfsm_strtmbuf(mb, bpos, cp, siz) | |
425 | struct mbuf **mb; | |
426 | char **bpos; | |
427 | char *cp; | |
428 | long siz; | |
429 | { | |
430 | register struct mbuf *m1, *m2; | |
431 | long left, xfer, len, tlen; | |
432 | u_long *p; | |
433 | int putsize; | |
434 | ||
435 | putsize = 1; | |
436 | m2 = *mb; | |
437 | left = NFSMSIZ(m2)-m2->m_len; | |
438 | if (left > 0) { | |
439 | p = ((u_long *)(*bpos)); | |
440 | *p++ = txdr_unsigned(siz); | |
441 | putsize = 0; | |
442 | left -= NFSX_UNSIGNED; | |
443 | m2->m_len += NFSX_UNSIGNED; | |
444 | if (left > 0) { | |
445 | bcopy(cp, (caddr_t) p, left); | |
446 | siz -= left; | |
447 | cp += left; | |
448 | m2->m_len += left; | |
449 | left = 0; | |
450 | } | |
451 | } | |
452 | /* Loop arround adding mbufs */ | |
453 | while (siz > 0) { | |
454 | MGET(m1, M_WAIT, MT_DATA); | |
455 | if (siz > MLEN) | |
456 | NFSMCLGET(m1, M_WAIT); | |
457 | m1->m_len = NFSMSIZ(m1); | |
458 | m2->m_next = m1; | |
459 | m2 = m1; | |
460 | p = mtod(m1, u_long *); | |
461 | tlen = 0; | |
462 | if (putsize) { | |
463 | *p++ = txdr_unsigned(siz); | |
464 | m1->m_len -= NFSX_UNSIGNED; | |
465 | tlen = NFSX_UNSIGNED; | |
466 | putsize = 0; | |
467 | } | |
468 | if (siz < m1->m_len) { | |
469 | len = nfsm_rndup(siz); | |
470 | xfer = siz; | |
471 | if (xfer < len) | |
472 | *(p+(xfer>>2)) = 0; | |
473 | } else { | |
474 | xfer = len = m1->m_len; | |
475 | } | |
476 | bcopy(cp, (caddr_t) p, xfer); | |
477 | m1->m_len = len+tlen; | |
478 | siz -= xfer; | |
479 | cp += xfer; | |
480 | } | |
481 | *mb = m1; | |
482 | *bpos = mtod(m1, caddr_t)+m1->m_len; | |
483 | return(0); | |
484 | } | |
485 | ||
486 | /* | |
487 | * Called once to initialize data structures... | |
488 | */ | |
e16a8c9b | 489 | nfs_init() |
180c0ba3 KM |
490 | { |
491 | register int i; | |
492 | ||
493 | rpc_vers = txdr_unsigned(RPC_VER2); | |
494 | rpc_call = txdr_unsigned(RPC_CALL); | |
495 | rpc_reply = txdr_unsigned(RPC_REPLY); | |
496 | rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); | |
497 | rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); | |
498 | rpc_mismatch = txdr_unsigned(RPC_MISMATCH); | |
499 | rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); | |
500 | nfs_vers = txdr_unsigned(NFS_VER2); | |
501 | nfs_prog = txdr_unsigned(NFS_PROG); | |
502 | nfs_true = txdr_unsigned(TRUE); | |
503 | nfs_false = txdr_unsigned(FALSE); | |
504 | /* Loop thru nfs procids */ | |
505 | for (i = 0; i < NFS_NPROCS; i++) | |
506 | nfs_procids[i] = txdr_unsigned(i); | |
ffe6f482 KM |
507 | /* Ensure async daemons disabled */ |
508 | for (i = 0; i < MAX_ASYNCDAEMON; i++) | |
509 | nfs_iodwant[i] = (struct proc *)0; | |
180c0ba3 KM |
510 | v_type[0] = VNON; |
511 | v_type[1] = VREG; | |
512 | v_type[2] = VDIR; | |
513 | v_type[3] = VBLK; | |
514 | v_type[4] = VCHR; | |
515 | v_type[5] = VLNK; | |
516 | nfs_xdrneg1 = txdr_unsigned(-1); | |
517 | nfs_nhinit(); /* Init the nfsnode table */ | |
9238aa59 | 518 | rminit(nfsmap, (long)NFS_MAPREG, (long)1, "nfs mapreg", NFS_MSIZ); |
180c0ba3 KM |
519 | /* And start timer */ |
520 | nfs_timer(); | |
521 | } | |
522 | ||
523 | /* | |
524 | * Fill in the rest of the rpc_unixauth and return it | |
525 | */ | |
526 | static char *nfs_unixauth(cr) | |
527 | register struct ucred *cr; | |
528 | { | |
529 | register u_long *p; | |
530 | register int i; | |
531 | int ngr; | |
532 | ||
533 | /* Maybe someday there should be a cache of AUTH_SHORT's */ | |
534 | if ((p = rpc_uidp) == NULL) { | |
36c3043b | 535 | #ifdef FILLINHOST |
180c0ba3 | 536 | i = nfsm_rndup(hostnamelen)+(19*NFSX_UNSIGNED); |
36c3043b KM |
537 | #else |
538 | i = 19*NFSX_UNSIGNED; | |
539 | #endif | |
180c0ba3 KM |
540 | MALLOC(p, u_long *, i, M_TEMP, M_WAITOK); |
541 | bzero((caddr_t)p, i); | |
542 | rpc_unixauth = (caddr_t)p; | |
543 | *p++ = txdr_unsigned(RPCAUTH_UNIX); | |
544 | p++; /* Fill in size later */ | |
545 | *p++ = hostid; | |
36c3043b | 546 | #ifdef FILLINHOST |
180c0ba3 KM |
547 | *p++ = txdr_unsigned(hostnamelen); |
548 | i = nfsm_rndup(hostnamelen); | |
549 | bcopy(hostname, (caddr_t)p, hostnamelen); | |
550 | p += (i>>2); | |
36c3043b KM |
551 | #else |
552 | *p++ = 0; | |
553 | #endif | |
180c0ba3 KM |
554 | rpc_uidp = p; |
555 | } | |
556 | *p++ = txdr_unsigned(cr->cr_uid); | |
557 | *p++ = txdr_unsigned(cr->cr_groups[0]); | |
7a398e6f | 558 | ngr = (cr->cr_ngroups > numgrps) ? numgrps : cr->cr_ngroups; |
180c0ba3 KM |
559 | *p++ = txdr_unsigned(ngr); |
560 | for (i = 0; i < ngr; i++) | |
561 | *p++ = txdr_unsigned(cr->cr_groups[i]); | |
562 | /* And add the AUTH_NULL */ | |
563 | *p++ = 0; | |
564 | *p = 0; | |
565 | i = (((caddr_t)p)-rpc_unixauth)-12; | |
566 | p = (u_long *)(rpc_unixauth+4); | |
567 | *p = txdr_unsigned(i); | |
568 | return(rpc_unixauth); | |
569 | } | |
570 | ||
571 | /* | |
572 | * Attribute cache routines. | |
573 | * nfs_loadattrcache() - loads or updates the cache contents from attributes | |
574 | * that are on the mbuf list | |
575 | * nfs_getattrcache() - returns valid attributes if found in cache, returns | |
576 | * error otherwise | |
577 | */ | |
578 | ||
579 | /* | |
e16a8c9b | 580 | * Load the attribute cache (that lives in the nfsnode entry) with |
180c0ba3 KM |
581 | * the values on the mbuf list and |
582 | * Iff vap not NULL | |
583 | * copy the attributes to *vaper | |
584 | */ | |
610357c6 KM |
585 | nfs_loadattrcache(vpp, mdp, dposp, vaper) |
586 | struct vnode **vpp; | |
180c0ba3 KM |
587 | struct mbuf **mdp; |
588 | caddr_t *dposp; | |
589 | struct vattr *vaper; | |
590 | { | |
610357c6 | 591 | register struct vnode *vp = *vpp; |
180c0ba3 | 592 | register struct vattr *vap; |
9238aa59 | 593 | register struct nfsv2_fattr *fp; |
e16a8c9b | 594 | extern struct vnodeops spec_nfsv2nodeops; |
610357c6 | 595 | register struct nfsnode *np; |
180c0ba3 | 596 | nfsm_vars; |
e16a8c9b KM |
597 | enum vtype type; |
598 | dev_t rdev; | |
599 | struct timeval mtime; | |
600 | struct vnode *nvp; | |
180c0ba3 KM |
601 | |
602 | md = *mdp; | |
603 | dpos = *dposp; | |
604 | t1 = (mtod(md, caddr_t)+md->m_len)-dpos; | |
605 | if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2)) | |
606 | return (error); | |
9238aa59 | 607 | fp = (struct nfsv2_fattr *)cp2; |
e16a8c9b KM |
608 | type = nfstov_type(fp->fa_type); |
609 | rdev = fxdr_unsigned(dev_t, fp->fa_rdev); | |
610 | fxdr_time(&fp->fa_mtime, &mtime); | |
611 | /* | |
612 | * If v_type == VNON it is a new node, so fill in the v_type, | |
613 | * n_mtime fields. Check to see if it represents a special | |
614 | * device, and if so, check for a possible alias. Once the | |
615 | * correct vnode has been obtained, fill in the rest of the | |
616 | * information. | |
617 | */ | |
180c0ba3 | 618 | np = VTONFS(vp); |
e16a8c9b KM |
619 | if (vp->v_type == VNON) { |
620 | vp->v_type = type; | |
621 | if (vp->v_type == VCHR || vp->v_type == VBLK) { | |
622 | vp->v_rdev = rdev; | |
623 | vp->v_op = &spec_nfsv2nodeops; | |
624 | if (nvp = checkalias(vp, vp->v_mount)) { | |
625 | /* | |
626 | * Reinitialize aliased node. | |
627 | */ | |
628 | np = VTONFS(nvp); | |
629 | np->n_vnode = nvp; | |
630 | np->n_flag = NLOCKED; | |
631 | bcopy((caddr_t)&VTONFS(vp)->n_fh, | |
632 | (caddr_t)&np->n_fh, NFSX_FH); | |
633 | insque(np, nfs_hash(&np->n_fh)); | |
634 | np->n_attrstamp = 0; | |
635 | np->n_sillyrename = (struct sillyrename *)0; | |
636 | /* | |
610357c6 | 637 | * Discard unneeded vnode and update actual one |
e16a8c9b KM |
638 | */ |
639 | vput(vp); | |
610357c6 | 640 | *vpp = nvp; |
e16a8c9b KM |
641 | } |
642 | } | |
643 | np->n_mtime = mtime.tv_sec; | |
644 | } | |
180c0ba3 | 645 | vap = &np->n_vattr; |
e16a8c9b | 646 | vap->va_type = type; |
9238aa59 RM |
647 | vap->va_mode = nfstov_mode(fp->fa_mode); |
648 | vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); | |
649 | vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); | |
650 | vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); | |
651 | vap->va_size = fxdr_unsigned(u_long, fp->fa_size); | |
652 | if ((np->n_flag & NMODIFIED) == 0 || vap->va_size > np->n_size) | |
653 | np->n_size = vap->va_size; | |
180c0ba3 | 654 | vap->va_size1 = 0; /* OR -1 ?? */ |
9238aa59 | 655 | vap->va_blocksize = fxdr_unsigned(long, fp->fa_blocksize); |
e16a8c9b | 656 | vap->va_rdev = rdev; |
9238aa59 RM |
657 | vap->va_bytes = fxdr_unsigned(long, fp->fa_blocks) * vap->va_blocksize; |
658 | vap->va_bytes1 = 0; | |
659 | vap->va_fsid = fxdr_unsigned(long, fp->fa_fsid); | |
660 | vap->va_fileid = fxdr_unsigned(long, fp->fa_fileid); | |
661 | fxdr_time(&fp->fa_atime, &vap->va_atime); | |
9238aa59 | 662 | fxdr_time(&fp->fa_ctime, &vap->va_ctime); |
e16a8c9b | 663 | vap->va_mtime = mtime; |
1f9b0aa5 KM |
664 | vap->va_gen = 0; |
665 | vap->va_flags = 0; | |
180c0ba3 KM |
666 | np->n_attrstamp = time.tv_sec; |
667 | *dposp = dpos; | |
668 | *mdp = md; | |
9238aa59 | 669 | if (vaper != NULL) { |
180c0ba3 | 670 | bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); |
9238aa59 RM |
671 | if ((np->n_flag & NMODIFIED) && (np->n_size > vap->va_size)) |
672 | vaper->va_size = np->n_size; | |
673 | } | |
180c0ba3 KM |
674 | return (0); |
675 | } | |
676 | ||
677 | /* | |
678 | * Check the time stamp | |
679 | * If the cache is valid, copy contents to *vap and return 0 | |
680 | * otherwise return an error | |
681 | */ | |
682 | nfs_getattrcache(vp, vap) | |
683 | register struct vnode *vp; | |
684 | struct vattr *vap; | |
685 | { | |
686 | register struct nfsnode *np; | |
687 | ||
688 | np = VTONFS(vp); | |
689 | if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) { | |
690 | nfsstats.attrcache_hits++; | |
691 | bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr)); | |
00b72154 KM |
692 | if ((np->n_flag & NMODIFIED) == 0) |
693 | np->n_size = vap->va_size; | |
694 | else if (np->n_size > vap->va_size) | |
9238aa59 | 695 | vap->va_size = np->n_size; |
180c0ba3 KM |
696 | return (0); |
697 | } else { | |
698 | nfsstats.attrcache_misses++; | |
699 | return (ENOENT); | |
700 | } | |
701 | } | |
702 | ||
180c0ba3 KM |
703 | /* |
704 | * nfs_namei - a liitle like namei(), but for one element only | |
705 | * essentially look up file handle, fill in ndp and call VOP_LOOKUP() | |
706 | */ | |
707 | nfs_namei(ndp, fhp, len, mdp, dposp) | |
708 | register struct nameidata *ndp; | |
709 | fhandle_t *fhp; | |
710 | int len; | |
711 | struct mbuf **mdp; | |
712 | caddr_t *dposp; | |
713 | { | |
714 | register int i, rem; | |
715 | register struct mbuf *md; | |
716 | register char *cp; | |
717 | struct vnode *dp = (struct vnode *)0; | |
718 | struct vnode *tdp; | |
719 | struct mount *mp; | |
720 | int flag; | |
721 | int docache; | |
722 | int wantparent; | |
723 | int lockparent; | |
724 | int rootflg = 0; | |
725 | int error = 0; | |
726 | ||
727 | ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0; | |
728 | flag = ndp->ni_nameiop & OPFLAG; | |
729 | wantparent = ndp->ni_nameiop & (LOCKPARENT | WANTPARENT); | |
730 | lockparent = ndp->ni_nameiop & LOCKPARENT; | |
731 | docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE; | |
732 | if (flag == DELETE || wantparent) | |
733 | docache = 0; | |
734 | ||
735 | /* Fill in the nameidata and call lookup */ | |
736 | cp = *dposp; | |
737 | md = *mdp; | |
738 | rem = mtod(md, caddr_t)+md->m_len-cp; | |
739 | ndp->ni_hash = 0; | |
740 | for (i = 0; i < len;) { | |
741 | if (rem == 0) { | |
742 | md = md->m_next; | |
743 | if (md == NULL) | |
744 | return (EBADRPC); | |
745 | cp = mtod(md, caddr_t); | |
746 | rem = md->m_len; | |
747 | } | |
748 | if (*cp == '\0' || *cp == '/') | |
749 | return (EINVAL); | |
750 | if (*cp & 0200) | |
751 | if ((*cp&0377) == ('/'|0200) || flag != DELETE) | |
752 | return (EINVAL); | |
753 | ndp->ni_dent.d_name[i++] = *cp; | |
754 | ndp->ni_hash += (unsigned char)*cp * i; | |
755 | cp++; | |
756 | rem--; | |
757 | } | |
758 | *mdp = md; | |
759 | len = nfsm_rndup(len)-len; | |
760 | if (len > 0) | |
761 | *dposp = cp+len; | |
762 | else | |
763 | *dposp = cp; | |
764 | ndp->ni_namelen = i; | |
765 | ndp->ni_dent.d_namlen = i; | |
766 | ndp->ni_dent.d_name[i] = '\0'; | |
36c3043b | 767 | ndp->ni_pathlen = 1; |
180c0ba3 KM |
768 | ndp->ni_dirp = ndp->ni_ptr = &ndp->ni_dent.d_name[0]; |
769 | ndp->ni_next = &ndp->ni_dent.d_name[i]; | |
770 | ndp->ni_loopcnt = 0; /* Not actually used for now */ | |
771 | ndp->ni_endoff = 0; | |
772 | if (docache) | |
773 | ndp->ni_makeentry = 1; | |
774 | else | |
775 | ndp->ni_makeentry = 0; | |
776 | ndp->ni_isdotdot = (i == 2 && | |
777 | ndp->ni_dent.d_name[1] == '.' && ndp->ni_dent.d_name[0] == '.'); | |
778 | ||
180c0ba3 KM |
779 | if (error = nfsrv_fhtovp(fhp, TRUE, &dp, ndp->ni_cred)) |
780 | return (error); | |
36c3043b KM |
781 | if (dp->v_type != VDIR) { |
782 | vput(dp); | |
783 | return (ENOTDIR); | |
784 | } | |
ffe6f482 KM |
785 | /* |
786 | * Must set current directory here to avoid confusion in namei() | |
787 | * called from rename() | |
788 | */ | |
36c3043b KM |
789 | ndp->ni_cdir = dp; |
790 | ndp->ni_rdir = (struct vnode *)0; | |
180c0ba3 KM |
791 | |
792 | /* | |
36c3043b KM |
793 | * Handle "..": |
794 | * If this vnode is the root of the mounted | |
795 | * file system, then ignore it so can't get out | |
180c0ba3 | 796 | */ |
36c3043b KM |
797 | if (ndp->ni_isdotdot && (dp->v_flag & VROOT)) { |
798 | ndp->ni_dvp = dp; | |
799 | ndp->ni_vp = dp; | |
800 | VREF(dp); | |
801 | goto nextname; | |
180c0ba3 KM |
802 | } |
803 | ||
804 | /* | |
805 | * We now have a segment name to search for, and a directory to search. | |
806 | */ | |
807 | if (error = VOP_LOOKUP(dp, ndp)) { | |
808 | if (ndp->ni_vp != NULL) | |
809 | panic("leaf should be empty"); | |
810 | /* | |
811 | * If creating and at end of pathname, then can consider | |
812 | * allowing file to be created. | |
813 | */ | |
814 | if (ndp->ni_dvp->v_mount->m_flag & (M_RDONLY | M_EXRDONLY)) | |
815 | error = EROFS; | |
816 | if (flag == LOOKUP || flag == DELETE || error != ENOENT) | |
817 | goto bad; | |
818 | /* | |
819 | * We return with ni_vp NULL to indicate that the entry | |
820 | * doesn't currently exist, leaving a pointer to the | |
821 | * (possibly locked) directory inode in ndp->ni_dvp. | |
822 | */ | |
823 | return (0); /* should this be ENOENT? */ | |
824 | } | |
825 | ||
180c0ba3 | 826 | dp = ndp->ni_vp; |
180c0ba3 KM |
827 | |
828 | nextname: | |
36c3043b | 829 | ndp->ni_ptr = ndp->ni_next; |
180c0ba3 | 830 | /* |
36c3043b | 831 | * Check for read-only file systems |
180c0ba3 | 832 | */ |
746ef028 KM |
833 | if (flag == DELETE || flag == RENAME) { |
834 | /* | |
835 | * Disallow directory write attempts on read-only | |
836 | * file systems. | |
837 | */ | |
838 | if ((dp->v_mount->m_flag & (M_RDONLY|M_EXRDONLY)) || | |
36c3043b | 839 | (wantparent && (ndp->ni_dvp->v_mount->m_flag & (M_RDONLY|M_EXRDONLY)))) { |
746ef028 KM |
840 | error = EROFS; |
841 | goto bad2; | |
842 | } | |
843 | } | |
180c0ba3 | 844 | |
180c0ba3 KM |
845 | if (!wantparent) |
846 | vrele(ndp->ni_dvp); | |
180c0ba3 KM |
847 | |
848 | if ((ndp->ni_nameiop & LOCKLEAF) == 0) | |
849 | VOP_UNLOCK(dp); | |
850 | return (0); | |
851 | ||
852 | bad2: | |
853 | if (lockparent) | |
854 | VOP_UNLOCK(ndp->ni_dvp); | |
855 | vrele(ndp->ni_dvp); | |
856 | bad: | |
857 | vput(dp); | |
858 | ndp->ni_vp = NULL; | |
859 | return (error); | |
860 | } | |
861 | ||
862 | /* | |
863 | * A fiddled version of m_adj() that ensures null fill to a long | |
864 | * boundary and only trims off the back end | |
865 | */ | |
866 | nfsm_adj(mp, len, nul) | |
867 | struct mbuf *mp; | |
868 | register int len; | |
869 | int nul; | |
870 | { | |
871 | register struct mbuf *m; | |
872 | register int count, i; | |
873 | register char *cp; | |
874 | ||
875 | /* | |
876 | * Trim from tail. Scan the mbuf chain, | |
877 | * calculating its length and finding the last mbuf. | |
878 | * If the adjustment only affects this mbuf, then just | |
879 | * adjust and return. Otherwise, rescan and truncate | |
880 | * after the remaining size. | |
881 | */ | |
882 | count = 0; | |
883 | m = mp; | |
884 | for (;;) { | |
885 | count += m->m_len; | |
886 | if (m->m_next == (struct mbuf *)0) | |
887 | break; | |
888 | m = m->m_next; | |
889 | } | |
1f9b0aa5 | 890 | if (m->m_len > len) { |
180c0ba3 KM |
891 | m->m_len -= len; |
892 | if (nul > 0) { | |
893 | cp = mtod(m, caddr_t)+m->m_len-nul; | |
894 | for (i = 0; i < nul; i++) | |
895 | *cp++ = '\0'; | |
896 | } | |
897 | return; | |
898 | } | |
899 | count -= len; | |
900 | if (count < 0) | |
901 | count = 0; | |
902 | /* | |
903 | * Correct length for chain is "count". | |
904 | * Find the mbuf with last data, adjust its length, | |
905 | * and toss data from remaining mbufs on chain. | |
906 | */ | |
907 | for (m = mp; m; m = m->m_next) { | |
908 | if (m->m_len >= count) { | |
909 | m->m_len = count; | |
910 | if (nul > 0) { | |
911 | cp = mtod(m, caddr_t)+m->m_len-nul; | |
912 | for (i = 0; i < nul; i++) | |
913 | *cp++ = '\0'; | |
914 | } | |
915 | break; | |
916 | } | |
917 | count -= m->m_len; | |
918 | } | |
919 | while (m = m->m_next) | |
920 | m->m_len = 0; | |
921 | } | |
922 | ||
923 | /* | |
924 | * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) | |
925 | * - look up fsid in mount list (if not found ret error) | |
926 | * - check that it is exported | |
927 | * - get vp by calling VFS_FHTOVP() macro | |
928 | * - if not lockflag unlock it with VOP_UNLOCK() | |
929 | * - if cred->cr_uid == 0 set it to m_exroot | |
930 | */ | |
931 | nfsrv_fhtovp(fhp, lockflag, vpp, cred) | |
932 | fhandle_t *fhp; | |
933 | int lockflag; | |
934 | struct vnode **vpp; | |
935 | struct ucred *cred; | |
936 | { | |
937 | register struct mount *mp; | |
938 | int error; | |
939 | ||
940 | if ((mp = getvfs(&fhp->fh_fsid)) == NULL) | |
941 | return (ESTALE); | |
942 | if ((mp->m_flag & M_EXPORTED) == 0) | |
943 | return (EACCES); | |
944 | if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) | |
945 | return (ESTALE); | |
946 | if (cred->cr_uid == 0) | |
947 | cred->cr_uid = mp->m_exroot; | |
948 | if (!lockflag) | |
949 | VOP_UNLOCK(*vpp); | |
950 | return (0); | |
951 | } |