add proc pointers to appropriate vnode operations
[unix-history] / usr / src / sys / nfs / nfs_serv.c
CommitLineData
971b93e3
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 *
dbf0c423 8 * %sccs.include.redist.c%
971b93e3 9 *
058dee65 10 * @(#)nfs_serv.c 7.36 (Berkeley) %G%
971b93e3
KM
11 */
12
13/*
14 * nfs version 2 server calls to vnode ops
15 * - these routines generally have 3 phases
16 * 1 - break down and validate rpc request in mbuf list
17 * 2 - do the vnode ops for the request
36c3043b 18 * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
971b93e3
KM
19 * 3 - build the rpc reply in an mbuf list
20 * nb:
21 * - do not mix the phases, since the nfsm_?? macros can return failures
f0f1cbaa 22 * on a bad rpc or similar and do not do any vrele() or vput()'s
971b93e3 23 *
36c3043b 24 * - the nfsm_reply() macro generates an nfs rpc reply with the nfs
971b93e3 25 * error number iff error != 0 whereas
f0f1cbaa
KM
26 * returning an error from the server function implies a fatal error
27 * such as a badly constructed rpc request that should be dropped without
28 * a reply.
971b93e3
KM
29 */
30
971b93e3 31#include "param.h"
e587d97d 32#include "file.h"
971b93e3 33#include "vnode.h"
e587d97d
KM
34#include "mount.h"
35#include "mbuf.h"
058dee65 36
d4e5799e
KM
37#include "../ufs/quota.h"
38#include "../ufs/inode.h"
058dee65 39
971b93e3
KM
40#include "nfsv2.h"
41#include "nfs.h"
42#include "xdr_subs.h"
43#include "nfsm_subs.h"
44
45/* Defs */
36c3043b
KM
46#define TRUE 1
47#define FALSE 0
971b93e3
KM
48
49/* Global vars */
50extern u_long nfs_procids[NFS_NPROCS];
51extern u_long nfs_xdrneg1;
52extern u_long nfs_false, nfs_true;
d4e5799e
KM
53nfstype nfs_type[9]={ NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
54 NFCHR, NFNON };
971b93e3
KM
55
56/*
57 * nfs getattr service
58 */
e8540f59 59nfsrv_getattr(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
60 struct mbuf **mrq;
61 struct mbuf *mrep, *md;
62 caddr_t dpos;
63 struct ucred *cred;
64 u_long xid;
e8540f59 65 int *repstat;
971b93e3 66{
9238aa59 67 register struct nfsv2_fattr *fp;
971b93e3
KM
68 struct vattr va;
69 register struct vattr *vap = &va;
70 struct vnode *vp;
71 nfsv2fh_t nfh;
72 fhandle_t *fhp;
0bd503ad
KM
73 register u_long *p;
74 register long t1;
75 caddr_t bpos;
76 int error = 0;
77 char *cp2;
e8540f59 78 struct mbuf *mb, *mb2, *mreq;
971b93e3
KM
79
80 fhp = &nfh.fh_generic;
81 nfsm_srvmtofh(fhp);
82 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
83 nfsm_reply(0);
84 error = VOP_GETATTR(vp, vap, cred);
85 vput(vp);
86 nfsm_reply(NFSX_FATTR);
9238aa59 87 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
e8540f59 88 nfsm_srvfillattr;
971b93e3
KM
89 nfsm_srvdone;
90}
91
92/*
93 * nfs setattr service
94 */
e8540f59 95nfsrv_setattr(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
96 struct mbuf **mrq;
97 struct mbuf *mrep, *md;
98 caddr_t dpos;
99 struct ucred *cred;
100 u_long xid;
e8540f59 101 int *repstat;
971b93e3
KM
102{
103 struct vattr va;
104 register struct vattr *vap = &va;
9238aa59
RM
105 register struct nfsv2_sattr *sp;
106 register struct nfsv2_fattr *fp;
971b93e3
KM
107 struct vnode *vp;
108 nfsv2fh_t nfh;
109 fhandle_t *fhp;
0bd503ad
KM
110 register u_long *p;
111 register long t1;
112 caddr_t bpos;
113 int error = 0;
114 char *cp2;
e8540f59 115 struct mbuf *mb, *mb2, *mreq;
971b93e3
KM
116
117 fhp = &nfh.fh_generic;
118 nfsm_srvmtofh(fhp);
9238aa59 119 nfsm_disect(sp, struct nfsv2_sattr *, NFSX_SATTR);
971b93e3
KM
120 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
121 nfsm_reply(0);
24ed1a73 122 if (error = nfsrv_access(vp, VWRITE, cred))
971b93e3 123 goto out;
3ee1461b 124 VATTR_NULL(vap);
971b93e3
KM
125 /*
126 * Nah nah nah nah na nah
127 * There is a bug in the Sun client that puts 0xffff in the mode
128 * field of sattr when it should put in 0xffffffff. The u_short
129 * doesn't sign extend.
130 * --> check the low order 2 bytes for 0xffff
131 */
9238aa59
RM
132 if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
133 vap->va_mode = nfstov_mode(sp->sa_mode);
134 if (sp->sa_uid != nfs_xdrneg1)
135 vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
136 if (sp->sa_gid != nfs_xdrneg1)
137 vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
e8540f59 138 if (sp->sa_size != nfs_xdrneg1)
9238aa59 139 vap->va_size = fxdr_unsigned(u_long, sp->sa_size);
e8540f59
KM
140 /*
141 * The usec field of sa_atime is overloaded with the va_flags field
142 * for 4.4BSD clients. Hopefully other clients always set both the
143 * sec and usec fields to -1 when not setting the atime.
144 */
145 if (sp->sa_atime.tv_sec != nfs_xdrneg1) {
146 vap->va_atime.tv_sec = fxdr_unsigned(long, sp->sa_atime.tv_sec);
147 vap->va_atime.tv_usec = 0;
36c3043b 148 }
e8540f59
KM
149 if (sp->sa_atime.tv_usec != nfs_xdrneg1)
150 vap->va_flags = fxdr_unsigned(u_long, sp->sa_atime.tv_usec);
9238aa59
RM
151 if (sp->sa_mtime.tv_sec != nfs_xdrneg1)
152 fxdr_time(&sp->sa_mtime, &vap->va_mtime);
971b93e3
KM
153 if (error = VOP_SETATTR(vp, vap, cred)) {
154 vput(vp);
155 nfsm_reply(0);
156 }
157 error = VOP_GETATTR(vp, vap, cred);
158out:
159 vput(vp);
160 nfsm_reply(NFSX_FATTR);
9238aa59 161 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
e8540f59 162 nfsm_srvfillattr;
971b93e3
KM
163 nfsm_srvdone;
164}
165
166/*
167 * nfs lookup rpc
168 */
e8540f59 169nfsrv_lookup(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
170 struct mbuf **mrq;
171 struct mbuf *mrep, *md;
172 caddr_t dpos;
173 struct ucred *cred;
174 u_long xid;
e8540f59 175 int *repstat;
971b93e3 176{
9238aa59 177 register struct nfsv2_fattr *fp;
ffe6f482
KM
178 struct nameidata nami;
179 register struct nameidata *ndp = &nami;
971b93e3
KM
180 struct vnode *vp;
181 nfsv2fh_t nfh;
182 fhandle_t *fhp;
0bd503ad
KM
183 register caddr_t cp;
184 register u_long *p;
185 register long t1;
186 caddr_t bpos;
187 int error = 0;
188 char *cp2;
e8540f59 189 struct mbuf *mb, *mb2, *mreq;
971b93e3
KM
190 long len;
191 struct vattr va, *vap = &va;
192
ffe6f482 193 ndinit(ndp);
971b93e3
KM
194 fhp = &nfh.fh_generic;
195 nfsm_srvmtofh(fhp);
196 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
197 ndp->ni_cred = cred;
198 ndp->ni_nameiop = LOOKUP | LOCKLEAF;
971b93e3
KM
199 if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
200 nfsm_reply(0);
201 vp = ndp->ni_vp;
202 bzero((caddr_t)fhp, sizeof(nfh));
54fb9dc2 203 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
971b93e3
KM
204 if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
205 vput(vp);
206 nfsm_reply(0);
207 }
208 error = VOP_GETATTR(vp, vap, cred);
209 vput(vp);
210 nfsm_reply(NFSX_FH+NFSX_FATTR);
211 nfsm_srvfhtom(fhp);
9238aa59 212 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
e8540f59 213 nfsm_srvfillattr;
971b93e3
KM
214 nfsm_srvdone;
215}
216
217/*
218 * nfs readlink service
219 */
e8540f59 220nfsrv_readlink(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
221 struct mbuf **mrq;
222 struct mbuf *mrep, *md;
223 caddr_t dpos;
224 struct ucred *cred;
e8540f59
KM
225 u_long xid;
226 int *repstat;
971b93e3 227{
f0f1cbaa 228 struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
971b93e3
KM
229 register struct iovec *ivp = iv;
230 register struct mbuf *mp;
0bd503ad
KM
231 register u_long *p;
232 register long t1;
233 caddr_t bpos;
234 int error = 0;
235 char *cp2;
e8540f59 236 struct mbuf *mb, *mb2, *mp2, *mp3, *mreq;
971b93e3
KM
237 struct vnode *vp;
238 nfsv2fh_t nfh;
239 fhandle_t *fhp;
240 struct uio io, *uiop = &io;
241 int i, tlen, len;
242
243 fhp = &nfh.fh_generic;
244 nfsm_srvmtofh(fhp);
245 len = 0;
246 i = 0;
247 while (len < NFS_MAXPATHLEN) {
248 MGET(mp, M_WAIT, MT_DATA);
f0f1cbaa 249 MCLGET(mp, M_WAIT);
971b93e3
KM
250 mp->m_len = NFSMSIZ(mp);
251 if (len == 0)
252 mp3 = mp2 = mp;
f0f1cbaa 253 else {
971b93e3 254 mp2->m_next = mp;
f0f1cbaa
KM
255 mp2 = mp;
256 }
971b93e3
KM
257 if ((len+mp->m_len) > NFS_MAXPATHLEN) {
258 mp->m_len = NFS_MAXPATHLEN-len;
259 len = NFS_MAXPATHLEN;
260 } else
261 len += mp->m_len;
262 ivp->iov_base = mtod(mp, caddr_t);
263 ivp->iov_len = mp->m_len;
264 i++;
265 ivp++;
266 }
267 uiop->uio_iov = iv;
268 uiop->uio_iovcnt = i;
269 uiop->uio_offset = 0;
270 uiop->uio_resid = len;
271 uiop->uio_rw = UIO_READ;
272 uiop->uio_segflg = UIO_SYSSPACE;
273 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) {
274 m_freem(mp3);
275 nfsm_reply(0);
276 }
277 if (vp->v_type != VLNK) {
278 error = EINVAL;
279 goto out;
280 }
281 error = VOP_READLINK(vp, uiop, cred);
282out:
283 vput(vp);
284 if (error)
285 m_freem(mp3);
286 nfsm_reply(NFSX_UNSIGNED);
287 if (uiop->uio_resid > 0) {
288 len -= uiop->uio_resid;
289 tlen = nfsm_rndup(len);
290 nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
291 }
292 nfsm_build(p, u_long *, NFSX_UNSIGNED);
293 *p = txdr_unsigned(len);
294 mb->m_next = mp3;
295 nfsm_srvdone;
296}
297
298/*
299 * nfs read service
300 */
e8540f59 301nfsrv_read(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
302 struct mbuf **mrq;
303 struct mbuf *mrep, *md;
304 caddr_t dpos;
305 struct ucred *cred;
306 u_long xid;
e8540f59 307 int *repstat;
971b93e3 308{
170bfd05
KM
309 register struct iovec *iv;
310 struct iovec *iv2;
f0f1cbaa 311 register struct mbuf *m;
9238aa59 312 register struct nfsv2_fattr *fp;
0bd503ad
KM
313 register u_long *p;
314 register long t1;
315 caddr_t bpos;
316 int error = 0;
317 char *cp2;
e8540f59 318 struct mbuf *mb, *mb2, *mreq;
f0f1cbaa 319 struct mbuf *m2, *m3;
971b93e3
KM
320 struct vnode *vp;
321 nfsv2fh_t nfh;
322 fhandle_t *fhp;
323 struct uio io, *uiop = &io;
324 struct vattr va, *vap = &va;
f0f1cbaa 325 int i, cnt, len, left, siz, tlen;
971b93e3
KM
326 off_t off;
327
328 fhp = &nfh.fh_generic;
329 nfsm_srvmtofh(fhp);
330 nfsm_disect(p, u_long *, NFSX_UNSIGNED);
331 off = fxdr_unsigned(off_t, *p);
332 nfsm_srvstrsiz(cnt, NFS_MAXDATA);
333 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
334 nfsm_reply(0);
24ed1a73 335 if (error = nfsrv_access(vp, VREAD | VEXEC, cred)) {
971b93e3
KM
336 vput(vp);
337 nfsm_reply(0);
338 }
339 len = left = cnt;
f0f1cbaa
KM
340 /*
341 * Generate the mbuf list with the uio_iov ref. to it.
342 */
343 i = 0;
344 m3 = (struct mbuf *)0;
d4e5799e
KM
345#ifdef lint
346 m2 = (struct mbuf *)0;
347#endif /* lint */
170bfd05
KM
348 MALLOC(iv, struct iovec *,
349 ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec), M_TEMP,
350 M_WAITOK);
351 iv2 = iv;
f0f1cbaa
KM
352 while (left > 0) {
353 MGET(m, M_WAIT, MT_DATA);
354 if (left > MINCLSIZE)
355 MCLGET(m, M_WAIT);
356 m->m_len = 0;
357 siz = min(M_TRAILINGSPACE(m), left);
358 m->m_len = siz;
170bfd05
KM
359 iv->iov_base = mtod(m, caddr_t);
360 iv->iov_len = siz;
361 iv++;
f0f1cbaa
KM
362 i++;
363 left -= siz;
364 if (m3) {
365 m2->m_next = m;
366 m2 = m;
367 } else
368 m3 = m2 = m;
369 }
170bfd05 370 uiop->uio_iov = iv2;
f0f1cbaa 371 uiop->uio_iovcnt = i;
971b93e3
KM
372 uiop->uio_offset = off;
373 uiop->uio_resid = cnt;
374 uiop->uio_rw = UIO_READ;
375 uiop->uio_segflg = UIO_SYSSPACE;
e9843ca3
KM
376 error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
377 off = uiop->uio_offset;
170bfd05 378 FREE((caddr_t)iv2, M_TEMP);
971b93e3 379 if (error) {
f0f1cbaa 380 m_freem(m3);
971b93e3
KM
381 vput(vp);
382 nfsm_reply(0);
383 }
384 if (error = VOP_GETATTR(vp, vap, cred))
f0f1cbaa 385 m_freem(m3);
971b93e3
KM
386 vput(vp);
387 nfsm_reply(NFSX_FATTR+NFSX_UNSIGNED);
9238aa59 388 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
e8540f59 389 nfsm_srvfillattr;
25951042
KM
390 len -= uiop->uio_resid;
391 if (len > 0) {
392 tlen = nfsm_rndup(len);
393 if (cnt != tlen || tlen != len)
f0f1cbaa 394 nfsm_adj(m3, cnt-tlen, tlen-len);
25951042
KM
395 } else {
396 m_freem(m3);
397 m3 = (struct mbuf *)0;
971b93e3 398 }
9238aa59 399 nfsm_build(p, u_long *, NFSX_UNSIGNED);
971b93e3 400 *p = txdr_unsigned(len);
f0f1cbaa 401 mb->m_next = m3;
971b93e3
KM
402 nfsm_srvdone;
403}
404
405/*
406 * nfs write service
407 */
e8540f59 408nfsrv_write(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
409 struct mbuf *mrep, *md, **mrq;
410 caddr_t dpos;
411 struct ucred *cred;
e8540f59
KM
412 u_long xid;
413 int *repstat;
971b93e3
KM
414{
415 register struct iovec *ivp;
416 register struct mbuf *mp;
9238aa59 417 register struct nfsv2_fattr *fp;
f0f1cbaa 418 struct iovec iv[NFS_MAXIOVEC];
971b93e3
KM
419 struct vattr va;
420 register struct vattr *vap = &va;
0bd503ad
KM
421 register u_long *p;
422 register long t1;
423 caddr_t bpos;
424 int error = 0;
425 char *cp2;
e8540f59 426 struct mbuf *mb, *mb2, *mreq;
971b93e3
KM
427 struct vnode *vp;
428 nfsv2fh_t nfh;
429 fhandle_t *fhp;
430 struct uio io, *uiop = &io;
431 off_t off;
432 long siz, len, xfer;
433
434 fhp = &nfh.fh_generic;
435 nfsm_srvmtofh(fhp);
436 nfsm_disect(p, u_long *, 4*NFSX_UNSIGNED);
437 off = fxdr_unsigned(off_t, *++p);
438 p += 2;
439 len = fxdr_unsigned(long, *p);
440 if (len > NFS_MAXDATA || len <= 0) {
441 error = EBADRPC;
442 nfsm_reply(0);
443 }
444 if (dpos == (mtod(md, caddr_t)+md->m_len)) {
445 mp = md->m_next;
446 if (mp == NULL) {
447 error = EBADRPC;
448 nfsm_reply(0);
449 }
450 } else {
451 mp = md;
452 siz = dpos-mtod(mp, caddr_t);
453 mp->m_len -= siz;
454 NFSMADV(mp, siz);
455 }
456 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
457 nfsm_reply(0);
24ed1a73 458 if (error = nfsrv_access(vp, VWRITE, cred)) {
971b93e3
KM
459 vput(vp);
460 nfsm_reply(0);
461 }
462 uiop->uio_resid = 0;
463 uiop->uio_rw = UIO_WRITE;
464 uiop->uio_segflg = UIO_SYSSPACE;
465 /*
f0f1cbaa 466 * Do up to NFS_MAXIOVEC mbufs of write each iteration of the
971b93e3
KM
467 * loop until done.
468 */
469 while (len > 0 && uiop->uio_resid == 0) {
470 ivp = iv;
471 siz = 0;
472 uiop->uio_iov = ivp;
473 uiop->uio_iovcnt = 0;
474 uiop->uio_offset = off;
f0f1cbaa 475 while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) {
971b93e3
KM
476 ivp->iov_base = mtod(mp, caddr_t);
477 if (len < mp->m_len)
478 ivp->iov_len = xfer = len;
479 else
480 ivp->iov_len = xfer = mp->m_len;
481#ifdef notdef
482 /* Not Yet .. */
483 if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0)
484 ivp->iov_op = NULL; /* what should it be ?? */
485 else
486 ivp->iov_op = NULL;
487#endif
488 uiop->uio_iovcnt++;
489 ivp++;
490 len -= xfer;
491 siz += xfer;
492 mp = mp->m_next;
493 }
494 if (len > 0 && mp == NULL) {
495 error = EBADRPC;
496 vput(vp);
497 nfsm_reply(0);
498 }
499 uiop->uio_resid = siz;
e9843ca3 500 if (error = VOP_WRITE(vp, uiop, IO_SYNC | IO_NODELOCKED,
971b93e3
KM
501 cred)) {
502 vput(vp);
503 nfsm_reply(0);
504 }
e9843ca3 505 off = uiop->uio_offset;
971b93e3
KM
506 }
507 error = VOP_GETATTR(vp, vap, cred);
508 vput(vp);
509 nfsm_reply(NFSX_FATTR);
9238aa59 510 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
e8540f59 511 nfsm_srvfillattr;
971b93e3
KM
512 nfsm_srvdone;
513}
514
515/*
516 * nfs create service
517 * now does a truncate to 0 length via. setattr if it already exists
518 */
e8540f59 519nfsrv_create(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
520 struct mbuf *mrep, *md, **mrq;
521 caddr_t dpos;
522 struct ucred *cred;
e8540f59
KM
523 u_long xid;
524 int *repstat;
971b93e3 525{
9238aa59 526 register struct nfsv2_fattr *fp;
971b93e3
KM
527 struct vattr va;
528 register struct vattr *vap = &va;
ffe6f482
KM
529 struct nameidata nami;
530 register struct nameidata *ndp = &nami;
0bd503ad
KM
531 register caddr_t cp;
532 register u_long *p;
533 register long t1;
534 caddr_t bpos;
d4e5799e 535 long rdev;
0bd503ad
KM
536 int error = 0;
537 char *cp2;
e8540f59 538 struct mbuf *mb, *mb2, *mreq;
971b93e3
KM
539 struct vnode *vp;
540 nfsv2fh_t nfh;
541 fhandle_t *fhp;
542 long len;
543
ffe6f482 544 ndinit(ndp);
971b93e3
KM
545 fhp = &nfh.fh_generic;
546 nfsm_srvmtofh(fhp);
547 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
548 ndp->ni_cred = cred;
549 ndp->ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF;
971b93e3
KM
550 if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
551 nfsm_reply(0);
3ee1461b 552 VATTR_NULL(vap);
d4e5799e 553 nfsm_disect(p, u_long *, NFSX_SATTR);
971b93e3
KM
554 /*
555 * Iff doesn't exist, create it
556 * otherwise just truncate to 0 length
557 * should I set the mode too ??
558 */
559 if (ndp->ni_vp == NULL) {
d4e5799e 560 vap->va_type = IFTOVT(fxdr_unsigned(u_long, *p));
4249699a
KM
561 if (vap->va_type == VNON)
562 vap->va_type = VREG;
d4e5799e
KM
563 vap->va_mode = nfstov_mode(*p);
564 rdev = fxdr_unsigned(long, *(p+3));
1c89915d 565 if (vap->va_type == VREG || vap->va_type == VSOCK) {
d4e5799e
KM
566 if (error = VOP_CREATE(ndp, vap))
567 nfsm_reply(0);
568 } else if (vap->va_type == VCHR || vap->va_type == VBLK ||
569 vap->va_type == VFIFO) {
570 if (vap->va_type == VCHR && rdev == 0xffffffff)
571 vap->va_type = VFIFO;
572 if (vap->va_type == VFIFO) {
573#ifndef FIFO
574 VOP_ABORTOP(ndp);
66955caf 575 vput(ndp->ni_dvp);
d4e5799e
KM
576 error = ENXIO;
577 nfsm_reply(0);
578#endif /* FIFO */
579 } else if (error = suser(cred, (short *)0)) {
580 VOP_ABORTOP(ndp);
66955caf 581 vput(ndp->ni_dvp);
d4e5799e
KM
582 nfsm_reply(0);
583 } else
584 vap->va_rdev = (dev_t)rdev;
585 if (error = VOP_MKNOD(ndp, vap, cred))
586 nfsm_reply(0);
587 ndp->ni_nameiop = LOOKUP | LOCKLEAF | HASBUF;
588 if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
589 nfsm_reply(0);
590 } else {
591 VOP_ABORTOP(ndp);
66955caf 592 vput(ndp->ni_dvp);
d4e5799e 593 error = ENXIO;
971b93e3 594 nfsm_reply(0);
d4e5799e 595 }
36c3043b 596 vp = ndp->ni_vp;
971b93e3 597 } else {
36c3043b 598 vp = ndp->ni_vp;
54fb9dc2 599 ndp->ni_vp = NULLVP;
36c3043b 600 VOP_ABORTOP(ndp);
639383fa
KM
601 if (ndp->ni_dvp == vp)
602 vrele(ndp->ni_dvp);
603 else
604 vput(ndp->ni_dvp);
971b93e3 605 vap->va_size = 0;
383e7b4c
KM
606 if (error = VOP_SETATTR(vp, vap, cred)) {
607 vput(vp);
971b93e3 608 nfsm_reply(0);
383e7b4c 609 }
971b93e3 610 }
971b93e3 611 bzero((caddr_t)fhp, sizeof(nfh));
54fb9dc2 612 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
971b93e3
KM
613 if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
614 vput(vp);
615 nfsm_reply(0);
616 }
617 error = VOP_GETATTR(vp, vap, cred);
618 vput(vp);
619 nfsm_reply(NFSX_FH+NFSX_FATTR);
620 nfsm_srvfhtom(fhp);
9238aa59 621 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
e8540f59 622 nfsm_srvfillattr;
971b93e3
KM
623 return (error);
624nfsmout:
625 VOP_ABORTOP(ndp);
639383fa
KM
626 if (ndp->ni_dvp == ndp->ni_vp)
627 vrele(ndp->ni_dvp);
628 else
629 vput(ndp->ni_dvp);
66955caf
KM
630 if (ndp->ni_vp)
631 vput(ndp->ni_vp);
971b93e3
KM
632 return (error);
633}
634
635/*
636 * nfs remove service
637 */
e8540f59 638nfsrv_remove(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
639 struct mbuf *mrep, *md, **mrq;
640 caddr_t dpos;
641 struct ucred *cred;
e8540f59
KM
642 u_long xid;
643 int *repstat;
971b93e3 644{
ffe6f482
KM
645 struct nameidata nami;
646 register struct nameidata *ndp = &nami;
0bd503ad
KM
647 register u_long *p;
648 register long t1;
649 caddr_t bpos;
650 int error = 0;
651 char *cp2;
e8540f59 652 struct mbuf *mb, *mreq;
971b93e3
KM
653 struct vnode *vp;
654 nfsv2fh_t nfh;
655 fhandle_t *fhp;
656 long len;
657
ffe6f482 658 ndinit(ndp);
971b93e3
KM
659 fhp = &nfh.fh_generic;
660 nfsm_srvmtofh(fhp);
661 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
662 ndp->ni_cred = cred;
663 ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
971b93e3
KM
664 if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
665 nfsm_reply(0);
666 vp = ndp->ni_vp;
667 if (vp->v_type == VDIR &&
668 (error = suser(cred, (short *)0)))
669 goto out;
670 /*
671 * Don't unlink a mounted file.
672 */
673 if (vp->v_flag & VROOT) {
674 error = EBUSY;
675 goto out;
676 }
677 if (vp->v_flag & VTEXT)
3329d91f 678#ifdef NVM
8986c97c 679 (void) vnode_pager_uncache(vp);
3329d91f
KM
680#else
681 xrele(vp); /* try once to free text */
682#endif
971b93e3 683out:
66955caf 684 if (!error) {
971b93e3 685 error = VOP_REMOVE(ndp);
66955caf
KM
686 } else {
687 VOP_ABORTOP(ndp);
639383fa
KM
688 if (ndp->ni_dvp == vp)
689 vrele(ndp->ni_dvp);
690 else
691 vput(ndp->ni_dvp);
66955caf
KM
692 vput(vp);
693 }
971b93e3
KM
694 nfsm_reply(0);
695 nfsm_srvdone;
696}
697
698/*
699 * nfs rename service
971b93e3 700 */
e8540f59 701nfsrv_rename(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
702 struct mbuf *mrep, *md, **mrq;
703 caddr_t dpos;
704 struct ucred *cred;
e8540f59
KM
705 u_long xid;
706 int *repstat;
971b93e3 707{
36c3043b 708 register struct nameidata *ndp;
0bd503ad
KM
709 register u_long *p;
710 register long t1;
711 caddr_t bpos;
712 int error = 0;
713 char *cp2;
e8540f59 714 struct mbuf *mb, *mreq;
ffe6f482 715 struct nameidata nami, tond;
971b93e3
KM
716 struct vnode *fvp, *tvp, *tdvp;
717 nfsv2fh_t fnfh, tnfh;
718 fhandle_t *ffhp, *tfhp;
719 long len, len2;
720 int rootflg = 0;
721
ffe6f482
KM
722 ndp = &nami;
723 ndinit(ndp);
971b93e3
KM
724 ffhp = &fnfh.fh_generic;
725 tfhp = &tnfh.fh_generic;
726 nfsm_srvmtofh(ffhp);
727 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
728 /*
729 * Remember if we are root so that we can reset cr_uid before
730 * the second nfs_namei() call
731 */
732 if (cred->cr_uid == 0)
733 rootflg++;
36c3043b 734 ndp->ni_cred = cred;
10bae9ee 735 ndp->ni_nameiop = DELETE | WANTPARENT | SAVESTARTDIR;
36c3043b 736 if (error = nfs_namei(ndp, ffhp, len, &md, &dpos))
971b93e3 737 nfsm_reply(0);
36c3043b 738 fvp = ndp->ni_vp;
971b93e3 739 nfsm_srvmtofh(tfhp);
f0f1cbaa 740 nfsm_strsiz(len2, NFS_MAXNAMLEN);
971b93e3
KM
741 if (rootflg)
742 cred->cr_uid = 0;
ffe6f482
KM
743 ndinit(&tond);
744 crhold(cred);
745 tond.ni_cred = cred;
10bae9ee
KM
746 tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE
747 | SAVESTARTDIR;
66955caf
KM
748 if (error = nfs_namei(&tond, tfhp, len2, &md, &dpos)) {
749 VOP_ABORTOP(ndp);
750 vrele(ndp->ni_dvp);
751 vrele(fvp);
752 goto out1;
753 }
36c3043b
KM
754 tdvp = tond.ni_dvp;
755 tvp = tond.ni_vp;
971b93e3
KM
756 if (tvp != NULL) {
757 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
758 error = EISDIR;
759 goto out;
760 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
761 error = ENOTDIR;
762 goto out;
763 }
764 }
971b93e3
KM
765 if (fvp->v_mount != tdvp->v_mount) {
766 error = EXDEV;
767 goto out;
768 }
769 if (fvp == tdvp || fvp == tvp)
770 error = EINVAL;
771out:
66955caf 772 if (!error) {
36c3043b 773 error = VOP_RENAME(ndp, &tond);
66955caf
KM
774 } else {
775 VOP_ABORTOP(&tond);
639383fa
KM
776 if (tdvp == tvp)
777 vrele(tdvp);
778 else
779 vput(tdvp);
66955caf
KM
780 if (tvp)
781 vput(tvp);
782 VOP_ABORTOP(ndp);
783 vrele(ndp->ni_dvp);
784 vrele(fvp);
971b93e3 785 }
10bae9ee 786 vrele(tond.ni_startdir);
971b93e3 787out1:
10bae9ee 788 vrele(ndp->ni_startdir);
ffe6f482 789 crfree(cred);
971b93e3
KM
790 nfsm_reply(0);
791 return (error);
792nfsmout:
10bae9ee
KM
793 if (ndp->ni_nameiop & SAVESTARTDIR)
794 vrele(ndp->ni_startdir);
36c3043b 795 VOP_ABORTOP(ndp);
66955caf
KM
796 vrele(ndp->ni_dvp);
797 vrele(fvp);
971b93e3
KM
798 return (error);
799}
800
801/*
802 * nfs link service
803 */
e8540f59 804nfsrv_link(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
805 struct mbuf *mrep, *md, **mrq;
806 caddr_t dpos;
807 struct ucred *cred;
e8540f59
KM
808 u_long xid;
809 int *repstat;
971b93e3 810{
ffe6f482
KM
811 struct nameidata nami;
812 register struct nameidata *ndp = &nami;
0bd503ad
KM
813 register u_long *p;
814 register long t1;
815 caddr_t bpos;
816 int error = 0;
817 char *cp2;
e8540f59 818 struct mbuf *mb, *mreq;
971b93e3
KM
819 struct vnode *vp, *xp;
820 nfsv2fh_t nfh, dnfh;
821 fhandle_t *fhp, *dfhp;
822 long len;
823
ffe6f482 824 ndinit(ndp);
971b93e3
KM
825 fhp = &nfh.fh_generic;
826 dfhp = &dnfh.fh_generic;
827 nfsm_srvmtofh(fhp);
828 nfsm_srvmtofh(dfhp);
829 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
830 if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred))
831 nfsm_reply(0);
832 if (vp->v_type == VDIR && (error = suser(cred, NULL)))
833 goto out1;
834 ndp->ni_cred = cred;
835 ndp->ni_nameiop = CREATE | LOCKPARENT;
971b93e3
KM
836 if (error = nfs_namei(ndp, dfhp, len, &md, &dpos))
837 goto out1;
838 xp = ndp->ni_vp;
839 if (xp != NULL) {
840 error = EEXIST;
841 goto out;
842 }
843 xp = ndp->ni_dvp;
844 if (vp->v_mount != xp->v_mount)
845 error = EXDEV;
846out:
66955caf 847 if (!error) {
971b93e3 848 error = VOP_LINK(vp, ndp);
66955caf
KM
849 } else {
850 VOP_ABORTOP(ndp);
639383fa
KM
851 if (ndp->ni_dvp == ndp->ni_vp)
852 vrele(ndp->ni_dvp);
853 else
854 vput(ndp->ni_dvp);
66955caf
KM
855 if (ndp->ni_vp)
856 vrele(ndp->ni_vp);
857 }
971b93e3
KM
858out1:
859 vrele(vp);
860 nfsm_reply(0);
861 nfsm_srvdone;
862}
863
864/*
865 * nfs symbolic link service
866 */
e8540f59 867nfsrv_symlink(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
868 struct mbuf *mrep, *md, **mrq;
869 caddr_t dpos;
870 struct ucred *cred;
e8540f59
KM
871 u_long xid;
872 int *repstat;
971b93e3
KM
873{
874 struct vattr va;
ffe6f482
KM
875 struct nameidata nami;
876 register struct nameidata *ndp = &nami;
971b93e3 877 register struct vattr *vap = &va;
0bd503ad
KM
878 register u_long *p;
879 register long t1;
09e56da6 880 struct nfsv2_sattr *sp;
0bd503ad 881 caddr_t bpos;
f0f1cbaa
KM
882 struct uio io;
883 struct iovec iv;
0bd503ad 884 int error = 0;
f0f1cbaa 885 char *pathcp, *cp2;
e8540f59 886 struct mbuf *mb, *mreq;
971b93e3
KM
887 nfsv2fh_t nfh;
888 fhandle_t *fhp;
d4e5799e 889 long len, len2;
971b93e3 890
f0f1cbaa 891 pathcp = (char *)0;
ffe6f482 892 ndinit(ndp);
971b93e3
KM
893 fhp = &nfh.fh_generic;
894 nfsm_srvmtofh(fhp);
895 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
896 ndp->ni_cred = cred;
897 ndp->ni_nameiop = CREATE | LOCKPARENT;
971b93e3 898 if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
66955caf 899 goto out;
f0f1cbaa
KM
900 nfsm_strsiz(len2, NFS_MAXPATHLEN);
901 MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK);
902 iv.iov_base = pathcp;
903 iv.iov_len = len2;
904 io.uio_resid = len2;
905 io.uio_offset = 0;
906 io.uio_iov = &iv;
907 io.uio_iovcnt = 1;
908 io.uio_segflg = UIO_SYSSPACE;
909 io.uio_rw = UIO_READ;
910 nfsm_mtouio(&io, len2);
09e56da6 911 nfsm_disect(sp, struct nfsv2_sattr *, NFSX_SATTR);
f0f1cbaa 912 *(pathcp + len2) = '\0';
66955caf
KM
913 if (ndp->ni_vp) {
914 VOP_ABORTOP(ndp);
639383fa
KM
915 if (ndp->ni_dvp == ndp->ni_vp)
916 vrele(ndp->ni_dvp);
917 else
918 vput(ndp->ni_dvp);
66955caf 919 vrele(ndp->ni_vp);
971b93e3
KM
920 error = EEXIST;
921 goto out;
922 }
3ee1461b 923 VATTR_NULL(vap);
09e56da6 924 vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode);
66955caf 925 error = VOP_SYMLINK(ndp, vap, pathcp);
971b93e3 926out:
f0f1cbaa
KM
927 if (pathcp)
928 FREE(pathcp, M_TEMP);
971b93e3
KM
929 nfsm_reply(0);
930 return (error);
931nfsmout:
932 VOP_ABORTOP(ndp);
639383fa
KM
933 if (ndp->ni_dvp == ndp->ni_vp)
934 vrele(ndp->ni_dvp);
935 else
936 vput(ndp->ni_dvp);
66955caf
KM
937 if (ndp->ni_vp);
938 vrele(ndp->ni_vp);
f0f1cbaa
KM
939 if (pathcp)
940 FREE(pathcp, M_TEMP);
971b93e3
KM
941 return (error);
942}
943
944/*
945 * nfs mkdir service
946 */
e8540f59 947nfsrv_mkdir(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
948 struct mbuf *mrep, *md, **mrq;
949 caddr_t dpos;
950 struct ucred *cred;
e8540f59
KM
951 u_long xid;
952 int *repstat;
971b93e3
KM
953{
954 struct vattr va;
955 register struct vattr *vap = &va;
9238aa59 956 register struct nfsv2_fattr *fp;
ffe6f482
KM
957 struct nameidata nami;
958 register struct nameidata *ndp = &nami;
0bd503ad
KM
959 register caddr_t cp;
960 register u_long *p;
961 register long t1;
962 caddr_t bpos;
963 int error = 0;
964 char *cp2;
e8540f59 965 struct mbuf *mb, *mb2, *mreq;
971b93e3
KM
966 struct vnode *vp;
967 nfsv2fh_t nfh;
968 fhandle_t *fhp;
969 long len;
970
ffe6f482 971 ndinit(ndp);
971b93e3
KM
972 fhp = &nfh.fh_generic;
973 nfsm_srvmtofh(fhp);
974 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
975 ndp->ni_cred = cred;
10bae9ee 976 ndp->ni_nameiop = CREATE | LOCKPARENT | SAVESTARTDIR;
971b93e3
KM
977 if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
978 nfsm_reply(0);
979 nfsm_disect(p, u_long *, NFSX_UNSIGNED);
3ee1461b 980 VATTR_NULL(vap);
971b93e3
KM
981 vap->va_type = VDIR;
982 vap->va_mode = nfstov_mode(*p++);
983 vp = ndp->ni_vp;
984 if (vp != NULL) {
985 VOP_ABORTOP(ndp);
639383fa
KM
986 if (ndp->ni_dvp == vp)
987 vrele(ndp->ni_dvp);
988 else
989 vput(ndp->ni_dvp);
66955caf 990 vrele(vp);
10bae9ee 991 vrele(ndp->ni_startdir);
971b93e3
KM
992 error = EEXIST;
993 nfsm_reply(0);
994 }
10bae9ee
KM
995 error = VOP_MKDIR(ndp, vap);
996 vrele(ndp->ni_startdir);
997 if (error)
971b93e3
KM
998 nfsm_reply(0);
999 vp = ndp->ni_vp;
1000 bzero((caddr_t)fhp, sizeof(nfh));
54fb9dc2 1001 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
971b93e3
KM
1002 if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
1003 vput(vp);
1004 nfsm_reply(0);
1005 }
1006 error = VOP_GETATTR(vp, vap, cred);
1007 vput(vp);
1008 nfsm_reply(NFSX_FH+NFSX_FATTR);
1009 nfsm_srvfhtom(fhp);
9238aa59 1010 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
e8540f59 1011 nfsm_srvfillattr;
971b93e3
KM
1012 return (error);
1013nfsmout:
1014 VOP_ABORTOP(ndp);
639383fa
KM
1015 if (ndp->ni_dvp == ndp->ni_vp)
1016 vrele(ndp->ni_dvp);
1017 else
1018 vput(ndp->ni_dvp);
66955caf
KM
1019 if (ndp->ni_vp)
1020 vrele(ndp->ni_vp);
971b93e3
KM
1021 return (error);
1022}
1023
1024/*
1025 * nfs rmdir service
1026 */
e8540f59 1027nfsrv_rmdir(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
1028 struct mbuf *mrep, *md, **mrq;
1029 caddr_t dpos;
1030 struct ucred *cred;
e8540f59
KM
1031 u_long xid;
1032 int *repstat;
971b93e3 1033{
ffe6f482
KM
1034 struct nameidata nami;
1035 register struct nameidata *ndp = &nami;
0bd503ad
KM
1036 register u_long *p;
1037 register long t1;
1038 caddr_t bpos;
1039 int error = 0;
1040 char *cp2;
e8540f59 1041 struct mbuf *mb, *mreq;
971b93e3
KM
1042 struct vnode *vp;
1043 nfsv2fh_t nfh;
1044 fhandle_t *fhp;
1045 long len;
1046
ffe6f482 1047 ndinit(ndp);
971b93e3
KM
1048 fhp = &nfh.fh_generic;
1049 nfsm_srvmtofh(fhp);
1050 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
1051 ndp->ni_cred = cred;
1052 ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
971b93e3
KM
1053 if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
1054 nfsm_reply(0);
1055 vp = ndp->ni_vp;
1056 if (vp->v_type != VDIR) {
1057 error = ENOTDIR;
1058 goto out;
1059 }
1060 /*
1061 * No rmdir "." please.
1062 */
1063 if (ndp->ni_dvp == vp) {
1064 error = EINVAL;
1065 goto out;
1066 }
1067 /*
1068 * Don't unlink a mounted file.
1069 */
1070 if (vp->v_flag & VROOT)
1071 error = EBUSY;
1072out:
66955caf 1073 if (!error) {
971b93e3 1074 error = VOP_RMDIR(ndp);
66955caf
KM
1075 } else {
1076 VOP_ABORTOP(ndp);
639383fa
KM
1077 if (ndp->ni_dvp == ndp->ni_vp)
1078 vrele(ndp->ni_dvp);
1079 else
1080 vput(ndp->ni_dvp);
66955caf
KM
1081 vput(vp);
1082 }
971b93e3
KM
1083 nfsm_reply(0);
1084 nfsm_srvdone;
1085}
1086
1087/*
1088 * nfs readdir service
1089 * - mallocs what it thinks is enough to read
f0f1cbaa 1090 * count rounded up to a multiple of DIRBLKSIZ <= NFS_MAXREADDIR
971b93e3 1091 * - calls VOP_READDIR()
732aefe9 1092 * - loops around building the reply
36c3043b
KM
1093 * if the output generated exceeds count break out of loop
1094 * The nfsm_clget macro is used here so that the reply will be packed
1095 * tightly in mbuf clusters.
971b93e3 1096 * - it only knows that it has encountered eof when the VOP_READDIR()
36c3043b 1097 * reads nothing
971b93e3 1098 * - as such one readdir rpc will return eof false although you are there
36c3043b 1099 * and then the next will return eof
971b93e3 1100 * - it trims out records with d_ino == 0
36c3043b
KM
1101 * this doesn't matter for Unix clients, but they might confuse clients
1102 * for other os'.
971b93e3 1103 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
36c3043b
KM
1104 * than requested, but this may not apply to all filesystems. For
1105 * example, client NFS does not { although it is never remote mounted
1106 * anyhow }
971b93e3 1107 * PS: The NFS protocol spec. does not clarify what the "count" byte
36c3043b
KM
1108 * argument is a count of.. just name strings and file id's or the
1109 * entire reply rpc or ...
1110 * I tried just file name and id sizes and it confused the Sun client,
1111 * so I am using the full rpc size now. The "paranoia.." comment refers
1112 * to including the status longwords that are not a part of the dir.
1113 * "entry" structures, but are in the rpc.
971b93e3 1114 */
e8540f59 1115nfsrv_readdir(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
1116 struct mbuf **mrq;
1117 struct mbuf *mrep, *md;
1118 caddr_t dpos;
1119 struct ucred *cred;
1120 u_long xid;
e8540f59 1121 int *repstat;
971b93e3
KM
1122{
1123 register char *bp, *be;
1124 register struct mbuf *mp;
1125 register struct direct *dp;
0bd503ad
KM
1126 register caddr_t cp;
1127 register u_long *p;
1128 register long t1;
1129 caddr_t bpos;
1130 int error = 0;
1131 char *cp2;
e8540f59 1132 struct mbuf *mb, *mb2, *mreq;
971b93e3
KM
1133 char *cpos, *cend;
1134 int len, nlen, rem, xfer, tsiz, i;
1135 struct vnode *vp;
1136 struct mbuf *mp2, *mp3;
1137 nfsv2fh_t nfh;
1138 fhandle_t *fhp;
1139 struct uio io;
1140 struct iovec iv;
e49b1a6c 1141 int siz, cnt, fullsiz, eofflag;
971b93e3
KM
1142 u_long on;
1143 char *rbuf;
1144 off_t off, toff;
1145
1146 fhp = &nfh.fh_generic;
1147 nfsm_srvmtofh(fhp);
1148 nfsm_disect(p, u_long *, 2*NFSX_UNSIGNED);
1149 toff = fxdr_unsigned(off_t, *p++);
1150 off = (toff & ~(DIRBLKSIZ-1));
1151 on = (toff & (DIRBLKSIZ-1));
1152 cnt = fxdr_unsigned(int, *p);
f0f1cbaa
KM
1153 siz = ((cnt+DIRBLKSIZ-1) & ~(DIRBLKSIZ-1));
1154 if (cnt > NFS_MAXREADDIR)
1155 siz = NFS_MAXREADDIR;
971b93e3
KM
1156 fullsiz = siz;
1157 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
1158 nfsm_reply(0);
24ed1a73 1159 if (error = nfsrv_access(vp, VEXEC, cred)) {
971b93e3
KM
1160 vput(vp);
1161 nfsm_reply(0);
1162 }
1163 VOP_UNLOCK(vp);
1164 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
1165again:
1166 iv.iov_base = rbuf;
1167 iv.iov_len = fullsiz;
1168 io.uio_iov = &iv;
1169 io.uio_iovcnt = 1;
1170 io.uio_offset = off;
1171 io.uio_resid = fullsiz;
1172 io.uio_segflg = UIO_SYSSPACE;
1173 io.uio_rw = UIO_READ;
e49b1a6c 1174 error = VOP_READDIR(vp, &io, cred, &eofflag);
e9843ca3 1175 off = io.uio_offset;
971b93e3
KM
1176 if (error) {
1177 vrele(vp);
1178 free((caddr_t)rbuf, M_TEMP);
1179 nfsm_reply(0);
1180 }
1181 if (io.uio_resid) {
1182 siz -= io.uio_resid;
1183
1184 /*
1185 * If nothing read, return eof
1186 * rpc reply
1187 */
1188 if (siz == 0) {
1189 vrele(vp);
1190 nfsm_reply(2*NFSX_UNSIGNED);
1191 nfsm_build(p, u_long *, 2*NFSX_UNSIGNED);
1192 *p++ = nfs_false;
1193 *p = nfs_true;
1194 FREE((caddr_t)rbuf, M_TEMP);
1195 return (0);
1196 }
1197 }
732aefe9 1198
971b93e3
KM
1199 /*
1200 * Check for degenerate cases of nothing useful read.
732aefe9 1201 * If so go try again
971b93e3 1202 */
732aefe9
KM
1203 cpos = rbuf + on;
1204 cend = rbuf + siz;
1205 dp = (struct direct *)cpos;
1206 while (cpos < cend && dp->d_ino == 0) {
1207 cpos += dp->d_reclen;
1208 dp = (struct direct *)cpos;
1209 }
1210 if (cpos >= cend) {
971b93e3
KM
1211 toff = off;
1212 siz = fullsiz;
1213 on = 0;
1214 goto again;
1215 }
732aefe9
KM
1216
1217 cpos = rbuf + on;
1218 cend = rbuf + siz;
1219 dp = (struct direct *)cpos;
971b93e3 1220 vrele(vp);
36c3043b 1221 len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */
971b93e3
KM
1222 bp = be = (caddr_t)0;
1223 mp3 = (struct mbuf *)0;
1224 nfsm_reply(siz);
1225
1226 /* Loop through the records and build reply */
1227 while (cpos < cend) {
1228 if (dp->d_ino != 0) {
1229 nlen = dp->d_namlen;
1230 rem = nfsm_rndup(nlen)-nlen;
36c3043b 1231
971b93e3
KM
1232 /*
1233 * As noted above, the NFS spec. is not clear about what
1234 * should be included in "count" as totalled up here in
1235 * "len".
1236 */
1237 len += (4*NFSX_UNSIGNED+nlen+rem);
f0f1cbaa
KM
1238 if (len > cnt) {
1239 eofflag = 0;
971b93e3 1240 break;
f0f1cbaa 1241 }
36c3043b 1242
971b93e3
KM
1243 /* Build the directory record xdr from the direct entry */
1244 nfsm_clget;
1245 *p = nfs_true;
1246 bp += NFSX_UNSIGNED;
1247 nfsm_clget;
1248 *p = txdr_unsigned(dp->d_ino);
1249 bp += NFSX_UNSIGNED;
1250 nfsm_clget;
1251 *p = txdr_unsigned(nlen);
1252 bp += NFSX_UNSIGNED;
36c3043b 1253
971b93e3
KM
1254 /* And loop arround copying the name */
1255 xfer = nlen;
1256 cp = dp->d_name;
1257 while (xfer > 0) {
1258 nfsm_clget;
1259 if ((bp+xfer) > be)
1260 tsiz = be-bp;
1261 else
1262 tsiz = xfer;
1263 bcopy(cp, bp, tsiz);
1264 bp += tsiz;
1265 xfer -= tsiz;
1266 if (xfer > 0)
1267 cp += tsiz;
1268 }
1269 /* And null pad to a long boundary */
1270 for (i = 0; i < rem; i++)
1271 *bp++ = '\0';
1272 nfsm_clget;
36c3043b 1273
971b93e3
KM
1274 /* Finish off the record */
1275 toff += dp->d_reclen;
1276 *p = txdr_unsigned(toff);
1277 bp += NFSX_UNSIGNED;
1278 } else
1279 toff += dp->d_reclen;
1280 cpos += dp->d_reclen;
1281 dp = (struct direct *)cpos;
1282 }
1283 nfsm_clget;
1284 *p = nfs_false;
1285 bp += NFSX_UNSIGNED;
1286 nfsm_clget;
e49b1a6c
KM
1287 if (eofflag)
1288 *p = nfs_true;
1289 else
1290 *p = nfs_false;
971b93e3
KM
1291 bp += NFSX_UNSIGNED;
1292 if (bp < be)
1293 mp->m_len = bp-mtod(mp, caddr_t);
1294 mb->m_next = mp3;
1295 FREE(rbuf, M_TEMP);
1296 nfsm_srvdone;
1297}
1298
1299/*
1300 * nfs statfs service
1301 */
e8540f59 1302nfsrv_statfs(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
1303 struct mbuf **mrq;
1304 struct mbuf *mrep, *md;
1305 caddr_t dpos;
1306 struct ucred *cred;
1307 u_long xid;
e8540f59 1308 int *repstat;
971b93e3
KM
1309{
1310 register struct statfs *sf;
9238aa59 1311 register struct nfsv2_statfs *sfp;
0bd503ad
KM
1312 register u_long *p;
1313 register long t1;
1314 caddr_t bpos;
1315 int error = 0;
1316 char *cp2;
e8540f59 1317 struct mbuf *mb, *mb2, *mreq;
971b93e3
KM
1318 struct vnode *vp;
1319 nfsv2fh_t nfh;
1320 fhandle_t *fhp;
1321 struct statfs statfs;
1322
1323 fhp = &nfh.fh_generic;
1324 nfsm_srvmtofh(fhp);
1325 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
1326 nfsm_reply(0);
1327 sf = &statfs;
1328 error = VFS_STATFS(vp->v_mount, sf);
1329 vput(vp);
1330 nfsm_reply(NFSX_STATFS);
9238aa59 1331 nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS);
b28c3bcc 1332 sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
9238aa59
RM
1333 sfp->sf_bsize = txdr_unsigned(sf->f_fsize);
1334 sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
1335 sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
1336 sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
971b93e3
KM
1337 nfsm_srvdone;
1338}
1339
1340/*
1341 * Null operation, used by clients to ping server
1342 */
0bd503ad 1343/* ARGSUSED */
e8540f59 1344nfsrv_null(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
1345 struct mbuf **mrq;
1346 struct mbuf *mrep, *md;
1347 caddr_t dpos;
1348 struct ucred *cred;
1349 u_long xid;
e8540f59 1350 int *repstat;
971b93e3 1351{
0bd503ad
KM
1352 caddr_t bpos;
1353 int error = 0;
e8540f59 1354 struct mbuf *mb, *mreq;
971b93e3
KM
1355
1356 error = VNOVAL;
1357 nfsm_reply(0);
0bd503ad 1358 return (error);
971b93e3
KM
1359}
1360
1361/*
1362 * No operation, used for obsolete procedures
1363 */
0bd503ad 1364/* ARGSUSED */
e8540f59 1365nfsrv_noop(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
1366 struct mbuf **mrq;
1367 struct mbuf *mrep, *md;
1368 caddr_t dpos;
1369 struct ucred *cred;
1370 u_long xid;
e8540f59 1371 int *repstat;
971b93e3 1372{
0bd503ad
KM
1373 caddr_t bpos;
1374 int error = 0;
e8540f59 1375 struct mbuf *mb, *mreq;
971b93e3
KM
1376
1377 error = EPROCUNAVAIL;
1378 nfsm_reply(0);
0bd503ad 1379 return (error);
971b93e3 1380}
36c3043b 1381
24ed1a73
KM
1382/*
1383 * Perform access checking for vnodes obtained from file handles that would
1384 * refer to files already opened by a Unix client. You cannot just use
1385 * vn_writechk() and VOP_ACCESS() for two reasons.
54fb9dc2 1386 * 1 - You must check for MNT_EXRDONLY as well as MNT_RDONLY for the write case
24ed1a73
KM
1387 * 2 - The owner is to be given access irrespective of mode bits so that
1388 * processes that chmod after opening a file don't break. I don't like
1389 * this because it opens a security hole, but since the nfs server opens
1390 * a security hole the size of a barn door anyhow, what the heck.
1391 */
1392nfsrv_access(vp, flags, cred)
1393 register struct vnode *vp;
1394 int flags;
1395 register struct ucred *cred;
1396{
1397 struct vattr vattr;
1398 int error;
1399 if (flags & VWRITE) {
54fb9dc2 1400 /* Just vn_writechk() changed to check MNT_EXRDONLY */
24ed1a73
KM
1401 /*
1402 * Disallow write attempts on read-only file systems;
1403 * unless the file is a socket or a block or character
1404 * device resident on the file system.
1405 */
fef23149
KM
1406 if (vp->v_mount->mnt_flag & (MNT_RDONLY | MNT_EXRDONLY)) {
1407 switch (vp->v_type) {
1408 case VREG: case VDIR: case VLNK:
24ed1a73 1409 return (EROFS);
fef23149
KM
1410 }
1411 }
24ed1a73
KM
1412 /*
1413 * If there's shared text associated with
1414 * the inode, try to free it up once. If
1415 * we fail, we can't allow writing.
1416 */
3329d91f 1417#ifdef NVM
8986c97c 1418 if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
24ed1a73 1419 return (ETXTBSY);
3329d91f
KM
1420#else
1421 if (vp->v_flag & VTEXT)
1422 xrele(vp);
1423 if (vp->v_flag & VTEXT)
1424 return (ETXTBSY);
1425#endif
24ed1a73 1426 }
fef23149
KM
1427 if (error = VOP_GETATTR(vp, &vattr, cred))
1428 return (error);
1429 if ((error = VOP_ACCESS(vp, flags, cred)) &&
1430 cred->cr_uid != vattr.va_uid)
1431 return (error);
1432 return (0);
24ed1a73 1433}