reset optind before getopt() -- fixes 'make -k clean' failure
[unix-history] / usr / src / sys / nfs / nfs_subs.c
CommitLineData
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 */
54u_long nfs_procids[NFS_NPROCS];
55u_long nfs_xdrneg1;
56u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied,
57 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted;
58u_long nfs_vers, nfs_prog, nfs_true, nfs_false;
59/* And other global data */
60static u_long *rpc_uidp = (u_long *)0;
61static u_long nfs_xid = 1;
62static char *rpc_unixauth;
63extern long hostid;
d4e5799e 64enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON };
f0f1cbaa 65extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
9238aa59 66extern struct map nfsmap[NFS_MSIZ];
f0f1cbaa 67extern struct nfsreq nfsreqh;
180c0ba3
KM
68
69/* Function ret types */
70static 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 */
78int 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 88struct 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 */
167nfsm_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 */
241nfsm_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 */
326nfsm_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 */
394nfs_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 */
420nfsm_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 485nfs_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 */
521static 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
580nfs_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 */
693nfs_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 */
717nfs_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 */
805nfsm_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 */
870nfsrv_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}