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