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