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