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