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