file descriptors are now allocated dynamically
[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 *
25951042 10 * @(#)nfs_serv.c 7.31 (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"
971b93e3 32#include "user.h"
e587d97d 33#include "file.h"
971b93e3 34#include "vnode.h"
e587d97d
KM
35#include "mount.h"
36#include "mbuf.h"
971b93e3 37#include "errno.h"
d4e5799e
KM
38#include "../ufs/quota.h"
39#include "../ufs/inode.h"
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));
565 if (vap->va_type == VREG) {
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)
8986c97c 678 (void) vnode_pager_uncache(vp);
971b93e3 679out:
66955caf 680 if (!error) {
971b93e3 681 error = VOP_REMOVE(ndp);
66955caf
KM
682 } else {
683 VOP_ABORTOP(ndp);
639383fa
KM
684 if (ndp->ni_dvp == vp)
685 vrele(ndp->ni_dvp);
686 else
687 vput(ndp->ni_dvp);
66955caf
KM
688 vput(vp);
689 }
971b93e3
KM
690 nfsm_reply(0);
691 nfsm_srvdone;
692}
693
694/*
695 * nfs rename service
971b93e3 696 */
e8540f59 697nfsrv_rename(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
698 struct mbuf *mrep, *md, **mrq;
699 caddr_t dpos;
700 struct ucred *cred;
e8540f59
KM
701 u_long xid;
702 int *repstat;
971b93e3 703{
36c3043b 704 register struct nameidata *ndp;
0bd503ad
KM
705 register u_long *p;
706 register long t1;
707 caddr_t bpos;
708 int error = 0;
709 char *cp2;
e8540f59 710 struct mbuf *mb, *mreq;
ffe6f482 711 struct nameidata nami, tond;
971b93e3
KM
712 struct vnode *fvp, *tvp, *tdvp;
713 nfsv2fh_t fnfh, tnfh;
714 fhandle_t *ffhp, *tfhp;
715 long len, len2;
716 int rootflg = 0;
717
ffe6f482
KM
718 ndp = &nami;
719 ndinit(ndp);
971b93e3
KM
720 ffhp = &fnfh.fh_generic;
721 tfhp = &tnfh.fh_generic;
722 nfsm_srvmtofh(ffhp);
723 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
724 /*
725 * Remember if we are root so that we can reset cr_uid before
726 * the second nfs_namei() call
727 */
728 if (cred->cr_uid == 0)
729 rootflg++;
36c3043b
KM
730 ndp->ni_cred = cred;
731 ndp->ni_nameiop = DELETE | WANTPARENT;
732 if (error = nfs_namei(ndp, ffhp, len, &md, &dpos))
971b93e3 733 nfsm_reply(0);
36c3043b 734 fvp = ndp->ni_vp;
971b93e3 735 nfsm_srvmtofh(tfhp);
f0f1cbaa 736 nfsm_strsiz(len2, NFS_MAXNAMLEN);
971b93e3
KM
737 if (rootflg)
738 cred->cr_uid = 0;
ffe6f482
KM
739 ndinit(&tond);
740 crhold(cred);
741 tond.ni_cred = cred;
36c3043b 742 tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
66955caf
KM
743 if (error = nfs_namei(&tond, tfhp, len2, &md, &dpos)) {
744 VOP_ABORTOP(ndp);
745 vrele(ndp->ni_dvp);
746 vrele(fvp);
747 goto out1;
748 }
36c3043b
KM
749 tdvp = tond.ni_dvp;
750 tvp = tond.ni_vp;
971b93e3
KM
751 if (tvp != NULL) {
752 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
753 error = EISDIR;
754 goto out;
755 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
756 error = ENOTDIR;
757 goto out;
758 }
759 }
971b93e3
KM
760 if (fvp->v_mount != tdvp->v_mount) {
761 error = EXDEV;
762 goto out;
763 }
764 if (fvp == tdvp || fvp == tvp)
765 error = EINVAL;
766out:
66955caf 767 if (!error) {
ffe6f482 768 VREF(ndp->ni_cdir);
107d27c5 769 VREF(tond.ni_cdir);
36c3043b 770 error = VOP_RENAME(ndp, &tond);
ffe6f482 771 vrele(ndp->ni_cdir);
107d27c5 772 vrele(tond.ni_cdir);
66955caf
KM
773 } else {
774 VOP_ABORTOP(&tond);
639383fa
KM
775 if (tdvp == tvp)
776 vrele(tdvp);
777 else
778 vput(tdvp);
66955caf
KM
779 if (tvp)
780 vput(tvp);
781 VOP_ABORTOP(ndp);
782 vrele(ndp->ni_dvp);
783 vrele(fvp);
971b93e3
KM
784 }
785out1:
ffe6f482 786 crfree(cred);
971b93e3
KM
787 nfsm_reply(0);
788 return (error);
789nfsmout:
36c3043b 790 VOP_ABORTOP(ndp);
66955caf
KM
791 vrele(ndp->ni_dvp);
792 vrele(fvp);
971b93e3
KM
793 return (error);
794}
795
796/*
797 * nfs link service
798 */
e8540f59 799nfsrv_link(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
800 struct mbuf *mrep, *md, **mrq;
801 caddr_t dpos;
802 struct ucred *cred;
e8540f59
KM
803 u_long xid;
804 int *repstat;
971b93e3 805{
ffe6f482
KM
806 struct nameidata nami;
807 register struct nameidata *ndp = &nami;
0bd503ad
KM
808 register u_long *p;
809 register long t1;
810 caddr_t bpos;
811 int error = 0;
812 char *cp2;
e8540f59 813 struct mbuf *mb, *mreq;
971b93e3
KM
814 struct vnode *vp, *xp;
815 nfsv2fh_t nfh, dnfh;
816 fhandle_t *fhp, *dfhp;
817 long len;
818
ffe6f482 819 ndinit(ndp);
971b93e3
KM
820 fhp = &nfh.fh_generic;
821 dfhp = &dnfh.fh_generic;
822 nfsm_srvmtofh(fhp);
823 nfsm_srvmtofh(dfhp);
824 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
825 if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred))
826 nfsm_reply(0);
827 if (vp->v_type == VDIR && (error = suser(cred, NULL)))
828 goto out1;
829 ndp->ni_cred = cred;
830 ndp->ni_nameiop = CREATE | LOCKPARENT;
971b93e3
KM
831 if (error = nfs_namei(ndp, dfhp, len, &md, &dpos))
832 goto out1;
833 xp = ndp->ni_vp;
834 if (xp != NULL) {
835 error = EEXIST;
836 goto out;
837 }
838 xp = ndp->ni_dvp;
839 if (vp->v_mount != xp->v_mount)
840 error = EXDEV;
841out:
66955caf 842 if (!error) {
971b93e3 843 error = VOP_LINK(vp, ndp);
66955caf
KM
844 } else {
845 VOP_ABORTOP(ndp);
639383fa
KM
846 if (ndp->ni_dvp == ndp->ni_vp)
847 vrele(ndp->ni_dvp);
848 else
849 vput(ndp->ni_dvp);
66955caf
KM
850 if (ndp->ni_vp)
851 vrele(ndp->ni_vp);
852 }
971b93e3
KM
853out1:
854 vrele(vp);
855 nfsm_reply(0);
856 nfsm_srvdone;
857}
858
859/*
860 * nfs symbolic link service
861 */
e8540f59 862nfsrv_symlink(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
863 struct mbuf *mrep, *md, **mrq;
864 caddr_t dpos;
865 struct ucred *cred;
e8540f59
KM
866 u_long xid;
867 int *repstat;
971b93e3
KM
868{
869 struct vattr va;
ffe6f482
KM
870 struct nameidata nami;
871 register struct nameidata *ndp = &nami;
971b93e3 872 register struct vattr *vap = &va;
0bd503ad
KM
873 register u_long *p;
874 register long t1;
09e56da6 875 struct nfsv2_sattr *sp;
0bd503ad 876 caddr_t bpos;
f0f1cbaa
KM
877 struct uio io;
878 struct iovec iv;
0bd503ad 879 int error = 0;
f0f1cbaa 880 char *pathcp, *cp2;
e8540f59 881 struct mbuf *mb, *mreq;
971b93e3
KM
882 nfsv2fh_t nfh;
883 fhandle_t *fhp;
d4e5799e 884 long len, len2;
971b93e3 885
f0f1cbaa 886 pathcp = (char *)0;
ffe6f482 887 ndinit(ndp);
971b93e3
KM
888 fhp = &nfh.fh_generic;
889 nfsm_srvmtofh(fhp);
890 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
891 ndp->ni_cred = cred;
892 ndp->ni_nameiop = CREATE | LOCKPARENT;
971b93e3 893 if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
66955caf 894 goto out;
f0f1cbaa
KM
895 nfsm_strsiz(len2, NFS_MAXPATHLEN);
896 MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK);
897 iv.iov_base = pathcp;
898 iv.iov_len = len2;
899 io.uio_resid = len2;
900 io.uio_offset = 0;
901 io.uio_iov = &iv;
902 io.uio_iovcnt = 1;
903 io.uio_segflg = UIO_SYSSPACE;
904 io.uio_rw = UIO_READ;
905 nfsm_mtouio(&io, len2);
09e56da6 906 nfsm_disect(sp, struct nfsv2_sattr *, NFSX_SATTR);
f0f1cbaa 907 *(pathcp + len2) = '\0';
66955caf
KM
908 if (ndp->ni_vp) {
909 VOP_ABORTOP(ndp);
639383fa
KM
910 if (ndp->ni_dvp == ndp->ni_vp)
911 vrele(ndp->ni_dvp);
912 else
913 vput(ndp->ni_dvp);
66955caf 914 vrele(ndp->ni_vp);
971b93e3
KM
915 error = EEXIST;
916 goto out;
917 }
3ee1461b 918 VATTR_NULL(vap);
09e56da6 919 vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode);
66955caf 920 error = VOP_SYMLINK(ndp, vap, pathcp);
971b93e3 921out:
f0f1cbaa
KM
922 if (pathcp)
923 FREE(pathcp, M_TEMP);
971b93e3
KM
924 nfsm_reply(0);
925 return (error);
926nfsmout:
927 VOP_ABORTOP(ndp);
639383fa
KM
928 if (ndp->ni_dvp == ndp->ni_vp)
929 vrele(ndp->ni_dvp);
930 else
931 vput(ndp->ni_dvp);
66955caf
KM
932 if (ndp->ni_vp);
933 vrele(ndp->ni_vp);
f0f1cbaa
KM
934 if (pathcp)
935 FREE(pathcp, M_TEMP);
971b93e3
KM
936 return (error);
937}
938
939/*
940 * nfs mkdir service
941 */
e8540f59 942nfsrv_mkdir(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
943 struct mbuf *mrep, *md, **mrq;
944 caddr_t dpos;
945 struct ucred *cred;
e8540f59
KM
946 u_long xid;
947 int *repstat;
971b93e3
KM
948{
949 struct vattr va;
950 register struct vattr *vap = &va;
9238aa59 951 register struct nfsv2_fattr *fp;
ffe6f482
KM
952 struct nameidata nami;
953 register struct nameidata *ndp = &nami;
0bd503ad
KM
954 register caddr_t cp;
955 register u_long *p;
956 register long t1;
957 caddr_t bpos;
958 int error = 0;
959 char *cp2;
e8540f59 960 struct mbuf *mb, *mb2, *mreq;
971b93e3
KM
961 struct vnode *vp;
962 nfsv2fh_t nfh;
963 fhandle_t *fhp;
964 long len;
965
ffe6f482 966 ndinit(ndp);
971b93e3
KM
967 fhp = &nfh.fh_generic;
968 nfsm_srvmtofh(fhp);
969 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
970 ndp->ni_cred = cred;
971 ndp->ni_nameiop = CREATE | LOCKPARENT;
971b93e3
KM
972 if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
973 nfsm_reply(0);
974 nfsm_disect(p, u_long *, NFSX_UNSIGNED);
3ee1461b 975 VATTR_NULL(vap);
971b93e3
KM
976 vap->va_type = VDIR;
977 vap->va_mode = nfstov_mode(*p++);
978 vp = ndp->ni_vp;
979 if (vp != NULL) {
980 VOP_ABORTOP(ndp);
639383fa
KM
981 if (ndp->ni_dvp == vp)
982 vrele(ndp->ni_dvp);
983 else
984 vput(ndp->ni_dvp);
66955caf 985 vrele(vp);
971b93e3
KM
986 error = EEXIST;
987 nfsm_reply(0);
988 }
989 if (error = VOP_MKDIR(ndp, vap))
990 nfsm_reply(0);
991 vp = ndp->ni_vp;
992 bzero((caddr_t)fhp, sizeof(nfh));
54fb9dc2 993 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
971b93e3
KM
994 if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
995 vput(vp);
996 nfsm_reply(0);
997 }
998 error = VOP_GETATTR(vp, vap, cred);
999 vput(vp);
1000 nfsm_reply(NFSX_FH+NFSX_FATTR);
1001 nfsm_srvfhtom(fhp);
9238aa59 1002 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
e8540f59 1003 nfsm_srvfillattr;
971b93e3
KM
1004 return (error);
1005nfsmout:
1006 VOP_ABORTOP(ndp);
639383fa
KM
1007 if (ndp->ni_dvp == ndp->ni_vp)
1008 vrele(ndp->ni_dvp);
1009 else
1010 vput(ndp->ni_dvp);
66955caf
KM
1011 if (ndp->ni_vp)
1012 vrele(ndp->ni_vp);
971b93e3
KM
1013 return (error);
1014}
1015
1016/*
1017 * nfs rmdir service
1018 */
e8540f59 1019nfsrv_rmdir(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
1020 struct mbuf *mrep, *md, **mrq;
1021 caddr_t dpos;
1022 struct ucred *cred;
e8540f59
KM
1023 u_long xid;
1024 int *repstat;
971b93e3 1025{
ffe6f482
KM
1026 struct nameidata nami;
1027 register struct nameidata *ndp = &nami;
0bd503ad
KM
1028 register u_long *p;
1029 register long t1;
1030 caddr_t bpos;
1031 int error = 0;
1032 char *cp2;
e8540f59 1033 struct mbuf *mb, *mreq;
971b93e3
KM
1034 struct vnode *vp;
1035 nfsv2fh_t nfh;
1036 fhandle_t *fhp;
1037 long len;
1038
ffe6f482 1039 ndinit(ndp);
971b93e3
KM
1040 fhp = &nfh.fh_generic;
1041 nfsm_srvmtofh(fhp);
1042 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
1043 ndp->ni_cred = cred;
1044 ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
971b93e3
KM
1045 if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
1046 nfsm_reply(0);
1047 vp = ndp->ni_vp;
1048 if (vp->v_type != VDIR) {
1049 error = ENOTDIR;
1050 goto out;
1051 }
1052 /*
1053 * No rmdir "." please.
1054 */
1055 if (ndp->ni_dvp == vp) {
1056 error = EINVAL;
1057 goto out;
1058 }
1059 /*
1060 * Don't unlink a mounted file.
1061 */
1062 if (vp->v_flag & VROOT)
1063 error = EBUSY;
1064out:
66955caf 1065 if (!error) {
971b93e3 1066 error = VOP_RMDIR(ndp);
66955caf
KM
1067 } else {
1068 VOP_ABORTOP(ndp);
639383fa
KM
1069 if (ndp->ni_dvp == ndp->ni_vp)
1070 vrele(ndp->ni_dvp);
1071 else
1072 vput(ndp->ni_dvp);
66955caf
KM
1073 vput(vp);
1074 }
971b93e3
KM
1075 nfsm_reply(0);
1076 nfsm_srvdone;
1077}
1078
1079/*
1080 * nfs readdir service
1081 * - mallocs what it thinks is enough to read
f0f1cbaa 1082 * count rounded up to a multiple of DIRBLKSIZ <= NFS_MAXREADDIR
971b93e3 1083 * - calls VOP_READDIR()
732aefe9 1084 * - loops around building the reply
36c3043b
KM
1085 * if the output generated exceeds count break out of loop
1086 * The nfsm_clget macro is used here so that the reply will be packed
1087 * tightly in mbuf clusters.
971b93e3 1088 * - it only knows that it has encountered eof when the VOP_READDIR()
36c3043b 1089 * reads nothing
971b93e3 1090 * - as such one readdir rpc will return eof false although you are there
36c3043b 1091 * and then the next will return eof
971b93e3 1092 * - it trims out records with d_ino == 0
36c3043b
KM
1093 * this doesn't matter for Unix clients, but they might confuse clients
1094 * for other os'.
971b93e3 1095 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
36c3043b
KM
1096 * than requested, but this may not apply to all filesystems. For
1097 * example, client NFS does not { although it is never remote mounted
1098 * anyhow }
971b93e3 1099 * PS: The NFS protocol spec. does not clarify what the "count" byte
36c3043b
KM
1100 * argument is a count of.. just name strings and file id's or the
1101 * entire reply rpc or ...
1102 * I tried just file name and id sizes and it confused the Sun client,
1103 * so I am using the full rpc size now. The "paranoia.." comment refers
1104 * to including the status longwords that are not a part of the dir.
1105 * "entry" structures, but are in the rpc.
971b93e3 1106 */
e8540f59 1107nfsrv_readdir(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
1108 struct mbuf **mrq;
1109 struct mbuf *mrep, *md;
1110 caddr_t dpos;
1111 struct ucred *cred;
1112 u_long xid;
e8540f59 1113 int *repstat;
971b93e3
KM
1114{
1115 register char *bp, *be;
1116 register struct mbuf *mp;
1117 register struct direct *dp;
0bd503ad
KM
1118 register caddr_t cp;
1119 register u_long *p;
1120 register long t1;
1121 caddr_t bpos;
1122 int error = 0;
1123 char *cp2;
e8540f59 1124 struct mbuf *mb, *mb2, *mreq;
971b93e3
KM
1125 char *cpos, *cend;
1126 int len, nlen, rem, xfer, tsiz, i;
1127 struct vnode *vp;
1128 struct mbuf *mp2, *mp3;
1129 nfsv2fh_t nfh;
1130 fhandle_t *fhp;
1131 struct uio io;
1132 struct iovec iv;
e49b1a6c 1133 int siz, cnt, fullsiz, eofflag;
971b93e3
KM
1134 u_long on;
1135 char *rbuf;
1136 off_t off, toff;
1137
1138 fhp = &nfh.fh_generic;
1139 nfsm_srvmtofh(fhp);
1140 nfsm_disect(p, u_long *, 2*NFSX_UNSIGNED);
1141 toff = fxdr_unsigned(off_t, *p++);
1142 off = (toff & ~(DIRBLKSIZ-1));
1143 on = (toff & (DIRBLKSIZ-1));
1144 cnt = fxdr_unsigned(int, *p);
f0f1cbaa
KM
1145 siz = ((cnt+DIRBLKSIZ-1) & ~(DIRBLKSIZ-1));
1146 if (cnt > NFS_MAXREADDIR)
1147 siz = NFS_MAXREADDIR;
971b93e3
KM
1148 fullsiz = siz;
1149 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
1150 nfsm_reply(0);
24ed1a73 1151 if (error = nfsrv_access(vp, VEXEC, cred)) {
971b93e3
KM
1152 vput(vp);
1153 nfsm_reply(0);
1154 }
1155 VOP_UNLOCK(vp);
1156 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
1157again:
1158 iv.iov_base = rbuf;
1159 iv.iov_len = fullsiz;
1160 io.uio_iov = &iv;
1161 io.uio_iovcnt = 1;
1162 io.uio_offset = off;
1163 io.uio_resid = fullsiz;
1164 io.uio_segflg = UIO_SYSSPACE;
1165 io.uio_rw = UIO_READ;
e49b1a6c 1166 error = VOP_READDIR(vp, &io, cred, &eofflag);
e9843ca3 1167 off = io.uio_offset;
971b93e3
KM
1168 if (error) {
1169 vrele(vp);
1170 free((caddr_t)rbuf, M_TEMP);
1171 nfsm_reply(0);
1172 }
1173 if (io.uio_resid) {
1174 siz -= io.uio_resid;
1175
1176 /*
1177 * If nothing read, return eof
1178 * rpc reply
1179 */
1180 if (siz == 0) {
1181 vrele(vp);
1182 nfsm_reply(2*NFSX_UNSIGNED);
1183 nfsm_build(p, u_long *, 2*NFSX_UNSIGNED);
1184 *p++ = nfs_false;
1185 *p = nfs_true;
1186 FREE((caddr_t)rbuf, M_TEMP);
1187 return (0);
1188 }
1189 }
732aefe9 1190
971b93e3
KM
1191 /*
1192 * Check for degenerate cases of nothing useful read.
732aefe9 1193 * If so go try again
971b93e3 1194 */
732aefe9
KM
1195 cpos = rbuf + on;
1196 cend = rbuf + siz;
1197 dp = (struct direct *)cpos;
1198 while (cpos < cend && dp->d_ino == 0) {
1199 cpos += dp->d_reclen;
1200 dp = (struct direct *)cpos;
1201 }
1202 if (cpos >= cend) {
971b93e3
KM
1203 toff = off;
1204 siz = fullsiz;
1205 on = 0;
1206 goto again;
1207 }
732aefe9
KM
1208
1209 cpos = rbuf + on;
1210 cend = rbuf + siz;
1211 dp = (struct direct *)cpos;
971b93e3 1212 vrele(vp);
36c3043b 1213 len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */
971b93e3
KM
1214 bp = be = (caddr_t)0;
1215 mp3 = (struct mbuf *)0;
1216 nfsm_reply(siz);
1217
1218 /* Loop through the records and build reply */
1219 while (cpos < cend) {
1220 if (dp->d_ino != 0) {
1221 nlen = dp->d_namlen;
1222 rem = nfsm_rndup(nlen)-nlen;
36c3043b 1223
971b93e3
KM
1224 /*
1225 * As noted above, the NFS spec. is not clear about what
1226 * should be included in "count" as totalled up here in
1227 * "len".
1228 */
1229 len += (4*NFSX_UNSIGNED+nlen+rem);
f0f1cbaa
KM
1230 if (len > cnt) {
1231 eofflag = 0;
971b93e3 1232 break;
f0f1cbaa 1233 }
36c3043b 1234
971b93e3
KM
1235 /* Build the directory record xdr from the direct entry */
1236 nfsm_clget;
1237 *p = nfs_true;
1238 bp += NFSX_UNSIGNED;
1239 nfsm_clget;
1240 *p = txdr_unsigned(dp->d_ino);
1241 bp += NFSX_UNSIGNED;
1242 nfsm_clget;
1243 *p = txdr_unsigned(nlen);
1244 bp += NFSX_UNSIGNED;
36c3043b 1245
971b93e3
KM
1246 /* And loop arround copying the name */
1247 xfer = nlen;
1248 cp = dp->d_name;
1249 while (xfer > 0) {
1250 nfsm_clget;
1251 if ((bp+xfer) > be)
1252 tsiz = be-bp;
1253 else
1254 tsiz = xfer;
1255 bcopy(cp, bp, tsiz);
1256 bp += tsiz;
1257 xfer -= tsiz;
1258 if (xfer > 0)
1259 cp += tsiz;
1260 }
1261 /* And null pad to a long boundary */
1262 for (i = 0; i < rem; i++)
1263 *bp++ = '\0';
1264 nfsm_clget;
36c3043b 1265
971b93e3
KM
1266 /* Finish off the record */
1267 toff += dp->d_reclen;
1268 *p = txdr_unsigned(toff);
1269 bp += NFSX_UNSIGNED;
1270 } else
1271 toff += dp->d_reclen;
1272 cpos += dp->d_reclen;
1273 dp = (struct direct *)cpos;
1274 }
1275 nfsm_clget;
1276 *p = nfs_false;
1277 bp += NFSX_UNSIGNED;
1278 nfsm_clget;
e49b1a6c
KM
1279 if (eofflag)
1280 *p = nfs_true;
1281 else
1282 *p = nfs_false;
971b93e3
KM
1283 bp += NFSX_UNSIGNED;
1284 if (bp < be)
1285 mp->m_len = bp-mtod(mp, caddr_t);
1286 mb->m_next = mp3;
1287 FREE(rbuf, M_TEMP);
1288 nfsm_srvdone;
1289}
1290
1291/*
1292 * nfs statfs service
1293 */
e8540f59 1294nfsrv_statfs(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
1295 struct mbuf **mrq;
1296 struct mbuf *mrep, *md;
1297 caddr_t dpos;
1298 struct ucred *cred;
1299 u_long xid;
e8540f59 1300 int *repstat;
971b93e3
KM
1301{
1302 register struct statfs *sf;
9238aa59 1303 register struct nfsv2_statfs *sfp;
0bd503ad
KM
1304 register u_long *p;
1305 register long t1;
1306 caddr_t bpos;
1307 int error = 0;
1308 char *cp2;
e8540f59 1309 struct mbuf *mb, *mb2, *mreq;
971b93e3
KM
1310 struct vnode *vp;
1311 nfsv2fh_t nfh;
1312 fhandle_t *fhp;
1313 struct statfs statfs;
1314
1315 fhp = &nfh.fh_generic;
1316 nfsm_srvmtofh(fhp);
1317 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
1318 nfsm_reply(0);
1319 sf = &statfs;
1320 error = VFS_STATFS(vp->v_mount, sf);
1321 vput(vp);
1322 nfsm_reply(NFSX_STATFS);
9238aa59 1323 nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS);
b28c3bcc 1324 sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
9238aa59
RM
1325 sfp->sf_bsize = txdr_unsigned(sf->f_fsize);
1326 sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
1327 sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
1328 sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
971b93e3
KM
1329 nfsm_srvdone;
1330}
1331
1332/*
1333 * Null operation, used by clients to ping server
1334 */
0bd503ad 1335/* ARGSUSED */
e8540f59 1336nfsrv_null(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
1337 struct mbuf **mrq;
1338 struct mbuf *mrep, *md;
1339 caddr_t dpos;
1340 struct ucred *cred;
1341 u_long xid;
e8540f59 1342 int *repstat;
971b93e3 1343{
0bd503ad
KM
1344 caddr_t bpos;
1345 int error = 0;
e8540f59 1346 struct mbuf *mb, *mreq;
971b93e3
KM
1347
1348 error = VNOVAL;
1349 nfsm_reply(0);
0bd503ad 1350 return (error);
971b93e3
KM
1351}
1352
1353/*
1354 * No operation, used for obsolete procedures
1355 */
0bd503ad 1356/* ARGSUSED */
e8540f59 1357nfsrv_noop(mrep, md, dpos, cred, xid, mrq, repstat)
971b93e3
KM
1358 struct mbuf **mrq;
1359 struct mbuf *mrep, *md;
1360 caddr_t dpos;
1361 struct ucred *cred;
1362 u_long xid;
e8540f59 1363 int *repstat;
971b93e3 1364{
0bd503ad
KM
1365 caddr_t bpos;
1366 int error = 0;
e8540f59 1367 struct mbuf *mb, *mreq;
971b93e3
KM
1368
1369 error = EPROCUNAVAIL;
1370 nfsm_reply(0);
0bd503ad 1371 return (error);
971b93e3 1372}
36c3043b 1373
24ed1a73
KM
1374/*
1375 * Perform access checking for vnodes obtained from file handles that would
1376 * refer to files already opened by a Unix client. You cannot just use
1377 * vn_writechk() and VOP_ACCESS() for two reasons.
54fb9dc2 1378 * 1 - You must check for MNT_EXRDONLY as well as MNT_RDONLY for the write case
24ed1a73
KM
1379 * 2 - The owner is to be given access irrespective of mode bits so that
1380 * processes that chmod after opening a file don't break. I don't like
1381 * this because it opens a security hole, but since the nfs server opens
1382 * a security hole the size of a barn door anyhow, what the heck.
1383 */
1384nfsrv_access(vp, flags, cred)
1385 register struct vnode *vp;
1386 int flags;
1387 register struct ucred *cred;
1388{
1389 struct vattr vattr;
1390 int error;
1391 if (flags & VWRITE) {
54fb9dc2 1392 /* Just vn_writechk() changed to check MNT_EXRDONLY */
24ed1a73
KM
1393 /*
1394 * Disallow write attempts on read-only file systems;
1395 * unless the file is a socket or a block or character
1396 * device resident on the file system.
1397 */
fef23149
KM
1398 if (vp->v_mount->mnt_flag & (MNT_RDONLY | MNT_EXRDONLY)) {
1399 switch (vp->v_type) {
1400 case VREG: case VDIR: case VLNK:
24ed1a73 1401 return (EROFS);
fef23149
KM
1402 }
1403 }
24ed1a73
KM
1404 /*
1405 * If there's shared text associated with
1406 * the inode, try to free it up once. If
1407 * we fail, we can't allow writing.
1408 */
8986c97c 1409 if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
24ed1a73 1410 return (ETXTBSY);
24ed1a73 1411 }
fef23149
KM
1412 if (error = VOP_GETATTR(vp, &vattr, cred))
1413 return (error);
1414 if ((error = VOP_ACCESS(vp, flags, cred)) &&
1415 cred->cr_uid != vattr.va_uid)
1416 return (error);
1417 return (0);
24ed1a73 1418}