add support for fifo's
[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 *
23ec03dc 20 * @(#)nfs_subs.c 7.18 (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;
64extern enum vtype v_type[NFLNK+1];
ffe6f482 65extern struct proc *nfs_iodwant[MAX_ASYNCDAEMON];
9238aa59 66extern struct map nfsmap[NFS_MSIZ];
180c0ba3
KM
67
68/* Function ret types */
69static char *nfs_unixauth();
70
7a398e6f
KM
71/*
72 * Maximum number of groups passed through to NFS server.
73 * For release 3.X systems, the maximum value is 8.
74 * For release 4.X systems, the maximum value is 10.
75 */
76int numgrps = 8;
77
180c0ba3
KM
78/*
79 * Create the header for an rpc request packet
80 * The function nfs_unixauth() creates a unix style authorization string
81 * and returns a ptr to it.
82 * The hsiz is the size of the rest of the nfs request header.
83 * (just used to decide if a cluster is a good idea)
0bd503ad 84 * nb: Note that the prog, vers and procid args are already in xdr byte order
180c0ba3 85 */
0bd503ad 86struct mbuf *nfsm_reqh(prog, vers, procid, cred, hsiz, bpos, mb, retxid)
180c0ba3
KM
87 u_long prog;
88 u_long vers;
0bd503ad 89 u_long procid;
180c0ba3
KM
90 struct ucred *cred;
91 int hsiz;
92 caddr_t *bpos;
93 struct mbuf **mb;
94 u_long *retxid;
95{
96 register struct mbuf *mreq, *m;
97 register u_long *p;
98 struct mbuf *m1;
99 char *ap;
100 int asiz, siz;
101
102 NFSMGETHDR(mreq);
7a398e6f 103 asiz = (((cred->cr_ngroups > numgrps) ? numgrps : cred->cr_ngroups)<<2);
36c3043b 104#ifdef FILLINHOST
180c0ba3 105 asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED);
36c3043b
KM
106#else
107 asiz += 9*NFSX_UNSIGNED;
108#endif
180c0ba3
KM
109
110 /* If we need a lot, alloc a cluster ?? */
111 if ((asiz+hsiz+RPC_SIZ) > MHLEN)
112 NFSMCLGET(mreq, M_WAIT);
113 mreq->m_len = NFSMSIZ(mreq);
114 siz = mreq->m_len;
115 m1 = mreq;
116 /*
117 * Alloc enough mbufs
118 * We do it now to avoid all sleeps after the call to nfs_unixauth()
119 */
120 while ((asiz+RPC_SIZ) > siz) {
121 MGET(m, M_WAIT, MT_DATA);
122 m1->m_next = m;
123 m->m_len = MLEN;
124 siz += MLEN;
125 m1 = m;
126 }
127 p = mtod(mreq, u_long *);
128 *p++ = *retxid = txdr_unsigned(++nfs_xid);
129 *p++ = rpc_call;
130 *p++ = rpc_vers;
131 *p++ = prog;
132 *p++ = vers;
0bd503ad 133 *p++ = procid;
180c0ba3
KM
134
135 /* Now we can call nfs_unixauth() and copy it in */
136 ap = nfs_unixauth(cred);
137 m = mreq;
138 siz = m->m_len-RPC_SIZ;
139 if (asiz <= siz) {
140 bcopy(ap, (caddr_t)p, asiz);
141 m->m_len = asiz+RPC_SIZ;
142 } else {
143 bcopy(ap, (caddr_t)p, siz);
144 ap += siz;
145 asiz -= siz;
146 while (asiz > 0) {
147 siz = (asiz > MLEN) ? MLEN : asiz;
148 m = m->m_next;
149 bcopy(ap, mtod(m, caddr_t), siz);
150 m->m_len = siz;
151 asiz -= siz;
152 ap += siz;
153 }
154 }
155
156 /* Finally, return values */
157 *mb = m;
158 *bpos = mtod(m, caddr_t)+m->m_len;
159 return (mreq);
160}
161
162/*
163 * copies mbuf chain to the uio scatter/gather list
164 */
165nfsm_mbuftouio(mrep, uiop, siz, dpos)
166 struct mbuf **mrep;
167 struct uio *uiop;
168 int siz;
169 caddr_t *dpos;
170{
171 register int xfer, left, len;
172 register struct mbuf *mp;
173 register char *mbufcp, *uiocp;
174 long uiosiz, rem;
175
176 mp = *mrep;
177 mbufcp = *dpos;
178 len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
179 rem = nfsm_rndup(siz)-siz;
180 while (siz > 0) {
181 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
182 return(EFBIG);
183 left = uiop->uio_iov->iov_len;
184 uiocp = uiop->uio_iov->iov_base;
185 if (left > siz)
186 left = siz;
187 uiosiz = left;
188 while (left > 0) {
189 while (len == 0) {
190 mp = mp->m_next;
191 if (mp == NULL)
192 return (EBADRPC);
193 mbufcp = mtod(mp, caddr_t);
194 len = mp->m_len;
195 }
196 xfer = (left > len) ? len : left;
197#ifdef notdef
198 /* Not Yet.. */
199 if (uiop->uio_iov->iov_op != NULL)
200 (*(uiop->uio_iov->iov_op))
201 (mbufcp, uiocp, xfer);
202 else
203#endif
204 if (uiop->uio_segflg == UIO_SYSSPACE)
205 bcopy(mbufcp, uiocp, xfer);
206 else
207 copyout(mbufcp, uiocp, xfer);
208 left -= xfer;
209 len -= xfer;
210 mbufcp += xfer;
211 uiocp += xfer;
24c658f0 212 uiop->uio_offset += xfer;
180c0ba3
KM
213 uiop->uio_resid -= xfer;
214 }
215 if (uiop->uio_iov->iov_len <= siz) {
216 uiop->uio_iovcnt--;
217 uiop->uio_iov++;
218 } else {
219 uiop->uio_iov->iov_base += uiosiz;
220 uiop->uio_iov->iov_len -= uiosiz;
221 }
222 siz -= uiosiz;
223 }
224 if (rem > 0)
225 mbufcp += rem;
226 *dpos = mbufcp;
227 *mrep = mp;
228 return(0);
229}
230
231/*
232 * copies a uio scatter/gather list to an mbuf chain...
233 */
234nfsm_uiotombuf(uiop, mq, siz, bpos)
235 register struct uio *uiop;
236 struct mbuf **mq;
237 int siz;
238 caddr_t *bpos;
239{
240 register struct mbuf *mp;
241 struct mbuf *mp2;
0bd503ad 242 long xfer, left, uiosiz;
180c0ba3
KM
243 int clflg;
244 int rem, len;
245 char *cp, *uiocp;
246
247 if (siz > MLEN) /* or should it >= MCLBYTES ?? */
248 clflg = 1;
249 else
250 clflg = 0;
251 rem = nfsm_rndup(siz)-siz;
252 mp2 = *mq;
253 while (siz > 0) {
254 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
255 return(EINVAL);
256 left = uiop->uio_iov->iov_len;
257 uiocp = uiop->uio_iov->iov_base;
258 if (left > siz)
259 left = siz;
260 uiosiz = left;
261 while (left > 0) {
262 MGET(mp, M_WAIT, MT_DATA);
263 if (clflg)
264 NFSMCLGET(mp, M_WAIT);
265 mp->m_len = NFSMSIZ(mp);
266 mp2->m_next = mp;
267 mp2 = mp;
268 xfer = (left > mp->m_len) ? mp->m_len : left;
269#ifdef notdef
270 /* Not Yet.. */
271 if (uiop->uio_iov->iov_op != NULL)
272 (*(uiop->uio_iov->iov_op))
273 (uiocp, mtod(mp, caddr_t), xfer);
274 else
275#endif
276 if (uiop->uio_segflg == UIO_SYSSPACE)
277 bcopy(uiocp, mtod(mp, caddr_t), xfer);
278 else
279 copyin(uiocp, mtod(mp, caddr_t), xfer);
280 len = mp->m_len;
281 mp->m_len = xfer;
282 left -= xfer;
283 uiocp += xfer;
24c658f0 284 uiop->uio_offset += xfer;
180c0ba3
KM
285 uiop->uio_resid -= xfer;
286 }
287 if (uiop->uio_iov->iov_len <= siz) {
288 uiop->uio_iovcnt--;
289 uiop->uio_iov++;
290 } else {
291 uiop->uio_iov->iov_base += uiosiz;
292 uiop->uio_iov->iov_len -= uiosiz;
293 }
294 siz -= uiosiz;
295 }
296 if (rem > 0) {
297 if (rem > (len-mp->m_len)) {
298 MGET(mp, M_WAIT, MT_DATA);
299 mp->m_len = 0;
300 mp2->m_next = mp;
301 }
302 cp = mtod(mp, caddr_t)+mp->m_len;
303 for (left = 0; left < rem; left++)
304 *cp++ = '\0';
305 mp->m_len += rem;
306 *bpos = cp;
307 } else
308 *bpos = mtod(mp, caddr_t)+mp->m_len;
309 *mq = mp;
310 return(0);
311}
312
313/*
314 * Help break down an mbuf chain by setting the first siz bytes contiguous
315 * pointed to by returned val.
316 * If Updateflg == True we can overwrite the first part of the mbuf data
317 * This is used by the macros nfsm_disect and nfsm_disecton for tough
318 * cases. (The macros use the vars. dpos and dpos2)
319 */
320nfsm_disct(mdp, dposp, siz, left, updateflg, cp2)
321 struct mbuf **mdp;
322 caddr_t *dposp;
323 int siz;
324 int left;
325 int updateflg;
326 caddr_t *cp2;
327{
328 register struct mbuf *mp, *mp2;
329 register int siz2, xfer;
330 register caddr_t p;
180c0ba3
KM
331
332 mp = *mdp;
333 while (left == 0) {
334 *mdp = mp = mp->m_next;
335 if (mp == NULL)
336 return(EBADRPC);
337 left = mp->m_len;
338 *dposp = mtod(mp, caddr_t);
339 }
340 if (left >= siz) {
341 *cp2 = *dposp;
342 *dposp += siz;
343 return(0);
344 } else if (mp->m_next == NULL) {
345 return(EBADRPC);
346 } else if (siz > MCLBYTES) {
347 panic("nfs S too big");
348 } else {
349 /* Iff update, you can overwrite, else must alloc new mbuf */
350 if (updateflg) {
351 NFSMINOFF(mp);
352 } else {
353 MGET(mp2, M_WAIT, MT_DATA);
354 mp2->m_next = mp->m_next;
355 mp->m_next = mp2;
356 mp->m_len -= left;
357 mp = mp2;
358 }
359 /* Alloc cluster iff we need it */
360 if (!M_HASCL(mp) && siz > NFSMSIZ(mp)) {
361 NFSMCLGET(mp, M_WAIT);
362 if (!M_HASCL(mp))
363 return(ENOBUFS);
364 }
365 *cp2 = p = mtod(mp, caddr_t);
366 bcopy(*dposp, p, left); /* Copy what was left */
367 siz2 = siz-left;
368 p += left;
369 mp2 = mp->m_next;
370 /* Loop arround copying up the siz2 bytes */
371 while (siz2 > 0) {
372 if (mp2 == NULL)
373 return (EBADRPC);
374 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
375 bcopy(mtod(mp2, caddr_t), p, xfer);
376 NFSMADV(mp2, xfer);
377 mp2->m_len -= xfer;
378 siz2 -= xfer;
379 if (siz2 > 0)
380 mp2 = mp2->m_next;
381 }
382 mp->m_len = siz;
383 *mdp = mp2;
384 *dposp = mtod(mp2, caddr_t);
180c0ba3 385 }
0bd503ad 386 return (0);
180c0ba3
KM
387}
388
389/*
390 * Advance the position in the mbuf chain with/without freeing mbufs
391 */
392nfs_adv(mdp, dposp, offs, left)
393 struct mbuf **mdp;
394 caddr_t *dposp;
395 int offs;
396 int left;
397{
398 register struct mbuf *m;
399 register int s;
400
401 m = *mdp;
402 s = left;
403 while (s < offs) {
404 offs -= s;
405 m = m->m_next;
406 if (m == NULL)
407 return(EBADRPC);
408 s = m->m_len;
409 }
410 *mdp = m;
411 *dposp = mtod(m, caddr_t)+offs;
412 return(0);
413}
414
415/*
416 * Copy a string into mbufs for the hard cases...
417 */
418nfsm_strtmbuf(mb, bpos, cp, siz)
419 struct mbuf **mb;
420 char **bpos;
421 char *cp;
422 long siz;
423{
424 register struct mbuf *m1, *m2;
425 long left, xfer, len, tlen;
426 u_long *p;
427 int putsize;
428
429 putsize = 1;
430 m2 = *mb;
431 left = NFSMSIZ(m2)-m2->m_len;
432 if (left > 0) {
433 p = ((u_long *)(*bpos));
434 *p++ = txdr_unsigned(siz);
435 putsize = 0;
436 left -= NFSX_UNSIGNED;
437 m2->m_len += NFSX_UNSIGNED;
438 if (left > 0) {
439 bcopy(cp, (caddr_t) p, left);
440 siz -= left;
441 cp += left;
442 m2->m_len += left;
443 left = 0;
444 }
445 }
446 /* Loop arround adding mbufs */
447 while (siz > 0) {
448 MGET(m1, M_WAIT, MT_DATA);
449 if (siz > MLEN)
450 NFSMCLGET(m1, M_WAIT);
451 m1->m_len = NFSMSIZ(m1);
452 m2->m_next = m1;
453 m2 = m1;
454 p = mtod(m1, u_long *);
455 tlen = 0;
456 if (putsize) {
457 *p++ = txdr_unsigned(siz);
458 m1->m_len -= NFSX_UNSIGNED;
459 tlen = NFSX_UNSIGNED;
460 putsize = 0;
461 }
462 if (siz < m1->m_len) {
463 len = nfsm_rndup(siz);
464 xfer = siz;
465 if (xfer < len)
466 *(p+(xfer>>2)) = 0;
467 } else {
468 xfer = len = m1->m_len;
469 }
470 bcopy(cp, (caddr_t) p, xfer);
471 m1->m_len = len+tlen;
472 siz -= xfer;
473 cp += xfer;
474 }
475 *mb = m1;
476 *bpos = mtod(m1, caddr_t)+m1->m_len;
477 return(0);
478}
479
480/*
481 * Called once to initialize data structures...
482 */
e16a8c9b 483nfs_init()
180c0ba3
KM
484{
485 register int i;
486
487 rpc_vers = txdr_unsigned(RPC_VER2);
488 rpc_call = txdr_unsigned(RPC_CALL);
489 rpc_reply = txdr_unsigned(RPC_REPLY);
490 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
491 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
492 rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
493 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
494 nfs_vers = txdr_unsigned(NFS_VER2);
495 nfs_prog = txdr_unsigned(NFS_PROG);
496 nfs_true = txdr_unsigned(TRUE);
497 nfs_false = txdr_unsigned(FALSE);
498 /* Loop thru nfs procids */
499 for (i = 0; i < NFS_NPROCS; i++)
500 nfs_procids[i] = txdr_unsigned(i);
ffe6f482
KM
501 /* Ensure async daemons disabled */
502 for (i = 0; i < MAX_ASYNCDAEMON; i++)
503 nfs_iodwant[i] = (struct proc *)0;
180c0ba3
KM
504 v_type[0] = VNON;
505 v_type[1] = VREG;
506 v_type[2] = VDIR;
507 v_type[3] = VBLK;
508 v_type[4] = VCHR;
509 v_type[5] = VLNK;
510 nfs_xdrneg1 = txdr_unsigned(-1);
511 nfs_nhinit(); /* Init the nfsnode table */
e8540f59 512 nfsrv_initcache(); /* Init the server request cache */
9238aa59 513 rminit(nfsmap, (long)NFS_MAPREG, (long)1, "nfs mapreg", NFS_MSIZ);
180c0ba3
KM
514 /* And start timer */
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);
563 return(rpc_unixauth);
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
KM
595 enum vtype type;
596 dev_t rdev;
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
KM
606 type = nfstov_type(fp->fa_type);
607 rdev = fxdr_unsigned(dev_t, fp->fa_rdev);
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
KM
617 if (vp->v_type == VNON) {
618 vp->v_type = type;
619 if (vp->v_type == VCHR || vp->v_type == VBLK) {
e16a8c9b 620 vp->v_op = &spec_nfsv2nodeops;
43fc727e 621 if (nvp = checkalias(vp, rdev, vp->v_mount)) {
e16a8c9b
KM
622 /*
623 * Reinitialize aliased node.
624 */
625 np = VTONFS(nvp);
626 np->n_vnode = nvp;
a8ddf3cc
KM
627 np->n_flag = 0;
628 nfs_lock(nvp);
e16a8c9b
KM
629 bcopy((caddr_t)&VTONFS(vp)->n_fh,
630 (caddr_t)&np->n_fh, NFSX_FH);
631 insque(np, nfs_hash(&np->n_fh));
632 np->n_attrstamp = 0;
633 np->n_sillyrename = (struct sillyrename *)0;
634 /*
610357c6 635 * Discard unneeded vnode and update actual one
e16a8c9b
KM
636 */
637 vput(vp);
610357c6 638 *vpp = nvp;
e16a8c9b
KM
639 }
640 }
641 np->n_mtime = mtime.tv_sec;
642 }
180c0ba3 643 vap = &np->n_vattr;
e16a8c9b 644 vap->va_type = type;
9238aa59
RM
645 vap->va_mode = nfstov_mode(fp->fa_mode);
646 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
647 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
648 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
649 vap->va_size = fxdr_unsigned(u_long, fp->fa_size);
650 if ((np->n_flag & NMODIFIED) == 0 || vap->va_size > np->n_size)
651 np->n_size = vap->va_size;
180c0ba3 652 vap->va_size1 = 0; /* OR -1 ?? */
9238aa59 653 vap->va_blocksize = fxdr_unsigned(long, fp->fa_blocksize);
e16a8c9b 654 vap->va_rdev = rdev;
9238aa59
RM
655 vap->va_bytes = fxdr_unsigned(long, fp->fa_blocks) * vap->va_blocksize;
656 vap->va_bytes1 = 0;
e8540f59 657 vap->va_fsid = vp->v_mount->m_fsid.val[0];
9238aa59 658 vap->va_fileid = fxdr_unsigned(long, fp->fa_fileid);
e8540f59
KM
659 vap->va_atime.tv_sec = fxdr_unsigned(long, fp->fa_atime.tv_sec);
660 vap->va_atime.tv_usec = 0;
661 vap->va_flags = fxdr_unsigned(u_long, fp->fa_atime.tv_usec);
e16a8c9b 662 vap->va_mtime = mtime;
e8540f59
KM
663 vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa_ctime.tv_sec);
664 vap->va_ctime.tv_usec = 0;
665 vap->va_gen = fxdr_unsigned(u_long, fp->fa_ctime.tv_usec);
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 */
682nfs_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 */
707nfs_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;
180c0ba3
KM
718 int flag;
719 int docache;
720 int wantparent;
721 int lockparent;
180c0ba3
KM
722 int error = 0;
723
724 ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0;
725 flag = ndp->ni_nameiop & OPFLAG;
726 wantparent = ndp->ni_nameiop & (LOCKPARENT | WANTPARENT);
727 lockparent = ndp->ni_nameiop & LOCKPARENT;
728 docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE;
729 if (flag == DELETE || wantparent)
730 docache = 0;
731
732 /* Fill in the nameidata and call lookup */
733 cp = *dposp;
734 md = *mdp;
735 rem = mtod(md, caddr_t)+md->m_len-cp;
736 ndp->ni_hash = 0;
737 for (i = 0; i < len;) {
738 if (rem == 0) {
739 md = md->m_next;
740 if (md == NULL)
741 return (EBADRPC);
742 cp = mtod(md, caddr_t);
743 rem = md->m_len;
744 }
745 if (*cp == '\0' || *cp == '/')
746 return (EINVAL);
747 if (*cp & 0200)
748 if ((*cp&0377) == ('/'|0200) || flag != DELETE)
749 return (EINVAL);
750 ndp->ni_dent.d_name[i++] = *cp;
751 ndp->ni_hash += (unsigned char)*cp * i;
752 cp++;
753 rem--;
754 }
755 *mdp = md;
756 len = nfsm_rndup(len)-len;
757 if (len > 0)
758 *dposp = cp+len;
759 else
760 *dposp = cp;
761 ndp->ni_namelen = i;
762 ndp->ni_dent.d_namlen = i;
763 ndp->ni_dent.d_name[i] = '\0';
36c3043b 764 ndp->ni_pathlen = 1;
180c0ba3
KM
765 ndp->ni_dirp = ndp->ni_ptr = &ndp->ni_dent.d_name[0];
766 ndp->ni_next = &ndp->ni_dent.d_name[i];
767 ndp->ni_loopcnt = 0; /* Not actually used for now */
768 ndp->ni_endoff = 0;
769 if (docache)
770 ndp->ni_makeentry = 1;
771 else
772 ndp->ni_makeentry = 0;
773 ndp->ni_isdotdot = (i == 2 &&
774 ndp->ni_dent.d_name[1] == '.' && ndp->ni_dent.d_name[0] == '.');
775
180c0ba3
KM
776 if (error = nfsrv_fhtovp(fhp, TRUE, &dp, ndp->ni_cred))
777 return (error);
36c3043b
KM
778 if (dp->v_type != VDIR) {
779 vput(dp);
780 return (ENOTDIR);
781 }
ffe6f482
KM
782 /*
783 * Must set current directory here to avoid confusion in namei()
784 * called from rename()
785 */
36c3043b
KM
786 ndp->ni_cdir = dp;
787 ndp->ni_rdir = (struct vnode *)0;
180c0ba3
KM
788
789 /*
36c3043b
KM
790 * Handle "..":
791 * If this vnode is the root of the mounted
792 * file system, then ignore it so can't get out
180c0ba3 793 */
36c3043b
KM
794 if (ndp->ni_isdotdot && (dp->v_flag & VROOT)) {
795 ndp->ni_dvp = dp;
796 ndp->ni_vp = dp;
797 VREF(dp);
798 goto nextname;
180c0ba3
KM
799 }
800
801 /*
802 * We now have a segment name to search for, and a directory to search.
803 */
804 if (error = VOP_LOOKUP(dp, ndp)) {
805 if (ndp->ni_vp != NULL)
806 panic("leaf should be empty");
807 /*
808 * If creating and at end of pathname, then can consider
809 * allowing file to be created.
810 */
811 if (ndp->ni_dvp->v_mount->m_flag & (M_RDONLY | M_EXRDONLY))
812 error = EROFS;
813 if (flag == LOOKUP || flag == DELETE || error != ENOENT)
814 goto bad;
815 /*
816 * We return with ni_vp NULL to indicate that the entry
817 * doesn't currently exist, leaving a pointer to the
818 * (possibly locked) directory inode in ndp->ni_dvp.
819 */
820 return (0); /* should this be ENOENT? */
821 }
822
180c0ba3 823 dp = ndp->ni_vp;
180c0ba3
KM
824
825nextname:
36c3043b 826 ndp->ni_ptr = ndp->ni_next;
180c0ba3 827 /*
36c3043b 828 * Check for read-only file systems
180c0ba3 829 */
746ef028
KM
830 if (flag == DELETE || flag == RENAME) {
831 /*
832 * Disallow directory write attempts on read-only
833 * file systems.
834 */
835 if ((dp->v_mount->m_flag & (M_RDONLY|M_EXRDONLY)) ||
36c3043b 836 (wantparent && (ndp->ni_dvp->v_mount->m_flag & (M_RDONLY|M_EXRDONLY)))) {
746ef028
KM
837 error = EROFS;
838 goto bad2;
839 }
840 }
180c0ba3 841
180c0ba3
KM
842 if (!wantparent)
843 vrele(ndp->ni_dvp);
180c0ba3
KM
844
845 if ((ndp->ni_nameiop & LOCKLEAF) == 0)
846 VOP_UNLOCK(dp);
847 return (0);
848
849bad2:
850 if (lockparent)
851 VOP_UNLOCK(ndp->ni_dvp);
852 vrele(ndp->ni_dvp);
853bad:
854 vput(dp);
855 ndp->ni_vp = NULL;
856 return (error);
857}
858
859/*
860 * A fiddled version of m_adj() that ensures null fill to a long
861 * boundary and only trims off the back end
862 */
863nfsm_adj(mp, len, nul)
864 struct mbuf *mp;
865 register int len;
866 int nul;
867{
868 register struct mbuf *m;
869 register int count, i;
870 register char *cp;
871
872 /*
873 * Trim from tail. Scan the mbuf chain,
874 * calculating its length and finding the last mbuf.
875 * If the adjustment only affects this mbuf, then just
876 * adjust and return. Otherwise, rescan and truncate
877 * after the remaining size.
878 */
879 count = 0;
880 m = mp;
881 for (;;) {
882 count += m->m_len;
883 if (m->m_next == (struct mbuf *)0)
884 break;
885 m = m->m_next;
886 }
1f9b0aa5 887 if (m->m_len > len) {
180c0ba3
KM
888 m->m_len -= len;
889 if (nul > 0) {
890 cp = mtod(m, caddr_t)+m->m_len-nul;
891 for (i = 0; i < nul; i++)
892 *cp++ = '\0';
893 }
894 return;
895 }
896 count -= len;
897 if (count < 0)
898 count = 0;
899 /*
900 * Correct length for chain is "count".
901 * Find the mbuf with last data, adjust its length,
902 * and toss data from remaining mbufs on chain.
903 */
904 for (m = mp; m; m = m->m_next) {
905 if (m->m_len >= count) {
906 m->m_len = count;
907 if (nul > 0) {
908 cp = mtod(m, caddr_t)+m->m_len-nul;
909 for (i = 0; i < nul; i++)
910 *cp++ = '\0';
911 }
912 break;
913 }
914 count -= m->m_len;
915 }
916 while (m = m->m_next)
917 m->m_len = 0;
918}
919
920/*
921 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
922 * - look up fsid in mount list (if not found ret error)
923 * - check that it is exported
924 * - get vp by calling VFS_FHTOVP() macro
925 * - if not lockflag unlock it with VOP_UNLOCK()
926 * - if cred->cr_uid == 0 set it to m_exroot
927 */
928nfsrv_fhtovp(fhp, lockflag, vpp, cred)
929 fhandle_t *fhp;
930 int lockflag;
931 struct vnode **vpp;
932 struct ucred *cred;
933{
934 register struct mount *mp;
180c0ba3
KM
935
936 if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
937 return (ESTALE);
938 if ((mp->m_flag & M_EXPORTED) == 0)
939 return (EACCES);
940 if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp))
941 return (ESTALE);
942 if (cred->cr_uid == 0)
943 cred->cr_uid = mp->m_exroot;
944 if (!lockflag)
945 VOP_UNLOCK(*vpp);
946 return (0);
947}