nfs_vfree prototype changed for vn_if
[unix-history] / usr / src / sys / nfs / nfs_serv.c
... / ...
CommitLineData
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 * %sccs.include.redist.c%
9 *
10 * @(#)nfs_serv.c 7.51 (Berkeley) %G%
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
18 * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
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
22 * on a bad rpc or similar and do not do any vrele() or vput()'s
23 *
24 * - the nfsm_reply() macro generates an nfs rpc reply with the nfs
25 * error number iff error != 0 whereas
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.
29 */
30
31#include <sys/param.h>
32#include <sys/proc.h>
33#include <sys/file.h>
34#include <sys/namei.h>
35#include <sys/vnode.h>
36#include <sys/mount.h>
37#include <sys/mbuf.h>
38#include <sys/dirent.h>
39
40#include <vm/vm.h>
41
42#include <ufs/ufs/quota.h> /* XXX - for ufid */
43#include <ufs/ufs/inode.h> /* XXX - for ufid */
44
45#include <nfs/nfsv2.h>
46#include <nfs/rpcv2.h>
47#include <nfs/nfs.h>
48#include <nfs/xdr_subs.h>
49#include <nfs/nfsm_subs.h>
50#include <nfs/nqnfs.h>
51
52/* Defs */
53#define TRUE 1
54#define FALSE 0
55
56/* Global vars */
57extern u_long nfs_procids[NFS_NPROCS];
58extern u_long nfs_xdrneg1;
59extern u_long nfs_false, nfs_true;
60nfstype nfs_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
61 NFCHR, NFNON };
62
63/*
64 * nfs getattr service
65 */
66nfsrv_getattr(nfsd, mrep, md, dpos, cred, nam, mrq)
67 struct nfsd *nfsd;
68 struct mbuf *mrep, *md;
69 caddr_t dpos;
70 struct ucred *cred;
71 struct mbuf *nam, **mrq;
72{
73 USES_VOP_GETATTR;
74 register struct nfsv2_fattr *fp;
75 struct vattr va;
76 register struct vattr *vap = &va;
77 struct vnode *vp;
78 nfsv2fh_t nfh;
79 fhandle_t *fhp;
80 register u_long *tl;
81 register long t1;
82 caddr_t bpos;
83 int error = 0, rdonly, cache;
84 char *cp2;
85 struct mbuf *mb, *mb2, *mreq;
86 u_quad_t frev;
87
88 fhp = &nfh.fh_generic;
89 nfsm_srvmtofh(fhp);
90 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
91 nfsm_reply(0);
92 nqsrv_getl(vp, NQL_READ);
93 error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
94 vput(vp);
95 nfsm_reply(NFSX_FATTR);
96 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
97 nfsm_srvfillattr;
98 nfsm_srvdone;
99}
100
101/*
102 * nfs setattr service
103 */
104nfsrv_setattr(nfsd, mrep, md, dpos, cred, nam, mrq)
105 struct nfsd *nfsd;
106 struct mbuf *mrep, *md;
107 caddr_t dpos;
108 struct ucred *cred;
109 struct mbuf *nam, **mrq;
110{
111 USES_VOP_GETATTR;
112 USES_VOP_SETATTR;
113 struct vattr va;
114 register struct vattr *vap = &va;
115 register struct nfsv2_sattr *sp;
116 register struct nfsv2_fattr *fp;
117 struct vnode *vp;
118 nfsv2fh_t nfh;
119 fhandle_t *fhp;
120 register u_long *tl;
121 register long t1;
122 caddr_t bpos;
123 int error = 0, rdonly, cache, duration2, cache2;
124 char *cp2;
125 struct mbuf *mb, *mb2, *mreq;
126 u_quad_t frev, frev2;
127
128 fhp = &nfh.fh_generic;
129 nfsm_srvmtofh(fhp);
130 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR);
131 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
132 nfsm_reply(0);
133 nqsrv_getl(vp, NQL_WRITE);
134 if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp))
135 goto out;
136 VATTR_NULL(vap);
137 /*
138 * Nah nah nah nah na nah
139 * There is a bug in the Sun client that puts 0xffff in the mode
140 * field of sattr when it should put in 0xffffffff. The u_short
141 * doesn't sign extend.
142 * --> check the low order 2 bytes for 0xffff
143 */
144 if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
145 vap->va_mode = nfstov_mode(sp->sa_mode);
146 if (sp->sa_uid != nfs_xdrneg1)
147 vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
148 if (sp->sa_gid != nfs_xdrneg1)
149 vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
150 if (sp->sa_size != nfs_xdrneg1)
151 vap->va_size = fxdr_unsigned(u_long, sp->sa_size);
152 /*
153 * The usec field of sa_atime is overloaded with the va_flags field
154 * for 4.4BSD clients. Hopefully other clients always set both the
155 * sec and usec fields to -1 when not setting the atime.
156 */
157 if (sp->sa_atime.tv_sec != nfs_xdrneg1) {
158 vap->va_atime.tv_sec = fxdr_unsigned(long, sp->sa_atime.tv_sec);
159 vap->va_atime.tv_usec = 0;
160 }
161 if (sp->sa_atime.tv_usec != nfs_xdrneg1)
162 vap->va_flags = fxdr_unsigned(u_long, sp->sa_atime.tv_usec);
163 if (sp->sa_mtime.tv_sec != nfs_xdrneg1)
164 fxdr_time(&sp->sa_mtime, &vap->va_mtime);
165 if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) {
166 vput(vp);
167 nfsm_reply(0);
168 }
169 error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
170out:
171 vput(vp);
172 nfsm_reply(NFSX_FATTR + 2*NFSX_UNSIGNED);
173 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
174 nfsm_srvfillattr;
175 if (nfsd->nd_nqlflag != NQL_NOVAL) {
176 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
177 txdr_hyper(&frev2, tl);
178 }
179 nfsm_srvdone;
180}
181
182/*
183 * nfs lookup rpc
184 */
185nfsrv_lookup(nfsd, mrep, md, dpos, cred, nam, mrq)
186 struct nfsd *nfsd;
187 struct mbuf *mrep, *md;
188 caddr_t dpos;
189 struct ucred *cred;
190 struct mbuf *nam, **mrq;
191{
192 USES_VOP_GETATTR;
193 register struct nfsv2_fattr *fp;
194 struct nameidata nd;
195 struct vnode *vp;
196 nfsv2fh_t nfh;
197 fhandle_t *fhp;
198 register caddr_t cp;
199 register u_long *tl;
200 register long t1;
201 caddr_t bpos;
202 int error = 0, lflag = 0, rdonly, cache, duration2, cache2, len;
203 char *cp2;
204 struct mbuf *mb, *mb2, *mreq;
205 struct vattr va, *vap = &va;
206 u_quad_t frev, frev2;
207
208 fhp = &nfh.fh_generic;
209 if (nfsd->nd_nqlflag != NQL_NOVAL) {
210 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
211 if (*tl) {
212 lflag = fxdr_unsigned(int, *tl);
213 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
214 duration2 = fxdr_unsigned(int, *tl);
215 }
216 }
217 nfsm_srvmtofh(fhp);
218 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
219 nd.ni_cnd.cn_cred = cred;
220 nd.ni_cnd.cn_nameiop = LOOKUP;
221 nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART;
222 if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
223 nfsd->nd_procp))
224 nfsm_reply(0);
225 nqsrv_getl(nd.ni_startdir, NQL_READ);
226 vrele(nd.ni_startdir);
227 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
228 vp = nd.ni_vp;
229 bzero((caddr_t)fhp, sizeof(nfh));
230 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
231 if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
232 vput(vp);
233 nfsm_reply(0);
234 }
235 if (lflag)
236 (void) nqsrv_getlease(vp, &duration2, lflag, nfsd,
237 nam, &cache2, &frev2, cred);
238 error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
239 vput(vp);
240 nfsm_reply(NFSX_FH + NFSX_FATTR + 5*NFSX_UNSIGNED);
241 if (nfsd->nd_nqlflag != NQL_NOVAL) {
242 if (lflag) {
243 nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED);
244 *tl++ = txdr_unsigned(lflag);
245 *tl++ = txdr_unsigned(cache2);
246 *tl++ = txdr_unsigned(duration2);
247 txdr_hyper(&frev2, tl);
248 } else {
249 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
250 *tl = 0;
251 }
252 }
253 nfsm_srvfhtom(fhp);
254 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
255 nfsm_srvfillattr;
256 nfsm_srvdone;
257}
258
259/*
260 * nfs readlink service
261 */
262nfsrv_readlink(nfsd, mrep, md, dpos, cred, nam, mrq)
263 struct nfsd *nfsd;
264 struct mbuf *mrep, *md;
265 caddr_t dpos;
266 struct ucred *cred;
267 struct mbuf *nam, **mrq;
268{
269 USES_VOP_READLINK;
270 struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
271 register struct iovec *ivp = iv;
272 register struct mbuf *mp;
273 register u_long *tl;
274 register long t1;
275 caddr_t bpos;
276 int error = 0, rdonly, cache, i, tlen, len;
277 char *cp2;
278 struct mbuf *mb, *mb2, *mp2, *mp3, *mreq;
279 struct vnode *vp;
280 nfsv2fh_t nfh;
281 fhandle_t *fhp;
282 struct uio io, *uiop = &io;
283 u_quad_t frev;
284
285 fhp = &nfh.fh_generic;
286 nfsm_srvmtofh(fhp);
287 len = 0;
288 i = 0;
289 while (len < NFS_MAXPATHLEN) {
290 MGET(mp, M_WAIT, MT_DATA);
291 MCLGET(mp, M_WAIT);
292 mp->m_len = NFSMSIZ(mp);
293 if (len == 0)
294 mp3 = mp2 = mp;
295 else {
296 mp2->m_next = mp;
297 mp2 = mp;
298 }
299 if ((len+mp->m_len) > NFS_MAXPATHLEN) {
300 mp->m_len = NFS_MAXPATHLEN-len;
301 len = NFS_MAXPATHLEN;
302 } else
303 len += mp->m_len;
304 ivp->iov_base = mtod(mp, caddr_t);
305 ivp->iov_len = mp->m_len;
306 i++;
307 ivp++;
308 }
309 uiop->uio_iov = iv;
310 uiop->uio_iovcnt = i;
311 uiop->uio_offset = 0;
312 uiop->uio_resid = len;
313 uiop->uio_rw = UIO_READ;
314 uiop->uio_segflg = UIO_SYSSPACE;
315 uiop->uio_procp = (struct proc *)0;
316 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) {
317 m_freem(mp3);
318 nfsm_reply(0);
319 }
320 if (vp->v_type != VLNK) {
321 error = EINVAL;
322 goto out;
323 }
324 nqsrv_getl(vp, NQL_READ);
325 error = VOP_READLINK(vp, uiop, cred);
326out:
327 vput(vp);
328 if (error)
329 m_freem(mp3);
330 nfsm_reply(NFSX_UNSIGNED);
331 if (uiop->uio_resid > 0) {
332 len -= uiop->uio_resid;
333 tlen = nfsm_rndup(len);
334 nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
335 }
336 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
337 *tl = txdr_unsigned(len);
338 mb->m_next = mp3;
339 nfsm_srvdone;
340}
341
342/*
343 * nfs read service
344 */
345nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq)
346 struct nfsd *nfsd;
347 struct mbuf *mrep, *md;
348 caddr_t dpos;
349 struct ucred *cred;
350 struct mbuf *nam, **mrq;
351{
352 USES_VOP_GETATTR;
353 USES_VOP_READ;
354 register struct iovec *iv;
355 struct iovec *iv2;
356 register struct mbuf *m;
357 register struct nfsv2_fattr *fp;
358 register u_long *tl;
359 register long t1;
360 caddr_t bpos;
361 int error = 0, rdonly, cache, i, cnt, len, left, siz, tlen;
362 char *cp2;
363 struct mbuf *mb, *mb2, *mreq;
364 struct mbuf *m2;
365 struct vnode *vp;
366 nfsv2fh_t nfh;
367 fhandle_t *fhp;
368 struct uio io, *uiop = &io;
369 struct vattr va, *vap = &va;
370 off_t off;
371 u_quad_t frev;
372
373 fhp = &nfh.fh_generic;
374 nfsm_srvmtofh(fhp);
375 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
376 off = fxdr_unsigned(off_t, *tl);
377 nfsm_srvstrsiz(cnt, NFS_MAXDATA);
378 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
379 nfsm_reply(0);
380 nqsrv_getl(vp, NQL_READ);
381 if (error = nfsrv_access(vp, VREAD | VEXEC, cred, rdonly, nfsd->nd_procp)) {
382 vput(vp);
383 nfsm_reply(0);
384 }
385 if (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp)) {
386 vput(vp);
387 nfsm_reply(0);
388 }
389 if (off >= vap->va_size)
390 cnt = 0;
391 else if ((off + cnt) > vap->va_size)
392 cnt = nfsm_rndup(vap->va_size - off);
393 nfsm_reply(NFSX_FATTR+NFSX_UNSIGNED+nfsm_rndup(cnt));
394 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
395 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
396 len = left = cnt;
397 if (cnt > 0) {
398 /*
399 * Generate the mbuf list with the uio_iov ref. to it.
400 */
401 i = 0;
402 m = m2 = mb;
403 MALLOC(iv, struct iovec *,
404 ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec),
405 M_TEMP, M_WAITOK);
406 iv2 = iv;
407 while (left > 0) {
408 siz = MIN(M_TRAILINGSPACE(m), left);
409 if (siz > 0) {
410 m->m_len += siz;
411 iv->iov_base = bpos;
412 iv->iov_len = siz;
413 iv++;
414 i++;
415 left -= siz;
416 }
417 if (left > 0) {
418 MGET(m, M_WAIT, MT_DATA);
419 MCLGET(m, M_WAIT);
420 m->m_len = 0;
421 m2->m_next = m;
422 m2 = m;
423 bpos = mtod(m, caddr_t);
424 }
425 }
426 uiop->uio_iov = iv2;
427 uiop->uio_iovcnt = i;
428 uiop->uio_offset = off;
429 uiop->uio_resid = cnt;
430 uiop->uio_rw = UIO_READ;
431 uiop->uio_segflg = UIO_SYSSPACE;
432 error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
433 off = uiop->uio_offset;
434 FREE((caddr_t)iv2, M_TEMP);
435 if (error || (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp))) {
436 m_freem(mreq);
437 vput(vp);
438 nfsm_reply(0);
439 }
440 } else
441 uiop->uio_resid = 0;
442 vput(vp);
443 nfsm_srvfillattr;
444 len -= uiop->uio_resid;
445 tlen = nfsm_rndup(len);
446 if (cnt != tlen || tlen != len)
447 nfsm_adj(mb, cnt-tlen, tlen-len);
448 *tl = txdr_unsigned(len);
449 nfsm_srvdone;
450}
451
452/*
453 * nfs write service
454 */
455nfsrv_write(nfsd, mrep, md, dpos, cred, nam, mrq)
456 struct nfsd *nfsd;
457 struct mbuf *mrep, *md;
458 caddr_t dpos;
459 struct ucred *cred;
460 struct mbuf *nam, **mrq;
461{
462 USES_VOP_GETATTR;
463 USES_VOP_WRITE;
464 register struct iovec *ivp;
465 register struct mbuf *mp;
466 register struct nfsv2_fattr *fp;
467 struct iovec iv[NFS_MAXIOVEC];
468 struct vattr va;
469 register struct vattr *vap = &va;
470 register u_long *tl;
471 register long t1;
472 caddr_t bpos;
473 int error = 0, rdonly, cache, siz, len, xfer;
474 char *cp2;
475 struct mbuf *mb, *mb2, *mreq;
476 struct vnode *vp;
477 nfsv2fh_t nfh;
478 fhandle_t *fhp;
479 struct uio io, *uiop = &io;
480 off_t off;
481 u_quad_t frev;
482
483 fhp = &nfh.fh_generic;
484 nfsm_srvmtofh(fhp);
485 nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
486 off = fxdr_unsigned(off_t, *++tl);
487 tl += 2;
488 len = fxdr_unsigned(long, *tl);
489 if (len > NFS_MAXDATA || len <= 0) {
490 error = EBADRPC;
491 nfsm_reply(0);
492 }
493 if (dpos == (mtod(md, caddr_t)+md->m_len)) {
494 mp = md->m_next;
495 if (mp == NULL) {
496 error = EBADRPC;
497 nfsm_reply(0);
498 }
499 } else {
500 mp = md;
501 siz = dpos-mtod(mp, caddr_t);
502 mp->m_len -= siz;
503 NFSMADV(mp, siz);
504 }
505 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
506 nfsm_reply(0);
507 nqsrv_getl(vp, NQL_WRITE);
508 if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) {
509 vput(vp);
510 nfsm_reply(0);
511 }
512 uiop->uio_resid = 0;
513 uiop->uio_rw = UIO_WRITE;
514 uiop->uio_segflg = UIO_SYSSPACE;
515 uiop->uio_procp = (struct proc *)0;
516 /*
517 * Do up to NFS_MAXIOVEC mbufs of write each iteration of the
518 * loop until done.
519 */
520 while (len > 0 && uiop->uio_resid == 0) {
521 ivp = iv;
522 siz = 0;
523 uiop->uio_iov = ivp;
524 uiop->uio_iovcnt = 0;
525 uiop->uio_offset = off;
526 while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) {
527 ivp->iov_base = mtod(mp, caddr_t);
528 if (len < mp->m_len)
529 ivp->iov_len = xfer = len;
530 else
531 ivp->iov_len = xfer = mp->m_len;
532#ifdef notdef
533 /* Not Yet .. */
534 if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0)
535 ivp->iov_op = NULL; /* what should it be ?? */
536 else
537 ivp->iov_op = NULL;
538#endif
539 uiop->uio_iovcnt++;
540 ivp++;
541 len -= xfer;
542 siz += xfer;
543 mp = mp->m_next;
544 }
545 if (len > 0 && mp == NULL) {
546 error = EBADRPC;
547 vput(vp);
548 nfsm_reply(0);
549 }
550 uiop->uio_resid = siz;
551 if (error = VOP_WRITE(vp, uiop, IO_SYNC | IO_NODELOCKED,
552 cred)) {
553 vput(vp);
554 nfsm_reply(0);
555 }
556 off = uiop->uio_offset;
557 }
558 error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
559 vput(vp);
560 nfsm_reply(NFSX_FATTR);
561 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
562 nfsm_srvfillattr;
563 if (nfsd->nd_nqlflag != NQL_NOVAL) {
564 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
565 txdr_hyper(&vap->va_filerev, tl);
566 }
567 nfsm_srvdone;
568}
569
570/*
571 * nfs create service
572 * now does a truncate to 0 length via. setattr if it already exists
573 */
574nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq)
575 struct nfsd *nfsd;
576 struct mbuf *mrep, *md;
577 caddr_t dpos;
578 struct ucred *cred;
579 struct mbuf *nam, **mrq;
580{
581 USES_VOP_ABORTOP;
582 USES_VOP_CREATE;
583 USES_VOP_GETATTR;
584 USES_VOP_MKNOD;
585 USES_VOP_SETATTR;
586 register struct nfsv2_fattr *fp;
587 struct vattr va;
588 register struct vattr *vap = &va;
589 struct nameidata nd;
590 register caddr_t cp;
591 register u_long *tl;
592 register long t1;
593 caddr_t bpos;
594 int error = 0, rdev, cache, len;
595 char *cp2;
596 struct mbuf *mb, *mb2, *mreq;
597 struct vnode *vp;
598 nfsv2fh_t nfh;
599 fhandle_t *fhp;
600 u_quad_t frev;
601
602 nd.ni_cnd.cn_nameiop = 0;
603 fhp = &nfh.fh_generic;
604 nfsm_srvmtofh(fhp);
605 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
606 nd.ni_cnd.cn_cred = cred;
607 nd.ni_cnd.cn_nameiop = CREATE;
608 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
609 if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
610 nfsd->nd_procp))
611 nfsm_reply(0);
612 VATTR_NULL(vap);
613 nfsm_dissect(tl, u_long *, NFSX_SATTR);
614 /*
615 * Iff doesn't exist, create it
616 * otherwise just truncate to 0 length
617 * should I set the mode too ??
618 */
619 if (nd.ni_vp == NULL) {
620 vap->va_type = IFTOVT(fxdr_unsigned(u_long, *tl));
621 if (vap->va_type == VNON)
622 vap->va_type = VREG;
623 vap->va_mode = nfstov_mode(*tl);
624 rdev = fxdr_unsigned(long, *(tl+3));
625 if (vap->va_type == VREG || vap->va_type == VSOCK) {
626 p->p_spare[1]--;
627 vrele(nd.ni_startdir);
628 nqsrv_getl(nd.ni_dvp, NQL_WRITE);
629 if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap))
630 nfsm_reply(0);
631 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
632 } else if (vap->va_type == VCHR || vap->va_type == VBLK ||
633 vap->va_type == VFIFO) {
634 if (vap->va_type == VCHR && rdev == 0xffffffff)
635 vap->va_type = VFIFO;
636 if (vap->va_type == VFIFO) {
637#ifndef FIFO
638 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
639 vput(nd.ni_dvp);
640 error = ENXIO;
641 goto out;
642#endif /* FIFO */
643 } else if (error = suser(cred, (u_short *)0)) {
644 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
645 vput(nd.ni_dvp);
646 goto out;
647 } else
648 vap->va_rdev = (dev_t)rdev;
649 nqsrv_getl(nd.ni_dvp, NQL_WRITE);
650 if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) {
651 p->p_spare[1]--;
652 vrele(nd.ni_startdir);
653 nfsm_reply(0);
654 }
655 nd.ni_cnd.cn_nameiop = LOOKUP;
656 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
657 nd.ni_cnd.cn_proc = nfsd->nd_procp;
658 nd.ni_cnd.cn_cred = nfsd->nd_procp->p_ucred;
659 if (error = lookup(&nd)) {
660 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
661 nfsm_reply(0);
662 }
663 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
664 if (nd.ni_cnd.cn_flags & ISSYMLINK) {
665 vrele(nd.ni_dvp);
666 vput(nd.ni_vp);
667 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
668 error = EINVAL;
669 nfsm_reply(0);
670 }
671 } else {
672 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
673 vput(nd.ni_dvp);
674 error = ENXIO;
675 goto out;
676 }
677 vp = nd.ni_vp;
678 } else {
679 p->p_spare[1]--;
680 vrele(nd.ni_startdir);
681 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
682 vp = nd.ni_vp;
683 if (nd.ni_dvp == vp)
684 vrele(nd.ni_dvp);
685 else
686 vput(nd.ni_dvp);
687 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
688 vap->va_size = 0;
689 nqsrv_getl(vp, NQL_WRITE);
690 if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) {
691 vput(vp);
692 nfsm_reply(0);
693 }
694 }
695 bzero((caddr_t)fhp, sizeof(nfh));
696 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
697 if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
698 vput(vp);
699 nfsm_reply(0);
700 }
701 error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
702 vput(vp);
703 nfsm_reply(NFSX_FH+NFSX_FATTR);
704 nfsm_srvfhtom(fhp);
705 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
706 nfsm_srvfillattr;
707 return (error);
708nfsmout:
709 if (nd.ni_cnd.cn_nameiop || nd.ni_cnd.cn_flags)
710 p->p_spare[1]--, vrele(nd.ni_startdir);
711 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
712 if (nd.ni_dvp == nd.ni_vp)
713 vrele(nd.ni_dvp);
714 else
715 vput(nd.ni_dvp);
716 if (nd.ni_vp)
717 vput(nd.ni_vp);
718 return (error);
719
720out:
721 p->p_spare[1]--;
722 vrele(nd.ni_startdir);
723 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
724 nfsm_reply(0);
725}
726
727/*
728 * nfs remove service
729 */
730nfsrv_remove(nfsd, mrep, md, dpos, cred, nam, mrq)
731 struct nfsd *nfsd;
732 struct mbuf *mrep, *md;
733 caddr_t dpos;
734 struct ucred *cred;
735 struct mbuf *nam, **mrq;
736{
737 USES_VOP_ABORTOP;
738 USES_VOP_REMOVE;
739 struct nameidata nd;
740 register u_long *tl;
741 register long t1;
742 caddr_t bpos;
743 int error = 0, cache, len;
744 char *cp2;
745 struct mbuf *mb, *mreq;
746 struct vnode *vp;
747 nfsv2fh_t nfh;
748 fhandle_t *fhp;
749 u_quad_t frev;
750
751 fhp = &nfh.fh_generic;
752 nfsm_srvmtofh(fhp);
753 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
754 nd.ni_cnd.cn_cred = cred;
755 nd.ni_cnd.cn_nameiop = DELETE;
756 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
757 if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
758 nfsd->nd_procp))
759 nfsm_reply(0);
760 vp = nd.ni_vp;
761 if (vp->v_type == VDIR &&
762 (error = suser(cred, (u_short *)0)))
763 goto out;
764 /*
765 * The root of a mounted filesystem cannot be deleted.
766 */
767 if (vp->v_flag & VROOT) {
768 error = EBUSY;
769 goto out;
770 }
771 if (vp->v_flag & VTEXT)
772 (void) vnode_pager_uncache(vp);
773out:
774 if (!error) {
775 nqsrv_getl(nd.ni_dvp, NQL_WRITE);
776 nqsrv_getl(vp, NQL_WRITE);
777 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
778 } else {
779 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
780 if (nd.ni_dvp == vp)
781 vrele(nd.ni_dvp);
782 else
783 vput(nd.ni_dvp);
784 vput(vp);
785 }
786 nfsm_reply(0);
787 nfsm_srvdone;
788}
789
790/*
791 * nfs rename service
792 */
793nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq)
794 struct nfsd *nfsd;
795 struct mbuf *mrep, *md;
796 caddr_t dpos;
797 struct ucred *cred;
798 struct mbuf *nam, **mrq;
799{
800 USES_VOP_ABORTOP;
801 USES_VOP_RENAME;
802 register u_long *tl;
803 register long t1;
804 caddr_t bpos;
805 int error = 0, rdonly, cache, len, len2;
806 char *cp2;
807 struct mbuf *mb, *mreq;
808 struct nameidata fromnd, tond;
809 struct vnode *fvp, *tvp, *tdvp;
810 nfsv2fh_t fnfh, tnfh;
811 fhandle_t *ffhp, *tfhp;
812 u_quad_t frev;
813 uid_t saved_uid;
814
815 ffhp = &fnfh.fh_generic;
816 tfhp = &tnfh.fh_generic;
817 fromnd.ni_cnd.cn_nameiop = 0;
818 tond.ni_cnd.cn_nameiop = 0;
819 nfsm_srvmtofh(ffhp);
820 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
821 /*
822 * Remember our original uid so that we can reset cr_uid before
823 * the second nfs_namei() call, in case it is remapped.
824 */
825 saved_uid = cred->cr_uid;
826 fromnd.ni_cnd.cn_cred = cred;
827 fromnd.ni_cnd.cn_nameiop = DELETE;
828 fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART;
829 if (error = nfs_namei(&fromnd, ffhp, len, nfsd->nd_slp, nam, &md,
830 &dpos, nfsd->nd_procp))
831 nfsm_reply(0);
832 fvp = fromnd.ni_vp;
833 nfsm_srvmtofh(tfhp);
834 nfsm_strsiz(len2, NFS_MAXNAMLEN);
835 cred->cr_uid = saved_uid;
836 tond.ni_cnd.cn_cred = cred;
837 tond.ni_cnd.cn_nameiop = RENAME;
838 tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
839 if (error = nfs_namei(&tond, tfhp, len2, nfsd->nd_slp, nam, &md,
840 &dpos, nfsd->nd_procp)) {
841 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
842 vrele(fromnd.ni_dvp);
843 vrele(fvp);
844 goto out1;
845 }
846 tdvp = tond.ni_dvp;
847 tvp = tond.ni_vp;
848 if (tvp != NULL) {
849 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
850 error = EISDIR;
851 goto out;
852 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
853 error = ENOTDIR;
854 goto out;
855 }
856 if (tvp->v_type == VDIR && tvp->v_mountedhere) {
857 error = EXDEV;
858 goto out;
859 }
860 }
861 if (fvp->v_type == VDIR && fvp->v_mountedhere) {
862 error = EBUSY;
863 goto out;
864 }
865 if (fvp->v_mount != tdvp->v_mount) {
866 error = EXDEV;
867 goto out;
868 }
869 if (fvp == tdvp)
870 error = EINVAL;
871 /*
872 * If source is the same as the destination (that is the
873 * same vnode with the same name in the same directory),
874 * then there is nothing to do.
875 */
876 if (fvp == tvp && fromnd.ni_dvp == tdvp &&
877 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
878 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
879 fromnd.ni_cnd.cn_namelen))
880 error = -1;
881out:
882 if (!error) {
883 nqsrv_getl(fromnd.ni_dvp, NQL_WRITE);
884 nqsrv_getl(tdvp, NQL_WRITE);
885 if (tvp)
886 nqsrv_getl(tvp, NQL_WRITE);
887 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
888 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
889 } else {
890 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
891 if (tdvp == tvp)
892 vrele(tdvp);
893 else
894 vput(tdvp);
895 if (tvp)
896 vput(tvp);
897 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
898 vrele(fromnd.ni_dvp);
899 vrele(fvp);
900 }
901 p->p_spare[1]--;
902 vrele(tond.ni_startdir);
903 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
904out1:
905 p->p_spare[1]--;
906 vrele(fromnd.ni_startdir);
907 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
908 nfsm_reply(0);
909 return (error);
910
911nfsmout:
912 if (tond.ni_cnd.cn_nameiop || tond.ni_cnd.cn_flags) {
913 p->p_spare[1]--;
914 vrele(tond.ni_startdir);
915 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
916 }
917 if (fromnd.ni_cnd.cn_nameiop || fromnd.ni_cnd.cn_flags) {
918 p->p_spare[1]--;
919 vrele(fromnd.ni_startdir);
920 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
921 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
922 vrele(fromnd.ni_dvp);
923 vrele(fvp);
924 }
925 return (error);
926}
927
928/*
929 * nfs link service
930 */
931nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq)
932 struct nfsd *nfsd;
933 struct mbuf *mrep, *md;
934 caddr_t dpos;
935 struct ucred *cred;
936 struct mbuf *nam, **mrq;
937{
938 USES_VOP_ABORTOP;
939 USES_VOP_LINK;
940 struct nameidata nd;
941 register u_long *tl;
942 register long t1;
943 caddr_t bpos;
944 int error = 0, rdonly, cache, len;
945 char *cp2;
946 struct mbuf *mb, *mreq;
947 struct vnode *vp, *xp;
948 nfsv2fh_t nfh, dnfh;
949 fhandle_t *fhp, *dfhp;
950 u_quad_t frev;
951
952 fhp = &nfh.fh_generic;
953 dfhp = &dnfh.fh_generic;
954 nfsm_srvmtofh(fhp);
955 nfsm_srvmtofh(dfhp);
956 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
957 if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
958 nfsm_reply(0);
959 if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0)))
960 goto out1;
961 nd.ni_cnd.cn_cred = cred;
962 nd.ni_cnd.cn_nameiop = CREATE;
963 nd.ni_cnd.cn_flags = LOCKPARENT;
964 if (error = nfs_namei(&nd, dfhp, len, nfsd->nd_slp, nam, &md, &dpos,
965 nfsd->nd_procp))
966 goto out1;
967 xp = nd.ni_vp;
968 if (xp != NULL) {
969 error = EEXIST;
970 goto out;
971 }
972 xp = nd.ni_dvp;
973 if (vp->v_mount != xp->v_mount)
974 error = EXDEV;
975out:
976 if (!error) {
977 nqsrv_getl(vp, NQL_WRITE);
978 nqsrv_getl(xp, NQL_WRITE);
979 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
980 } else {
981 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
982 if (nd.ni_dvp == nd.ni_vp)
983 vrele(nd.ni_dvp);
984 else
985 vput(nd.ni_dvp);
986 if (nd.ni_vp)
987 vrele(nd.ni_vp);
988 }
989out1:
990 vrele(vp);
991 nfsm_reply(0);
992 nfsm_srvdone;
993}
994
995/*
996 * nfs symbolic link service
997 */
998nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq)
999 struct nfsd *nfsd;
1000 struct mbuf *mrep, *md;
1001 caddr_t dpos;
1002 struct ucred *cred;
1003 struct mbuf *nam, **mrq;
1004{
1005 USES_VOP_ABORTOP;
1006 USES_VOP_SYMLINK;
1007 struct vattr va;
1008 struct nameidata nd;
1009 register struct vattr *vap = &va;
1010 register u_long *tl;
1011 register long t1;
1012 struct nfsv2_sattr *sp;
1013 caddr_t bpos;
1014 struct uio io;
1015 struct iovec iv;
1016 int error = 0, rdonly, cache, len, len2;
1017 char *pathcp, *cp2;
1018 struct mbuf *mb, *mreq;
1019 nfsv2fh_t nfh;
1020 fhandle_t *fhp;
1021 u_quad_t frev;
1022
1023 pathcp = (char *)0;
1024 fhp = &nfh.fh_generic;
1025 nfsm_srvmtofh(fhp);
1026 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
1027 nd.ni_cnd.cn_cred = cred;
1028 nd.ni_cnd.cn_nameiop = CREATE;
1029 nd.ni_cnd.cn_flags = LOCKPARENT;
1030 if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
1031 nfsd->nd_procp))
1032 goto out;
1033 nfsm_strsiz(len2, NFS_MAXPATHLEN);
1034 MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK);
1035 iv.iov_base = pathcp;
1036 iv.iov_len = len2;
1037 io.uio_resid = len2;
1038 io.uio_offset = 0;
1039 io.uio_iov = &iv;
1040 io.uio_iovcnt = 1;
1041 io.uio_segflg = UIO_SYSSPACE;
1042 io.uio_rw = UIO_READ;
1043 io.uio_procp = (struct proc *)0;
1044 nfsm_mtouio(&io, len2);
1045 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR);
1046 *(pathcp + len2) = '\0';
1047 if (nd.ni_vp) {
1048 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1049 if (nd.ni_dvp == nd.ni_vp)
1050 vrele(nd.ni_dvp);
1051 else
1052 vput(nd.ni_dvp);
1053 vrele(nd.ni_vp);
1054 error = EEXIST;
1055 goto out;
1056 }
1057 VATTR_NULL(vap);
1058 vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode);
1059 nqsrv_getl(nd.ni_dvp, NQL_WRITE);
1060 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp);
1061out:
1062 if (pathcp)
1063 FREE(pathcp, M_TEMP);
1064 nfsm_reply(0);
1065 return (error);
1066nfsmout:
1067 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1068 if (nd.ni_dvp == nd.ni_vp)
1069 vrele(nd.ni_dvp);
1070 else
1071 vput(nd.ni_dvp);
1072 if (nd.ni_vp)
1073 vrele(nd.ni_vp);
1074 if (pathcp)
1075 FREE(pathcp, M_TEMP);
1076 return (error);
1077}
1078
1079/*
1080 * nfs mkdir service
1081 */
1082nfsrv_mkdir(nfsd, mrep, md, dpos, cred, nam, mrq)
1083 struct nfsd *nfsd;
1084 struct mbuf *mrep, *md;
1085 caddr_t dpos;
1086 struct ucred *cred;
1087 struct mbuf *nam, **mrq;
1088{
1089 USES_VOP_ABORTOP;
1090 USES_VOP_GETATTR;
1091 USES_VOP_MKDIR;
1092 struct vattr va;
1093 register struct vattr *vap = &va;
1094 register struct nfsv2_fattr *fp;
1095 struct nameidata nd;
1096 register caddr_t cp;
1097 register u_long *tl;
1098 register long t1;
1099 caddr_t bpos;
1100 int error = 0, rdonly, cache, len;
1101 char *cp2;
1102 struct mbuf *mb, *mb2, *mreq;
1103 struct vnode *vp;
1104 nfsv2fh_t nfh;
1105 fhandle_t *fhp;
1106 u_quad_t frev;
1107
1108 fhp = &nfh.fh_generic;
1109 nfsm_srvmtofh(fhp);
1110 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
1111 nd.ni_cnd.cn_cred = cred;
1112 nd.ni_cnd.cn_nameiop = CREATE;
1113 nd.ni_cnd.cn_flags = LOCKPARENT;
1114 if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
1115 nfsd->nd_procp))
1116 nfsm_reply(0);
1117 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1118 VATTR_NULL(vap);
1119 vap->va_type = VDIR;
1120 vap->va_mode = nfstov_mode(*tl++);
1121 vp = nd.ni_vp;
1122 if (vp != NULL) {
1123 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1124 if (nd.ni_dvp == vp)
1125 vrele(nd.ni_dvp);
1126 else
1127 vput(nd.ni_dvp);
1128 vrele(vp);
1129 error = EEXIST;
1130 nfsm_reply(0);
1131 }
1132 nqsrv_getl(nd.ni_dvp, NQL_WRITE);
1133 if (error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap))
1134 nfsm_reply(0);
1135 vp = nd.ni_vp;
1136 bzero((caddr_t)fhp, sizeof(nfh));
1137 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1138 if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
1139 vput(vp);
1140 nfsm_reply(0);
1141 }
1142 error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
1143 vput(vp);
1144 nfsm_reply(NFSX_FH+NFSX_FATTR);
1145 nfsm_srvfhtom(fhp);
1146 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
1147 nfsm_srvfillattr;
1148 return (error);
1149nfsmout:
1150 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1151 if (nd.ni_dvp == nd.ni_vp)
1152 vrele(nd.ni_dvp);
1153 else
1154 vput(nd.ni_dvp);
1155 if (nd.ni_vp)
1156 vrele(nd.ni_vp);
1157 return (error);
1158}
1159
1160/*
1161 * nfs rmdir service
1162 */
1163nfsrv_rmdir(nfsd, mrep, md, dpos, cred, nam, mrq)
1164 struct nfsd *nfsd;
1165 struct mbuf *mrep, *md;
1166 caddr_t dpos;
1167 struct ucred *cred;
1168 struct mbuf *nam, **mrq;
1169{
1170 USES_VOP_ABORTOP;
1171 USES_VOP_RMDIR;
1172 register u_long *tl;
1173 register long t1;
1174 caddr_t bpos;
1175 int error = 0, rdonly, cache, len;
1176 char *cp2;
1177 struct mbuf *mb, *mreq;
1178 struct vnode *vp;
1179 nfsv2fh_t nfh;
1180 fhandle_t *fhp;
1181 struct nameidata nd;
1182 u_quad_t frev;
1183
1184 fhp = &nfh.fh_generic;
1185 nfsm_srvmtofh(fhp);
1186 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
1187 nd.ni_cnd.cn_cred = cred;
1188 nd.ni_cnd.cn_nameiop = DELETE;
1189 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1190 if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
1191 nfsd->nd_procp))
1192 nfsm_reply(0);
1193 vp = nd.ni_vp;
1194 if (vp->v_type != VDIR) {
1195 error = ENOTDIR;
1196 goto out;
1197 }
1198 /*
1199 * No rmdir "." please.
1200 */
1201 if (nd.ni_dvp == vp) {
1202 error = EINVAL;
1203 goto out;
1204 }
1205 /*
1206 * The root of a mounted filesystem cannot be deleted.
1207 */
1208 if (vp->v_flag & VROOT)
1209 error = EBUSY;
1210out:
1211 if (!error) {
1212 nqsrv_getl(nd.ni_dvp, NQL_WRITE);
1213 nqsrv_getl(vp, NQL_WRITE);
1214 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1215 } else {
1216 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1217 if (nd.ni_dvp == nd.ni_vp)
1218 vrele(nd.ni_dvp);
1219 else
1220 vput(nd.ni_dvp);
1221 vput(vp);
1222 }
1223 nfsm_reply(0);
1224 nfsm_srvdone;
1225}
1226
1227/*
1228 * nfs readdir service
1229 * - mallocs what it thinks is enough to read
1230 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
1231 * - calls VOP_READDIR()
1232 * - loops around building the reply
1233 * if the output generated exceeds count break out of loop
1234 * The nfsm_clget macro is used here so that the reply will be packed
1235 * tightly in mbuf clusters.
1236 * - it only knows that it has encountered eof when the VOP_READDIR()
1237 * reads nothing
1238 * - as such one readdir rpc will return eof false although you are there
1239 * and then the next will return eof
1240 * - it trims out records with d_fileno == 0
1241 * this doesn't matter for Unix clients, but they might confuse clients
1242 * for other os'.
1243 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
1244 * than requested, but this may not apply to all filesystems. For
1245 * example, client NFS does not { although it is never remote mounted
1246 * anyhow }
1247 * The alternate call nqnfsrv_readdirlook() does lookups as well.
1248 * PS: The NFS protocol spec. does not clarify what the "count" byte
1249 * argument is a count of.. just name strings and file id's or the
1250 * entire reply rpc or ...
1251 * I tried just file name and id sizes and it confused the Sun client,
1252 * so I am using the full rpc size now. The "paranoia.." comment refers
1253 * to including the status longwords that are not a part of the dir.
1254 * "entry" structures, but are in the rpc.
1255 */
1256struct flrep {
1257 u_long fl_cachable;
1258 u_long fl_duration;
1259 u_quad_t fl_frev;
1260 nfsv2fh_t fl_nfh;
1261 struct nfsv2_fattr fl_fattr;
1262};
1263
1264nfsrv_readdir(nfsd, mrep, md, dpos, cred, nam, mrq)
1265 struct nfsd *nfsd;
1266 struct mbuf *mrep, *md;
1267 caddr_t dpos;
1268 struct ucred *cred;
1269 struct mbuf *nam, **mrq;
1270{
1271 USES_VOP_READDIR;
1272 USES_VOP_UNLOCK;
1273 register char *bp, *be;
1274 register struct mbuf *mp;
1275 register struct dirent *dp;
1276 register caddr_t cp;
1277 register u_long *tl;
1278 register long t1;
1279 caddr_t bpos;
1280 struct mbuf *mb, *mb2, *mreq, *mp2;
1281 char *cpos, *cend, *cp2, *rbuf;
1282 struct vnode *vp;
1283 nfsv2fh_t nfh;
1284 fhandle_t *fhp;
1285 struct uio io;
1286 struct iovec iv;
1287 struct vattr va;
1288 int len, nlen, rem, xfer, tsiz, i, error = 0;
1289 int siz, cnt, fullsiz, eofflag, rdonly, cache;
1290 u_quad_t frev;
1291 u_long on;
1292 off_t off, toff;
1293
1294 fhp = &nfh.fh_generic;
1295 nfsm_srvmtofh(fhp);
1296 nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
1297 toff = fxdr_unsigned(off_t, *tl++);
1298 off = (toff & ~(NFS_DIRBLKSIZ-1));
1299 on = (toff & (NFS_DIRBLKSIZ-1));
1300 cnt = fxdr_unsigned(int, *tl);
1301 siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1));
1302 if (cnt > NFS_MAXREADDIR)
1303 siz = NFS_MAXREADDIR;
1304 fullsiz = siz;
1305 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
1306 nfsm_reply(0);
1307 nqsrv_getl(vp, NQL_READ);
1308 if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) {
1309 vput(vp);
1310 nfsm_reply(0);
1311 }
1312 VOP_UNLOCK(vp);
1313 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
1314again:
1315 iv.iov_base = rbuf;
1316 iv.iov_len = fullsiz;
1317 io.uio_iov = &iv;
1318 io.uio_iovcnt = 1;
1319 io.uio_offset = off;
1320 io.uio_resid = fullsiz;
1321 io.uio_segflg = UIO_SYSSPACE;
1322 io.uio_rw = UIO_READ;
1323 io.uio_procp = (struct proc *)0;
1324 error = VOP_READDIR(vp, &io, cred, &eofflag);
1325 off = io.uio_offset;
1326 if (error) {
1327 vrele(vp);
1328 free((caddr_t)rbuf, M_TEMP);
1329 nfsm_reply(0);
1330 }
1331 if (io.uio_resid) {
1332 siz -= io.uio_resid;
1333
1334 /*
1335 * If nothing read, return eof
1336 * rpc reply
1337 */
1338 if (siz == 0) {
1339 vrele(vp);
1340 nfsm_reply(2*NFSX_UNSIGNED);
1341 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
1342 *tl++ = nfs_false;
1343 *tl = nfs_true;
1344 FREE((caddr_t)rbuf, M_TEMP);
1345 return (0);
1346 }
1347 }
1348
1349 /*
1350 * Check for degenerate cases of nothing useful read.
1351 * If so go try again
1352 */
1353 cpos = rbuf + on;
1354 cend = rbuf + siz;
1355 dp = (struct dirent *)cpos;
1356 while (cpos < cend && dp->d_fileno == 0) {
1357 cpos += dp->d_reclen;
1358 dp = (struct dirent *)cpos;
1359 }
1360 if (cpos >= cend) {
1361 toff = off;
1362 siz = fullsiz;
1363 on = 0;
1364 goto again;
1365 }
1366
1367 cpos = rbuf + on;
1368 cend = rbuf + siz;
1369 dp = (struct dirent *)cpos;
1370 len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */
1371 nfsm_reply(siz);
1372 mp = mp2 = mb;
1373 bp = bpos;
1374 be = bp + M_TRAILINGSPACE(mp);
1375
1376 /* Loop through the records and build reply */
1377 while (cpos < cend) {
1378 if (dp->d_fileno != 0) {
1379 nlen = dp->d_namlen;
1380 rem = nfsm_rndup(nlen)-nlen;
1381 len += (4*NFSX_UNSIGNED + nlen + rem);
1382 if (len > cnt) {
1383 eofflag = 0;
1384 break;
1385 }
1386 /*
1387 * Build the directory record xdr from
1388 * the dirent entry.
1389 */
1390 nfsm_clget;
1391 *tl = nfs_true;
1392 bp += NFSX_UNSIGNED;
1393 nfsm_clget;
1394 *tl = txdr_unsigned(dp->d_fileno);
1395 bp += NFSX_UNSIGNED;
1396 nfsm_clget;
1397 *tl = txdr_unsigned(nlen);
1398 bp += NFSX_UNSIGNED;
1399
1400 /* And loop around copying the name */
1401 xfer = nlen;
1402 cp = dp->d_name;
1403 while (xfer > 0) {
1404 nfsm_clget;
1405 if ((bp+xfer) > be)
1406 tsiz = be-bp;
1407 else
1408 tsiz = xfer;
1409 bcopy(cp, bp, tsiz);
1410 bp += tsiz;
1411 xfer -= tsiz;
1412 if (xfer > 0)
1413 cp += tsiz;
1414 }
1415 /* And null pad to a long boundary */
1416 for (i = 0; i < rem; i++)
1417 *bp++ = '\0';
1418 nfsm_clget;
1419
1420 /* Finish off the record */
1421 toff += dp->d_reclen;
1422 *tl = txdr_unsigned(toff);
1423 bp += NFSX_UNSIGNED;
1424 } else
1425 toff += dp->d_reclen;
1426 cpos += dp->d_reclen;
1427 dp = (struct dirent *)cpos;
1428 }
1429 vrele(vp);
1430 nfsm_clget;
1431 *tl = nfs_false;
1432 bp += NFSX_UNSIGNED;
1433 nfsm_clget;
1434 if (eofflag)
1435 *tl = nfs_true;
1436 else
1437 *tl = nfs_false;
1438 bp += NFSX_UNSIGNED;
1439 if (mp != mb) {
1440 if (bp < be)
1441 mp->m_len = bp - mtod(mp, caddr_t);
1442 } else
1443 mp->m_len += bp - bpos;
1444 FREE(rbuf, M_TEMP);
1445 nfsm_srvdone;
1446}
1447
1448nqnfsrv_readdirlook(nfsd, mrep, md, dpos, cred, nam, mrq)
1449 struct nfsd *nfsd;
1450 struct mbuf *mrep, *md;
1451 caddr_t dpos;
1452 struct ucred *cred;
1453 struct mbuf *nam, **mrq;
1454{
1455 USES_VOP_GETATTR;
1456 USES_VOP_READDIR;
1457 USES_VOP_UNLOCK;
1458 register char *bp, *be;
1459 register struct mbuf *mp;
1460 register struct dirent *dp;
1461 register caddr_t cp;
1462 register u_long *tl;
1463 register long t1;
1464 caddr_t bpos;
1465 struct mbuf *mb, *mb2, *mreq, *mp2;
1466 char *cpos, *cend, *cp2, *rbuf;
1467 struct vnode *vp, *nvp;
1468 struct flrep fl;
1469 struct ufid *ufp = (struct ufid *)&fl.fl_nfh.fh_generic.fh_fid;
1470 struct mount *mntp;
1471 nfsv2fh_t nfh;
1472 fhandle_t *fhp;
1473 struct uio io;
1474 struct iovec iv;
1475 struct vattr va, *vap = &va;
1476 struct nfsv2_fattr *fp;
1477 int len, nlen, rem, xfer, tsiz, i, error = 0, duration2, cache2;
1478 int siz, cnt, fullsiz, eofflag, rdonly, cache;
1479 u_quad_t frev, frev2;
1480 u_long on;
1481 off_t off, toff;
1482
1483 fhp = &nfh.fh_generic;
1484 nfsm_srvmtofh(fhp);
1485 nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED);
1486 toff = fxdr_unsigned(off_t, *tl++);
1487 off = (toff & ~(NFS_DIRBLKSIZ-1));
1488 on = (toff & (NFS_DIRBLKSIZ-1));
1489 cnt = fxdr_unsigned(int, *tl++);
1490 duration2 = fxdr_unsigned(int, *tl);
1491 siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1));
1492 if (cnt > NFS_MAXREADDIR)
1493 siz = NFS_MAXREADDIR;
1494 fullsiz = siz;
1495 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
1496 nfsm_reply(0);
1497 nqsrv_getl(vp, NQL_READ);
1498 if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) {
1499 vput(vp);
1500 nfsm_reply(0);
1501 }
1502 VOP_UNLOCK(vp);
1503 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
1504again:
1505 iv.iov_base = rbuf;
1506 iv.iov_len = fullsiz;
1507 io.uio_iov = &iv;
1508 io.uio_iovcnt = 1;
1509 io.uio_offset = off;
1510 io.uio_resid = fullsiz;
1511 io.uio_segflg = UIO_SYSSPACE;
1512 io.uio_rw = UIO_READ;
1513 io.uio_procp = (struct proc *)0;
1514 error = VOP_READDIR(vp, &io, cred, &eofflag);
1515 off = io.uio_offset;
1516 if (error) {
1517 vrele(vp);
1518 free((caddr_t)rbuf, M_TEMP);
1519 nfsm_reply(0);
1520 }
1521 if (io.uio_resid) {
1522 siz -= io.uio_resid;
1523
1524 /*
1525 * If nothing read, return eof
1526 * rpc reply
1527 */
1528 if (siz == 0) {
1529 vrele(vp);
1530 nfsm_reply(2*NFSX_UNSIGNED);
1531 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
1532 *tl++ = nfs_false;
1533 *tl = nfs_true;
1534 FREE((caddr_t)rbuf, M_TEMP);
1535 return (0);
1536 }
1537 }
1538
1539 /*
1540 * Check for degenerate cases of nothing useful read.
1541 * If so go try again
1542 */
1543 cpos = rbuf + on;
1544 cend = rbuf + siz;
1545 dp = (struct dirent *)cpos;
1546 while (cpos < cend && dp->d_fileno == 0) {
1547 cpos += dp->d_reclen;
1548 dp = (struct dirent *)cpos;
1549 }
1550 if (cpos >= cend) {
1551 toff = off;
1552 siz = fullsiz;
1553 on = 0;
1554 goto again;
1555 }
1556
1557 cpos = rbuf + on;
1558 cend = rbuf + siz;
1559 dp = (struct dirent *)cpos;
1560 len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */
1561 nfsm_reply(siz);
1562 mp = mp2 = mb;
1563 bp = bpos;
1564 be = bp + M_TRAILINGSPACE(mp);
1565 mntp = vp->v_mount;
1566
1567 /* Loop through the records and build reply */
1568 while (cpos < cend) {
1569 if (dp->d_fileno != 0) {
1570 nlen = dp->d_namlen;
1571 rem = nfsm_rndup(nlen)-nlen;
1572
1573 /*
1574 * For readdir_and_lookup get the vnode using
1575 * the file number.
1576 */
1577 bzero((caddr_t)&fl.fl_nfh, sizeof (nfsv2fh_t));
1578 ufp->ufid_len = sizeof (struct ufid);
1579 ufp->ufid_ino = dp->d_fileno;
1580 fl.fl_nfh.fh_generic.fh_fsid = mntp->mnt_stat.f_fsid;
1581 if (VFS_FHTOVP(mntp, (struct fid *)ufp, 1, &nvp))
1582 goto invalid;
1583 (void) nqsrv_getlease(nvp, &duration2, NQL_READ, nfsd,
1584 nam, &cache2, &frev2, cred);
1585 fl.fl_duration = txdr_unsigned(duration2);
1586 fl.fl_cachable = txdr_unsigned(cache2);
1587 txdr_hyper(&frev2, &fl.fl_frev);
1588 if (VOP_GETATTR(nvp, vap, cred, nfsd->nd_procp)) {
1589 vput(nvp);
1590 goto invalid;
1591 }
1592 vput(nvp);
1593 fp = &fl.fl_fattr;
1594 nfsm_srvfillattr;
1595 len += (4*NFSX_UNSIGNED + nlen + rem + NFSX_FH
1596 + NFSX_FATTR);
1597 if (len > cnt) {
1598 eofflag = 0;
1599 break;
1600 }
1601 /*
1602 * Build the directory record xdr from
1603 * the dirent entry.
1604 */
1605 nfsm_clget;
1606 *tl = nfs_true;
1607 bp += NFSX_UNSIGNED;
1608
1609 /*
1610 * For readdir_and_lookup copy the stuff out.
1611 */
1612 xfer = sizeof (struct flrep);
1613 cp = (caddr_t)&fl;
1614 while (xfer > 0) {
1615 nfsm_clget;
1616 if ((bp+xfer) > be)
1617 tsiz = be-bp;
1618 else
1619 tsiz = xfer;
1620 bcopy(cp, bp, tsiz);
1621 bp += tsiz;
1622 xfer -= tsiz;
1623 if (xfer > 0)
1624 cp += tsiz;
1625 }
1626 nfsm_clget;
1627 *tl = txdr_unsigned(dp->d_fileno);
1628 bp += NFSX_UNSIGNED;
1629 nfsm_clget;
1630 *tl = txdr_unsigned(nlen);
1631 bp += NFSX_UNSIGNED;
1632
1633 /* And loop around copying the name */
1634 xfer = nlen;
1635 cp = dp->d_name;
1636 while (xfer > 0) {
1637 nfsm_clget;
1638 if ((bp+xfer) > be)
1639 tsiz = be-bp;
1640 else
1641 tsiz = xfer;
1642 bcopy(cp, bp, tsiz);
1643 bp += tsiz;
1644 xfer -= tsiz;
1645 if (xfer > 0)
1646 cp += tsiz;
1647 }
1648 /* And null pad to a long boundary */
1649 for (i = 0; i < rem; i++)
1650 *bp++ = '\0';
1651 nfsm_clget;
1652
1653 /* Finish off the record */
1654 toff += dp->d_reclen;
1655 *tl = txdr_unsigned(toff);
1656 bp += NFSX_UNSIGNED;
1657 } else
1658invalid:
1659 toff += dp->d_reclen;
1660 cpos += dp->d_reclen;
1661 dp = (struct dirent *)cpos;
1662 }
1663 vrele(vp);
1664 nfsm_clget;
1665 *tl = nfs_false;
1666 bp += NFSX_UNSIGNED;
1667 nfsm_clget;
1668 if (eofflag)
1669 *tl = nfs_true;
1670 else
1671 *tl = nfs_false;
1672 bp += NFSX_UNSIGNED;
1673 if (mp != mb) {
1674 if (bp < be)
1675 mp->m_len = bp - mtod(mp, caddr_t);
1676 } else
1677 mp->m_len += bp - bpos;
1678 FREE(rbuf, M_TEMP);
1679 nfsm_srvdone;
1680}
1681
1682/*
1683 * nfs statfs service
1684 */
1685nfsrv_statfs(nfsd, mrep, md, dpos, cred, nam, mrq)
1686 struct nfsd *nfsd;
1687 struct mbuf *mrep, *md;
1688 caddr_t dpos;
1689 struct ucred *cred;
1690 struct mbuf *nam, **mrq;
1691{
1692 register struct statfs *sf;
1693 register struct nfsv2_statfs *sfp;
1694 register u_long *tl;
1695 register long t1;
1696 caddr_t bpos;
1697 int error = 0, rdonly, cache;
1698 char *cp2;
1699 struct mbuf *mb, *mb2, *mreq;
1700 struct vnode *vp;
1701 nfsv2fh_t nfh;
1702 fhandle_t *fhp;
1703 struct statfs statfs;
1704 u_quad_t frev;
1705
1706 fhp = &nfh.fh_generic;
1707 nfsm_srvmtofh(fhp);
1708 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
1709 nfsm_reply(0);
1710 sf = &statfs;
1711 error = VFS_STATFS(vp->v_mount, sf, nfsd->nd_procp);
1712 vput(vp);
1713 nfsm_reply(NFSX_STATFS);
1714 nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS);
1715 sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
1716 sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
1717 sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
1718 sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
1719 sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
1720 nfsm_srvdone;
1721}
1722
1723/*
1724 * Null operation, used by clients to ping server
1725 */
1726/* ARGSUSED */
1727nfsrv_null(nfsd, mrep, md, dpos, cred, nam, mrq)
1728 struct nfsd *nfsd;
1729 struct mbuf *mrep, *md;
1730 caddr_t dpos;
1731 struct ucred *cred;
1732 struct mbuf *nam, **mrq;
1733{
1734 caddr_t bpos;
1735 int error = VNOVAL, cache;
1736 struct mbuf *mb, *mreq;
1737 u_quad_t frev;
1738
1739 nfsm_reply(0);
1740 return (error);
1741}
1742
1743/*
1744 * No operation, used for obsolete procedures
1745 */
1746/* ARGSUSED */
1747nfsrv_noop(nfsd, mrep, md, dpos, cred, nam, mrq)
1748 struct nfsd *nfsd;
1749 struct mbuf *mrep, *md;
1750 caddr_t dpos;
1751 struct ucred *cred;
1752 struct mbuf *nam, **mrq;
1753{
1754 caddr_t bpos;
1755 int error, cache;
1756 struct mbuf *mb, *mreq;
1757 u_quad_t frev;
1758
1759 if (nfsd->nd_repstat)
1760 error = nfsd->nd_repstat;
1761 else
1762 error = EPROCUNAVAIL;
1763 nfsm_reply(0);
1764 return (error);
1765}
1766
1767/*
1768 * Perform access checking for vnodes obtained from file handles that would
1769 * refer to files already opened by a Unix client. You cannot just use
1770 * vn_writechk() and VOP_ACCESS() for two reasons.
1771 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
1772 * 2 - The owner is to be given access irrespective of mode bits so that
1773 * processes that chmod after opening a file don't break. I don't like
1774 * this because it opens a security hole, but since the nfs server opens
1775 * a security hole the size of a barn door anyhow, what the heck.
1776 */
1777nfsrv_access(vp, flags, cred, rdonly, p)
1778 register struct vnode *vp;
1779 int flags;
1780 register struct ucred *cred;
1781 int rdonly;
1782 struct proc *p;
1783{
1784 USES_VOP_ACCESS;
1785 USES_VOP_GETATTR;
1786 struct vattr vattr;
1787 int error;
1788 if (flags & VWRITE) {
1789 /* Just vn_writechk() changed to check rdonly */
1790 /*
1791 * Disallow write attempts on read-only file systems;
1792 * unless the file is a socket or a block or character
1793 * device resident on the file system.
1794 */
1795 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
1796 switch (vp->v_type) {
1797 case VREG: case VDIR: case VLNK:
1798 return (EROFS);
1799 }
1800 }
1801 /*
1802 * If there's shared text associated with
1803 * the inode, try to free it up once. If
1804 * we fail, we can't allow writing.
1805 */
1806 if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
1807 return (ETXTBSY);
1808 }
1809 if (error = VOP_GETATTR(vp, &vattr, cred, p))
1810 return (error);
1811 if ((error = VOP_ACCESS(vp, flags, cred, p)) &&
1812 cred->cr_uid != vattr.va_uid)
1813 return (error);
1814 return (0);
1815}