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