1 /*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * %sccs.include.redist.c%
9 *
10 * @(#)nfs_serv.c 8.7 (Berkeley) 05/14/95
11 */
12
13 /*
14 * nfs version 2 and 3 server calls to vnode ops
15 * - these routines generally have 3 phases
16 * 1 - break down and validate rpc request in mbuf list
17 * 2 - do the vnode ops for the request
18 * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
19 * 3 - build the rpc reply in an mbuf list
20 * nb:
21 * - do not mix the phases, since the nfsm_?? macros can return failures
22 * on a bad rpc or similar and do not do any vrele() or vput()'s
23 *
24 * - the nfsm_reply() macro generates an nfs rpc reply with the nfs
25 * error number iff error != 0 whereas
26 * returning an error from the server function implies a fatal error
27 * such as a badly constructed rpc request that should be dropped without
28 * a reply.
29 * For Version 3, nfsm_reply() does not return for the error case, since
30 * most version 3 rpcs return more than the status for error cases.
31 */
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/proc.h>
36 #include <sys/file.h>
37 #include <sys/namei.h>
38 #include <sys/vnode.h>
39 #include <sys/mount.h>
40 #include <sys/socket.h>
41 #include <sys/socketvar.h>
42 #include <sys/mbuf.h>
43 #include <sys/dirent.h>
44 #include <sys/stat.h>
45 #include <sys/kernel.h>
46 #include <ufs/ufs/dir.h>
47
48 #include <vm/vm.h>
49
50 #include <nfs/nfsproto.h>
51 #include <nfs/rpcv2.h>
52 #include <nfs/nfs.h>
53 #include <nfs/xdr_subs.h>
54 #include <nfs/nfsm_subs.h>
55 #include <nfs/nqnfs.h>
56
57 /* Global vars */
58 extern u_long nfs_xdrneg1;
59 extern u_long nfs_false, nfs_true;
60 extern enum vtype nv3tov_type[8];
61 extern struct nfsstats nfsstats;
62 nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
63 NFCHR, NFNON };
64 nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
65 NFFIFO, NFNON };
66 int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000;
67
68 /*
69 * nfs v3 access service
70 */
71 int
nfsrv3_access(nfsd,slp,procp,mrq)72 nfsrv3_access(nfsd, slp, procp, mrq)
73 struct nfsrv_descript *nfsd;
74 struct nfssvc_sock *slp;
75 struct proc *procp;
76 struct mbuf **mrq;
77 {
78 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
79 struct mbuf *nam = nfsd->nd_nam;
80 caddr_t dpos = nfsd->nd_dpos;
81 struct ucred *cred = &nfsd->nd_cr;
82 struct vnode *vp;
83 nfsfh_t nfh;
84 fhandle_t *fhp;
85 register u_long *tl;
86 register long t1;
87 caddr_t bpos;
88 int error = 0, rdonly, cache, getret;
89 char *cp2;
90 struct mbuf *mb, *mreq, *mb2;
91 struct vattr vattr, *vap = &vattr;
92 u_long testmode, nfsmode;
93 u_quad_t frev;
94
95 #ifndef nolint
96 cache = 0;
97 #endif
98 fhp = &nfh.fh_generic;
99 nfsm_srvmtofh(fhp);
100 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
101 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
102 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
103 nfsm_reply(NFSX_UNSIGNED);
104 nfsm_srvpostop_attr(1, (struct vattr *)0);
105 return (0);
106 }
107 nfsmode = fxdr_unsigned(u_long, *tl);
108 if ((nfsmode & NFSV3ACCESS_READ) &&
109 nfsrv_access(vp, VREAD, cred, rdonly, procp))
110 nfsmode &= ~NFSV3ACCESS_READ;
111 if (vp->v_type == VDIR)
112 testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
113 NFSV3ACCESS_DELETE);
114 else
115 testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
116 if ((nfsmode & testmode) &&
117 nfsrv_access(vp, VWRITE, cred, rdonly, procp))
118 nfsmode &= ~testmode;
119 if (vp->v_type == VDIR)
120 testmode = NFSV3ACCESS_LOOKUP;
121 else
122 testmode = NFSV3ACCESS_EXECUTE;
123 if ((nfsmode & testmode) &&
124 nfsrv_access(vp, VEXEC, cred, rdonly, procp))
125 nfsmode &= ~testmode;
126 getret = VOP_GETATTR(vp, vap, cred, procp);
127 vput(vp);
128 nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED);
129 nfsm_srvpostop_attr(getret, vap);
130 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
131 *tl = txdr_unsigned(nfsmode);
132 nfsm_srvdone;
133 }
134
135 /*
136 * nfs getattr service
137 */
138 int
nfsrv_getattr(nfsd,slp,procp,mrq)139 nfsrv_getattr(nfsd, slp, procp, mrq)
140 struct nfsrv_descript *nfsd;
141 struct nfssvc_sock *slp;
142 struct proc *procp;
143 struct mbuf **mrq;
144 {
145 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
146 struct mbuf *nam = nfsd->nd_nam;
147 caddr_t dpos = nfsd->nd_dpos;
148 struct ucred *cred = &nfsd->nd_cr;
149 register struct nfs_fattr *fp;
150 struct vattr va;
151 register struct vattr *vap = &va;
152 struct vnode *vp;
153 nfsfh_t nfh;
154 fhandle_t *fhp;
155 register u_long *tl;
156 register long t1;
157 caddr_t bpos;
158 int error = 0, rdonly, cache;
159 char *cp2;
160 struct mbuf *mb, *mb2, *mreq;
161 u_quad_t frev;
162
163 fhp = &nfh.fh_generic;
164 nfsm_srvmtofh(fhp);
165 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
166 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
167 nfsm_reply(0);
168 return (0);
169 }
170 nqsrv_getl(vp, ND_READ);
171 error = VOP_GETATTR(vp, vap, cred, procp);
172 vput(vp);
173 nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
174 if (error)
175 return (0);
176 nfsm_build(fp, struct nfs_fattr *, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
177 nfsm_srvfillattr(vap, fp);
178 nfsm_srvdone;
179 }
180
181 /*
182 * nfs setattr service
183 */
184 int
nfsrv_setattr(nfsd,slp,procp,mrq)185 nfsrv_setattr(nfsd, slp, procp, mrq)
186 struct nfsrv_descript *nfsd;
187 struct nfssvc_sock *slp;
188 struct proc *procp;
189 struct mbuf **mrq;
190 {
191 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
192 struct mbuf *nam = nfsd->nd_nam;
193 caddr_t dpos = nfsd->nd_dpos;
194 struct ucred *cred = &nfsd->nd_cr;
195 struct vattr va, preat;
196 register struct vattr *vap = &va;
197 register struct nfsv2_sattr *sp;
198 register struct nfs_fattr *fp;
199 struct vnode *vp;
200 nfsfh_t nfh;
201 fhandle_t *fhp;
202 register u_long *tl;
203 register long t1;
204 caddr_t bpos;
205 int error = 0, rdonly, cache, preat_ret = 1, postat_ret = 1;
206 int v3 = (nfsd->nd_flag & ND_NFSV3), gcheck = 0;
207 char *cp2;
208 struct mbuf *mb, *mb2, *mreq;
209 u_quad_t frev;
210 struct timespec guard;
211
212 fhp = &nfh.fh_generic;
213 nfsm_srvmtofh(fhp);
214 VATTR_NULL(vap);
215 if (v3) {
216 nfsm_srvsattr(vap);
217 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
218 gcheck = fxdr_unsigned(int, *tl);
219 if (gcheck) {
220 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
221 fxdr_nfsv3time(tl, &guard);
222 }
223 } else {
224 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
225 /*
226 * Nah nah nah nah na nah
227 * There is a bug in the Sun client that puts 0xffff in the mode
228 * field of sattr when it should put in 0xffffffff. The u_short
229 * doesn't sign extend.
230 * --> check the low order 2 bytes for 0xffff
231 */
232 if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
233 vap->va_mode = nfstov_mode(sp->sa_mode);
234 if (sp->sa_uid != nfs_xdrneg1)
235 vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
236 if (sp->sa_gid != nfs_xdrneg1)
237 vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
238 if (sp->sa_size != nfs_xdrneg1)
239 vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_size);
240 if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) {
241 #ifdef notyet
242 fxdr_nfsv2time(&sp->sa_atime, &vap->va_atime);
243 #else
244 vap->va_atime.ts_sec =
245 fxdr_unsigned(long, sp->sa_atime.nfsv2_sec);
246 vap->va_atime.ts_nsec = 0;
247 #endif
248 }
249 if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1)
250 fxdr_nfsv2time(&sp->sa_mtime, &vap->va_mtime);
251
252 }
253
254 /*
255 * Now that we have all the fields, lets do it.
256 */
257 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
258 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
259 nfsm_reply(2 * NFSX_UNSIGNED);
260 nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
261 return (0);
262 }
263 nqsrv_getl(vp, ND_WRITE);
264 if (v3) {
265 error = preat_ret = VOP_GETATTR(vp, &preat, cred, procp);
266 if (!error && gcheck &&
267 (preat.va_ctime.ts_sec != guard.ts_sec ||
268 preat.va_ctime.ts_nsec != guard.ts_nsec))
269 error = NFSERR_NOT_SYNC;
270 if (error) {
271 vput(vp);
272 nfsm_reply(NFSX_WCCDATA(v3));
273 nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
274 return (0);
275 }
276 }
277
278 /*
279 * If the size is being changed write acces is required, otherwise
280 * just check for a read only file system.
281 */
282 if (vap->va_size == ((u_quad_t)((quad_t) -1))) {
283 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
284 error = EROFS;
285 goto out;
286 }
287 } else {
288 if (vp->v_type == VDIR) {
289 error = EISDIR;
290 goto out;
291 } else if (error = nfsrv_access(vp, VWRITE, cred, rdonly,
292 procp))
293 goto out;
294 }
295 error = VOP_SETATTR(vp, vap, cred, procp);
296 postat_ret = VOP_GETATTR(vp, vap, cred, procp);
297 if (!error)
298 error = postat_ret;
299 out:
300 vput(vp);
301 nfsm_reply(NFSX_WCCORFATTR(v3));
302 if (v3) {
303 nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
304 return (0);
305 } else {
306 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
307 nfsm_srvfillattr(vap, fp);
308 }
309 nfsm_srvdone;
310 }
311
312 /*
313 * nfs lookup rpc
314 */
315 int
nfsrv_lookup(nfsd,slp,procp,mrq)316 nfsrv_lookup(nfsd, slp, procp, mrq)
317 struct nfsrv_descript *nfsd;
318 struct nfssvc_sock *slp;
319 struct proc *procp;
320 struct mbuf **mrq;
321 {
322 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
323 struct mbuf *nam = nfsd->nd_nam;
324 caddr_t dpos = nfsd->nd_dpos;
325 struct ucred *cred = &nfsd->nd_cr;
326 register struct nfs_fattr *fp;
327 struct nameidata nd;
328 struct vnode *vp, *dirp;
329 nfsfh_t nfh;
330 fhandle_t *fhp;
331 register caddr_t cp;
332 register u_long *tl;
333 register long t1;
334 caddr_t bpos;
335 int error = 0, cache, len, dirattr_ret = 1;
336 int v3 = (nfsd->nd_flag & ND_NFSV3);
337 char *cp2;
338 struct mbuf *mb, *mb2, *mreq;
339 struct vattr va, dirattr, *vap = &va;
340 u_quad_t frev;
341
342 fhp = &nfh.fh_generic;
343 nfsm_srvmtofh(fhp);
344 nfsm_srvnamesiz(len);
345 nd.ni_cnd.cn_cred = cred;
346 nd.ni_cnd.cn_nameiop = LOOKUP;
347 nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART;
348 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
349 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
350 if (dirp) {
351 if (v3)
352 dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred,
353 procp);
354 vrele(dirp);
355 }
356 if (error) {
357 nfsm_reply(NFSX_POSTOPATTR(v3));
358 nfsm_srvpostop_attr(dirattr_ret, &dirattr);
359 return (0);
360 }
361 nqsrv_getl(nd.ni_startdir, ND_READ);
362 vrele(nd.ni_startdir);
363 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
364 vp = nd.ni_vp;
365 bzero((caddr_t)fhp, sizeof(nfh));
366 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
367 error = VFS_VPTOFH(vp, &fhp->fh_fid);
368 if (!error)
369 error = VOP_GETATTR(vp, vap, cred, procp);
370 vput(vp);
371 nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3));
372 if (error) {
373 nfsm_srvpostop_attr(dirattr_ret, &dirattr);
374 return (0);
375 }
376 nfsm_srvfhtom(fhp, v3);
377 if (v3) {
378 nfsm_srvpostop_attr(0, vap);
379 nfsm_srvpostop_attr(dirattr_ret, &dirattr);
380 } else {
381 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
382 nfsm_srvfillattr(vap, fp);
383 }
384 nfsm_srvdone;
385 }
386
387 /*
388 * nfs readlink service
389 */
390 int
nfsrv_readlink(nfsd,slp,procp,mrq)391 nfsrv_readlink(nfsd, slp, procp, mrq)
392 struct nfsrv_descript *nfsd;
393 struct nfssvc_sock *slp;
394 struct proc *procp;
395 struct mbuf **mrq;
396 {
397 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
398 struct mbuf *nam = nfsd->nd_nam;
399 caddr_t dpos = nfsd->nd_dpos;
400 struct ucred *cred = &nfsd->nd_cr;
401 struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
402 register struct iovec *ivp = iv;
403 register struct mbuf *mp;
404 register u_long *tl;
405 register long t1;
406 caddr_t bpos;
407 int error = 0, rdonly, cache, i, tlen, len, getret;
408 int v3 = (nfsd->nd_flag & ND_NFSV3);
409 char *cp2;
410 struct mbuf *mb, *mb2, *mp2, *mp3, *mreq;
411 struct vnode *vp;
412 struct vattr attr;
413 nfsfh_t nfh;
414 fhandle_t *fhp;
415 struct uio io, *uiop = &io;
416 u_quad_t frev;
417
418 #ifndef nolint
419 mp2 = mp3 = (struct mbuf *)0;
420 #endif
421 fhp = &nfh.fh_generic;
422 nfsm_srvmtofh(fhp);
423 len = 0;
424 i = 0;
425 while (len < NFS_MAXPATHLEN) {
426 MGET(mp, M_WAIT, MT_DATA);
427 MCLGET(mp, M_WAIT);
428 mp->m_len = NFSMSIZ(mp);
429 if (len == 0)
430 mp3 = mp2 = mp;
431 else {
432 mp2->m_next = mp;
433 mp2 = mp;
434 }
435 if ((len+mp->m_len) > NFS_MAXPATHLEN) {
436 mp->m_len = NFS_MAXPATHLEN-len;
437 len = NFS_MAXPATHLEN;
438 } else
439 len += mp->m_len;
440 ivp->iov_base = mtod(mp, caddr_t);
441 ivp->iov_len = mp->m_len;
442 i++;
443 ivp++;
444 }
445 uiop->uio_iov = iv;
446 uiop->uio_iovcnt = i;
447 uiop->uio_offset = 0;
448 uiop->uio_resid = len;
449 uiop->uio_rw = UIO_READ;
450 uiop->uio_segflg = UIO_SYSSPACE;
451 uiop->uio_procp = (struct proc *)0;
452 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
453 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
454 m_freem(mp3);
455 nfsm_reply(2 * NFSX_UNSIGNED);
456 nfsm_srvpostop_attr(1, (struct vattr *)0);
457 return (0);
458 }
459 if (vp->v_type != VLNK) {
460 if (v3)
461 error = EINVAL;
462 else
463 error = ENXIO;
464 goto out;
465 }
466 nqsrv_getl(vp, ND_READ);
467 error = VOP_READLINK(vp, uiop, cred);
468 out:
469 getret = VOP_GETATTR(vp, &attr, cred, procp);
470 vput(vp);
471 if (error)
472 m_freem(mp3);
473 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED);
474 if (v3) {
475 nfsm_srvpostop_attr(getret, &attr);
476 if (error)
477 return (0);
478 }
479 if (uiop->uio_resid > 0) {
480 len -= uiop->uio_resid;
481 tlen = nfsm_rndup(len);
482 nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
483 }
484 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
485 *tl = txdr_unsigned(len);
486 mb->m_next = mp3;
487 nfsm_srvdone;
488 }
489
490 /*
491 * nfs read service
492 */
493 int
nfsrv_read(nfsd,slp,procp,mrq)494 nfsrv_read(nfsd, slp, procp, mrq)
495 struct nfsrv_descript *nfsd;
496 struct nfssvc_sock *slp;
497 struct proc *procp;
498 struct mbuf **mrq;
499 {
500 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
501 struct mbuf *nam = nfsd->nd_nam;
502 caddr_t dpos = nfsd->nd_dpos;
503 struct ucred *cred = &nfsd->nd_cr;
504 register struct iovec *iv;
505 struct iovec *iv2;
506 register struct mbuf *m;
507 register struct nfs_fattr *fp;
508 register u_long *tl;
509 register long t1;
510 register int i;
511 caddr_t bpos;
512 int error = 0, rdonly, cache, cnt, len, left, siz, tlen, getret;
513 int v3 = (nfsd->nd_flag & ND_NFSV3), reqlen;
514 char *cp2;
515 struct mbuf *mb, *mb2, *mreq;
516 struct mbuf *m2;
517 struct vnode *vp;
518 nfsfh_t nfh;
519 fhandle_t *fhp;
520 struct uio io, *uiop = &io;
521 struct vattr va, *vap = &va;
522 off_t off;
523 u_quad_t frev;
524
525 fhp = &nfh.fh_generic;
526 nfsm_srvmtofh(fhp);
527 if (v3) {
528 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
529 fxdr_hyper(tl, &off);
530 } else {
531 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
532 off = (off_t)fxdr_unsigned(u_long, *tl);
533 }
534 nfsm_srvstrsiz(reqlen, NFS_SRVMAXDATA(nfsd));
535 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
536 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
537 nfsm_reply(2 * NFSX_UNSIGNED);
538 nfsm_srvpostop_attr(1, (struct vattr *)0);
539 return (0);
540 }
541 if (vp->v_type != VREG) {
542 if (v3)
543 error = EINVAL;
544 else
545 error = (vp->v_type == VDIR) ? EISDIR : EACCES;
546 }
547 if (!error) {
548 nqsrv_getl(vp, ND_READ);
549 if (error = nfsrv_access(vp, VREAD, cred, rdonly, procp))
550 error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
551 }
552 getret = VOP_GETATTR(vp, vap, cred, procp);
553 if (!error)
554 error = getret;
555 if (error) {
556 vput(vp);
557 nfsm_reply(NFSX_POSTOPATTR(v3));
558 nfsm_srvpostop_attr(getret, vap);
559 return (0);
560 }
561 if (off >= vap->va_size)
562 cnt = 0;
563 else if ((off + reqlen) > vap->va_size)
564 cnt = nfsm_rndup(vap->va_size - off);
565 else
566 cnt = reqlen;
567 nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt));
568 if (v3) {
569 nfsm_build(tl, u_long *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
570 *tl++ = nfs_true;
571 fp = (struct nfs_fattr *)tl;
572 tl += (NFSX_V3FATTR / sizeof (u_long));
573 } else {
574 nfsm_build(tl, u_long *, NFSX_V2FATTR + NFSX_UNSIGNED);
575 fp = (struct nfs_fattr *)tl;
576 tl += (NFSX_V2FATTR / sizeof (u_long));
577 }
578 len = left = cnt;
579 if (cnt > 0) {
580 /*
581 * Generate the mbuf list with the uio_iov ref. to it.
582 */
583 i = 0;
584 m = m2 = mb;
585 while (left > 0) {
586 siz = min(M_TRAILINGSPACE(m), left);
587 if (siz > 0) {
588 left -= siz;
589 i++;
590 }
591 if (left > 0) {
592 MGET(m, M_WAIT, MT_DATA);
593 MCLGET(m, M_WAIT);
594 m->m_len = 0;
595 m2->m_next = m;
596 m2 = m;
597 }
598 }
599 MALLOC(iv, struct iovec *, i * sizeof (struct iovec),
600 M_TEMP, M_WAITOK);
601 uiop->uio_iov = iv2 = iv;
602 m = mb;
603 left = cnt;
604 i = 0;
605 while (left > 0) {
606 if (m == NULL)
607 panic("nfsrv_read iov");
608 siz = min(M_TRAILINGSPACE(m), left);
609 if (siz > 0) {
610 iv->iov_base = mtod(m, caddr_t) + m->m_len;
611 iv->iov_len = siz;
612 m->m_len += siz;
613 left -= siz;
614 iv++;
615 i++;
616 }
617 m = m->m_next;
618 }
619 uiop->uio_iovcnt = i;
620 uiop->uio_offset = off;
621 uiop->uio_resid = cnt;
622 uiop->uio_rw = UIO_READ;
623 uiop->uio_segflg = UIO_SYSSPACE;
624 error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
625 off = uiop->uio_offset;
626 FREE((caddr_t)iv2, M_TEMP);
627 if (error || (getret = VOP_GETATTR(vp, vap, cred, procp))) {
628 if (!error)
629 error = getret;
630 m_freem(mreq);
631 vput(vp);
632 nfsm_reply(NFSX_POSTOPATTR(v3));
633 nfsm_srvpostop_attr(getret, vap);
634 return (0);
635 }
636 } else
637 uiop->uio_resid = 0;
638 vput(vp);
639 nfsm_srvfillattr(vap, fp);
640 len -= uiop->uio_resid;
641 tlen = nfsm_rndup(len);
642 if (cnt != tlen || tlen != len)
643 nfsm_adj(mb, cnt - tlen, tlen - len);
644 if (v3) {
645 *tl++ = txdr_unsigned(len);
646 if (len < reqlen)
647 *tl++ = nfs_true;
648 else
649 *tl++ = nfs_false;
650 }
651 *tl = txdr_unsigned(len);
652 nfsm_srvdone;
653 }
654
655 /*
656 * nfs write service
657 */
658 int
nfsrv_write(nfsd,slp,procp,mrq)659 nfsrv_write(nfsd, slp, procp, mrq)
660 struct nfsrv_descript *nfsd;
661 struct nfssvc_sock *slp;
662 struct proc *procp;
663 struct mbuf **mrq;
664 {
665 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
666 struct mbuf *nam = nfsd->nd_nam;
667 caddr_t dpos = nfsd->nd_dpos;
668 struct ucred *cred = &nfsd->nd_cr;
669 register struct iovec *ivp;
670 register int i, cnt;
671 register struct mbuf *mp;
672 register struct nfs_fattr *fp;
673 struct iovec *iv;
674 struct vattr va, forat;
675 register struct vattr *vap = &va;
676 register u_long *tl;
677 register long t1;
678 caddr_t bpos;
679 int error = 0, rdonly, cache, siz, len, xfer, forat_ret = 1;
680 int ioflags, aftat_ret = 1, retlen, zeroing, adjust;
681 int stable = NFSV3WRITE_FILESYNC;
682 int v3 = (nfsd->nd_flag & ND_NFSV3);
683 char *cp2;
684 struct mbuf *mb, *mb2, *mreq;
685 struct vnode *vp;
686 nfsfh_t nfh;
687 fhandle_t *fhp;
688 struct uio io, *uiop = &io;
689 off_t off;
690 u_quad_t frev;
691
692 if (mrep == NULL) {
693 *mrq = NULL;
694 return (0);
695 }
696 fhp = &nfh.fh_generic;
697 nfsm_srvmtofh(fhp);
698 if (v3) {
699 nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
700 fxdr_hyper(tl, &off);
701 tl += 3;
702 stable = fxdr_unsigned(int, *tl++);
703 } else {
704 nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
705 off = (off_t)fxdr_unsigned(u_long, *++tl);
706 tl += 2;
707 }
708 retlen = len = fxdr_unsigned(long, *tl);
709 cnt = i = 0;
710
711 /*
712 * For NFS Version 2, it is not obvious what a write of zero length
713 * should do, but I might as well be consistent with Version 3,
714 * which is to return ok so long as there are no permission problems.
715 */
716 if (len > 0) {
717 zeroing = 1;
718 mp = mrep;
719 while (mp) {
720 if (mp == md) {
721 zeroing = 0;
722 adjust = dpos - mtod(mp, caddr_t);
723 mp->m_len -= adjust;
724 if (mp->m_len > 0 && adjust > 0)
725 NFSMADV(mp, adjust);
726 }
727 if (zeroing)
728 mp->m_len = 0;
729 else if (mp->m_len > 0) {
730 i += mp->m_len;
731 if (i > len) {
732 mp->m_len -= (i - len);
733 zeroing = 1;
734 }
735 if (mp->m_len > 0)
736 cnt++;
737 }
738 mp = mp->m_next;
739 }
740 }
741 if (len > NFS_MAXDATA || len < 0 || i < len) {
742 error = EIO;
743 nfsm_reply(2 * NFSX_UNSIGNED);
744 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
745 return (0);
746 }
747 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
748 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
749 nfsm_reply(2 * NFSX_UNSIGNED);
750 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
751 return (0);
752 }
753 if (v3)
754 forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
755 if (vp->v_type != VREG) {
756 if (v3)
757 error = EINVAL;
758 else
759 error = (vp->v_type == VDIR) ? EISDIR : EACCES;
760 }
761 if (!error) {
762 nqsrv_getl(vp, ND_WRITE);
763 error = nfsrv_access(vp, VWRITE, cred, rdonly, procp);
764 }
765 if (error) {
766 vput(vp);
767 nfsm_reply(NFSX_WCCDATA(v3));
768 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
769 return (0);
770 }
771
772 if (len > 0) {
773 MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP,
774 M_WAITOK);
775 uiop->uio_iov = iv = ivp;
776 uiop->uio_iovcnt = cnt;
777 mp = mrep;
778 while (mp) {
779 if (mp->m_len > 0) {
780 ivp->iov_base = mtod(mp, caddr_t);
781 ivp->iov_len = mp->m_len;
782 ivp++;
783 }
784 mp = mp->m_next;
785 }
786
787 /*
788 * XXX
789 * The IO_METASYNC flag indicates that all metadata (and not just
790 * enough to ensure data integrity) mus be written to stable storage
791 * synchronously.
792 * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
793 */
794 if (stable == NFSV3WRITE_UNSTABLE)
795 ioflags = IO_NODELOCKED;
796 else if (stable == NFSV3WRITE_DATASYNC)
797 ioflags = (IO_SYNC | IO_NODELOCKED);
798 else
799 ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
800 uiop->uio_resid = len;
801 uiop->uio_rw = UIO_WRITE;
802 uiop->uio_segflg = UIO_SYSSPACE;
803 uiop->uio_procp = (struct proc *)0;
804 uiop->uio_offset = off;
805 error = VOP_WRITE(vp, uiop, ioflags, cred);
806 nfsstats.srvvop_writes++;
807 FREE((caddr_t)iv, M_TEMP);
808 }
809 aftat_ret = VOP_GETATTR(vp, vap, cred, procp);
810 vput(vp);
811 if (!error)
812 error = aftat_ret;
813 nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) +
814 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(v3));
815 if (v3) {
816 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
817 if (error)
818 return (0);
819 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
820 *tl++ = txdr_unsigned(retlen);
821 if (stable == NFSV3WRITE_UNSTABLE)
822 *tl++ = txdr_unsigned(stable);
823 else
824 *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC);
825 /*
826 * Actually, there is no need to txdr these fields,
827 * but it may make the values more human readable,
828 * for debugging purposes.
829 */
830 *tl++ = txdr_unsigned(boottime.tv_sec);
831 *tl = txdr_unsigned(boottime.tv_usec);
832 } else {
833 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
834 nfsm_srvfillattr(vap, fp);
835 }
836 nfsm_srvdone;
837 }
838
839 /*
840 * NFS write service with write gathering support. Called when
841 * nfsrvw_procrastinate > 0.
842 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
843 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
844 * Jan. 1994.
845 */
846 int
nfsrv_writegather(ndp,slp,procp,mrq)847 nfsrv_writegather(ndp, slp, procp, mrq)
848 struct nfsrv_descript **ndp;
849 struct nfssvc_sock *slp;
850 struct proc *procp;
851 struct mbuf **mrq;
852 {
853 register struct iovec *ivp;
854 register struct mbuf *mp;
855 register struct nfsrv_descript *wp, *nfsd, *owp, *swp;
856 register struct nfs_fattr *fp;
857 register int i;
858 struct iovec *iov;
859 struct nfsrvw_delayhash *wpp;
860 struct ucred *cred;
861 struct vattr va, forat;
862 register u_long *tl;
863 register long t1;
864 caddr_t bpos, dpos;
865 int error = 0, rdonly, cache, len, forat_ret = 1;
866 int ioflags, aftat_ret = 1, s, adjust, v3, zeroing;
867 char *cp2;
868 struct mbuf *mb, *mb2, *mreq, *mrep, *md;
869 struct vnode *vp;
870 struct uio io, *uiop = &io;
871 off_t off;
872 u_quad_t frev, cur_usec;
873
874 #ifndef nolint
875 i = 0;
876 len = 0;
877 #endif
878 *mrq = NULL;
879 if (*ndp) {
880 nfsd = *ndp;
881 *ndp = NULL;
882 mrep = nfsd->nd_mrep;
883 md = nfsd->nd_md;
884 dpos = nfsd->nd_dpos;
885 cred = &nfsd->nd_cr;
886 v3 = (nfsd->nd_flag & ND_NFSV3);
887 LIST_INIT(&nfsd->nd_coalesce);
888 nfsd->nd_mreq = NULL;
889 nfsd->nd_stable = NFSV3WRITE_FILESYNC;
890 cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
891 nfsd->nd_time = cur_usec + nfsrvw_procrastinate;
892
893 /*
894 * Now, get the write header..
895 */
896 nfsm_srvmtofh(&nfsd->nd_fh);
897 if (v3) {
898 nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
899 fxdr_hyper(tl, &nfsd->nd_off);
900 tl += 3;
901 nfsd->nd_stable = fxdr_unsigned(int, *tl++);
902 } else {
903 nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
904 nfsd->nd_off = (off_t)fxdr_unsigned(u_long, *++tl);
905 tl += 2;
906 }
907 len = fxdr_unsigned(long, *tl);
908 nfsd->nd_len = len;
909 nfsd->nd_eoff = nfsd->nd_off + len;
910
911 /*
912 * Trim the header out of the mbuf list and trim off any trailing
913 * junk so that the mbuf list has only the write data.
914 */
915 zeroing = 1;
916 i = 0;
917 mp = mrep;
918 while (mp) {
919 if (mp == md) {
920 zeroing = 0;
921 adjust = dpos - mtod(mp, caddr_t);
922 mp->m_len -= adjust;
923 if (mp->m_len > 0 && adjust > 0)
924 NFSMADV(mp, adjust);
925 }
926 if (zeroing)
927 mp->m_len = 0;
928 else {
929 i += mp->m_len;
930 if (i > len) {
931 mp->m_len -= (i - len);
932 zeroing = 1;
933 }
934 }
935 mp = mp->m_next;
936 }
937 if (len > NFS_MAXDATA || len < 0 || i < len) {
938 nfsmout:
939 m_freem(mrep);
940 error = EIO;
941 nfsm_writereply(2 * NFSX_UNSIGNED, v3);
942 if (v3)
943 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
944 nfsd->nd_mreq = mreq;
945 nfsd->nd_mrep = NULL;
946 nfsd->nd_time = 0;
947 }
948
949 /*
950 * Add this entry to the hash and time queues.
951 */
952 s = splsoftclock();
953 owp = NULL;
954 wp = slp->ns_tq.lh_first;
955 while (wp && wp->nd_time < nfsd->nd_time) {
956 owp = wp;
957 wp = wp->nd_tq.le_next;
958 }
959 if (owp) {
960 LIST_INSERT_AFTER(owp, nfsd, nd_tq);
961 } else {
962 LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
963 }
964 if (nfsd->nd_mrep) {
965 wpp = NWDELAYHASH(slp, nfsd->nd_fh.fh_fid.fid_data);
966 owp = NULL;
967 wp = wpp->lh_first;
968 while (wp &&
969 bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
970 owp = wp;
971 wp = wp->nd_hash.le_next;
972 }
973 while (wp && wp->nd_off < nfsd->nd_off &&
974 !bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
975 owp = wp;
976 wp = wp->nd_hash.le_next;
977 }
978 if (owp) {
979 LIST_INSERT_AFTER(owp, nfsd, nd_hash);
980
981 /*
982 * Search the hash list for overlapping entries and
983 * coalesce.
984 */
985 for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) {
986 wp = nfsd->nd_hash.le_next;
987 if (NFSW_SAMECRED(owp, nfsd))
988 nfsrvw_coalesce(owp, nfsd);
989 }
990 } else {
991 LIST_INSERT_HEAD(wpp, nfsd, nd_hash);
992 }
993 }
994 splx(s);
995 }
996
997 /*
998 * Now, do VOP_WRITE()s for any one(s) that need to be done now
999 * and generate the associated reply mbuf list(s).
1000 */
1001 loop1:
1002 cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
1003 s = splsoftclock();
1004 for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = owp) {
1005 owp = nfsd->nd_tq.le_next;
1006 if (nfsd->nd_time > cur_usec)
1007 break;
1008 if (nfsd->nd_mreq)
1009 continue;
1010 LIST_REMOVE(nfsd, nd_tq);
1011 LIST_REMOVE(nfsd, nd_hash);
1012 splx(s);
1013 mrep = nfsd->nd_mrep;
1014 nfsd->nd_mrep = NULL;
1015 cred = &nfsd->nd_cr;
1016 v3 = (nfsd->nd_flag & ND_NFSV3);
1017 forat_ret = aftat_ret = 1;
1018 error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp,
1019 nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH));
1020 if (!error) {
1021 if (v3)
1022 forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
1023 if (vp->v_type != VREG) {
1024 if (v3)
1025 error = EINVAL;
1026 else
1027 error = (vp->v_type == VDIR) ? EISDIR : EACCES;
1028 }
1029 } else
1030 vp = NULL;
1031 if (!error) {
1032 nqsrv_getl(vp, ND_WRITE);
1033 error = nfsrv_access(vp, VWRITE, cred, rdonly, procp);
1034 }
1035
1036 if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE)
1037 ioflags = IO_NODELOCKED;
1038 else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC)
1039 ioflags = (IO_SYNC | IO_NODELOCKED);
1040 else
1041 ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
1042 uiop->uio_rw = UIO_WRITE;
1043 uiop->uio_segflg = UIO_SYSSPACE;
1044 uiop->uio_procp = (struct proc *)0;
1045 uiop->uio_offset = nfsd->nd_off;
1046 uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off;
1047 if (uiop->uio_resid > 0) {
1048 mp = mrep;
1049 i = 0;
1050 while (mp) {
1051 if (mp->m_len > 0)
1052 i++;
1053 mp = mp->m_next;
1054 }
1055 uiop->uio_iovcnt = i;
1056 MALLOC(iov, struct iovec *, i * sizeof (struct iovec),
1057 M_TEMP, M_WAITOK);
1058 uiop->uio_iov = ivp = iov;
1059 mp = mrep;
1060 while (mp) {
1061 if (mp->m_len > 0) {
1062 ivp->iov_base = mtod(mp, caddr_t);
1063 ivp->iov_len = mp->m_len;
1064 ivp++;
1065 }
1066 mp = mp->m_next;
1067 }
1068 if (!error) {
1069 error = VOP_WRITE(vp, uiop, ioflags, cred);
1070 nfsstats.srvvop_writes++;
1071 }
1072 FREE((caddr_t)iov, M_TEMP);
1073 }
1074 m_freem(mrep);
1075 if (vp) {
1076 aftat_ret = VOP_GETATTR(vp, &va, cred, procp);
1077 vput(vp);
1078 }
1079
1080 /*
1081 * Loop around generating replies for all write rpcs that have
1082 * now been completed.
1083 */
1084 swp = nfsd;
1085 do {
1086 if (error) {
1087 nfsm_writereply(NFSX_WCCDATA(v3), v3);
1088 if (v3) {
1089 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1090 }
1091 } else {
1092 nfsm_writereply(NFSX_PREOPATTR(v3) +
1093 NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED +
1094 NFSX_WRITEVERF(v3), v3);
1095 if (v3) {
1096 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1097 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
1098 *tl++ = txdr_unsigned(nfsd->nd_len);
1099 *tl++ = txdr_unsigned(swp->nd_stable);
1100 /*
1101 * Actually, there is no need to txdr these fields,
1102 * but it may make the values more human readable,
1103 * for debugging purposes.
1104 */
1105 *tl++ = txdr_unsigned(boottime.tv_sec);
1106 *tl = txdr_unsigned(boottime.tv_usec);
1107 } else {
1108 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1109 nfsm_srvfillattr(&va, fp);
1110 }
1111 }
1112 nfsd->nd_mreq = mreq;
1113 if (nfsd->nd_mrep)
1114 panic("nfsrv_write: nd_mrep not free");
1115
1116 /*
1117 * Done. Put it at the head of the timer queue so that
1118 * the final phase can return the reply.
1119 */
1120 s = splsoftclock();
1121 if (nfsd != swp) {
1122 nfsd->nd_time = 0;
1123 LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1124 }
1125 nfsd = swp->nd_coalesce.lh_first;
1126 if (nfsd) {
1127 LIST_REMOVE(nfsd, nd_tq);
1128 }
1129 splx(s);
1130 } while (nfsd);
1131 s = splsoftclock();
1132 swp->nd_time = 0;
1133 LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq);
1134 splx(s);
1135 goto loop1;
1136 }
1137 splx(s);
1138
1139 /*
1140 * Search for a reply to return.
1141 */
1142 s = splsoftclock();
1143 for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = nfsd->nd_tq.le_next)
1144 if (nfsd->nd_mreq) {
1145 LIST_REMOVE(nfsd, nd_tq);
1146 *mrq = nfsd->nd_mreq;
1147 *ndp = nfsd;
1148 break;
1149 }
1150 splx(s);
1151 return (0);
1152 }
1153
1154 /*
1155 * Coalesce the write request nfsd into owp. To do this we must:
1156 * - remove nfsd from the queues
1157 * - merge nfsd->nd_mrep into owp->nd_mrep
1158 * - update the nd_eoff and nd_stable for owp
1159 * - put nfsd on owp's nd_coalesce list
1160 * NB: Must be called at splsoftclock().
1161 */
1162 void
nfsrvw_coalesce(owp,nfsd)1163 nfsrvw_coalesce(owp, nfsd)
1164 register struct nfsrv_descript *owp;
1165 register struct nfsrv_descript *nfsd;
1166 {
1167 register int overlap;
1168 register struct mbuf *mp;
1169
1170 LIST_REMOVE(nfsd, nd_hash);
1171 LIST_REMOVE(nfsd, nd_tq);
1172 if (owp->nd_eoff < nfsd->nd_eoff) {
1173 overlap = owp->nd_eoff - nfsd->nd_off;
1174 if (overlap < 0)
1175 panic("nfsrv_coalesce: bad off");
1176 if (overlap > 0)
1177 m_adj(nfsd->nd_mrep, overlap);
1178 mp = owp->nd_mrep;
1179 while (mp->m_next)
1180 mp = mp->m_next;
1181 mp->m_next = nfsd->nd_mrep;
1182 owp->nd_eoff = nfsd->nd_eoff;
1183 } else
1184 m_freem(nfsd->nd_mrep);
1185 nfsd->nd_mrep = NULL;
1186 if (nfsd->nd_stable == NFSV3WRITE_FILESYNC)
1187 owp->nd_stable = NFSV3WRITE_FILESYNC;
1188 else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC &&
1189 owp->nd_stable == NFSV3WRITE_UNSTABLE)
1190 owp->nd_stable = NFSV3WRITE_DATASYNC;
1191 LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq);
1192 }
1193
1194 /*
1195 * Sort the group list in increasing numerical order.
1196 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1197 * that used to be here.)
1198 */
1199 void
nfsrvw_sort(list,num)1200 nfsrvw_sort(list, num)
1201 register gid_t *list;
1202 register int num;
1203 {
1204 register int i, j;
1205 gid_t v;
1206
1207 /* Insertion sort. */
1208 for (i = 1; i < num; i++) {
1209 v = list[i];
1210 /* find correct slot for value v, moving others up */
1211 for (j = i; --j >= 0 && v < list[j];)
1212 list[j + 1] = list[j];
1213 list[j + 1] = v;
1214 }
1215 }
1216
1217 /*
1218 * copy credentials making sure that the result can be compared with bcmp().
1219 */
1220 void
nfsrv_setcred(incred,outcred)1221 nfsrv_setcred(incred, outcred)
1222 register struct ucred *incred, *outcred;
1223 {
1224 register int i;
1225
1226 bzero((caddr_t)outcred, sizeof (struct ucred));
1227 outcred->cr_ref = 1;
1228 outcred->cr_uid = incred->cr_uid;
1229 outcred->cr_ngroups = incred->cr_ngroups;
1230 for (i = 0; i < incred->cr_ngroups; i++)
1231 outcred->cr_groups[i] = incred->cr_groups[i];
1232 nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
1233 }
1234
1235 /*
1236 * nfs create service
1237 * now does a truncate to 0 length via. setattr if it already exists
1238 */
1239 int
nfsrv_create(nfsd,slp,procp,mrq)1240 nfsrv_create(nfsd, slp, procp, mrq)
1241 struct nfsrv_descript *nfsd;
1242 struct nfssvc_sock *slp;
1243 struct proc *procp;
1244 struct mbuf **mrq;
1245 {
1246 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1247 struct mbuf *nam = nfsd->nd_nam;
1248 caddr_t dpos = nfsd->nd_dpos;
1249 struct ucred *cred = &nfsd->nd_cr;
1250 register struct nfs_fattr *fp;
1251 struct vattr va, dirfor, diraft;
1252 register struct vattr *vap = &va;
1253 register struct nfsv2_sattr *sp;
1254 register u_long *tl;
1255 struct nameidata nd;
1256 register caddr_t cp;
1257 register long t1;
1258 caddr_t bpos;
1259 int error = 0, rdev, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1;
1260 int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0;
1261 char *cp2;
1262 struct mbuf *mb, *mb2, *mreq;
1263 struct vnode *vp, *dirp = (struct vnode *)0;
1264 nfsfh_t nfh;
1265 fhandle_t *fhp;
1266 u_quad_t frev, tempsize;
1267 u_char cverf[NFSX_V3CREATEVERF];
1268
1269 #ifndef nolint
1270 rdev = 0;
1271 #endif
1272 nd.ni_cnd.cn_nameiop = 0;
1273 fhp = &nfh.fh_generic;
1274 nfsm_srvmtofh(fhp);
1275 nfsm_srvnamesiz(len);
1276 nd.ni_cnd.cn_cred = cred;
1277 nd.ni_cnd.cn_nameiop = CREATE;
1278 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
1279 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1280 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1281 if (dirp) {
1282 if (v3)
1283 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
1284 procp);
1285 else {
1286 vrele(dirp);
1287 dirp = (struct vnode *)0;
1288 }
1289 }
1290 if (error) {
1291 nfsm_reply(NFSX_WCCDATA(v3));
1292 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1293 if (dirp)
1294 vrele(dirp);
1295 return (0);
1296 }
1297 VATTR_NULL(vap);
1298 if (v3) {
1299 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1300 how = fxdr_unsigned(int, *tl);
1301 switch (how) {
1302 case NFSV3CREATE_GUARDED:
1303 if (nd.ni_vp) {
1304 error = EEXIST;
1305 break;
1306 }
1307 case NFSV3CREATE_UNCHECKED:
1308 nfsm_srvsattr(vap);
1309 break;
1310 case NFSV3CREATE_EXCLUSIVE:
1311 nfsm_dissect(cp, caddr_t, NFSX_V3CREATEVERF);
1312 bcopy(cp, cverf, NFSX_V3CREATEVERF);
1313 exclusive_flag = 1;
1314 if (nd.ni_vp == NULL)
1315 vap->va_mode = 0;
1316 break;
1317 };
1318 vap->va_type = VREG;
1319 } else {
1320 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1321 vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode));
1322 if (vap->va_type == VNON)
1323 vap->va_type = VREG;
1324 vap->va_mode = nfstov_mode(sp->sa_mode);
1325 switch (vap->va_type) {
1326 case VREG:
1327 tsize = fxdr_unsigned(long, sp->sa_size);
1328 if (tsize != -1)
1329 vap->va_size = (u_quad_t)tsize;
1330 break;
1331 case VCHR:
1332 case VBLK:
1333 case VFIFO:
1334 rdev = fxdr_unsigned(long, sp->sa_size);
1335 break;
1336 };
1337 }
1338
1339 /*
1340 * Iff doesn't exist, create it
1341 * otherwise just truncate to 0 length
1342 * should I set the mode too ??
1343 */
1344 if (nd.ni_vp == NULL) {
1345 if (vap->va_type == VREG || vap->va_type == VSOCK) {
1346 vrele(nd.ni_startdir);
1347 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1348 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
1349 if (!error) {
1350 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1351 if (exclusive_flag) {
1352 exclusive_flag = 0;
1353 VATTR_NULL(vap);
1354 bcopy(cverf, (caddr_t)&vap->va_atime,
1355 NFSX_V3CREATEVERF);
1356 error = VOP_SETATTR(nd.ni_vp, vap, cred,
1357 procp);
1358 }
1359 }
1360 } else if (vap->va_type == VCHR || vap->va_type == VBLK ||
1361 vap->va_type == VFIFO) {
1362 if (vap->va_type == VCHR && rdev == 0xffffffff)
1363 vap->va_type = VFIFO;
1364 if (error = suser(cred, (u_short *)0)) {
1365 vrele(nd.ni_startdir);
1366 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1367 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1368 vput(nd.ni_dvp);
1369 nfsm_reply(0);
1370 return (error);
1371 } else
1372 vap->va_rdev = (dev_t)rdev;
1373 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1374 if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) {
1375 vrele(nd.ni_startdir);
1376 nfsm_reply(0);
1377 }
1378 nd.ni_cnd.cn_nameiop = LOOKUP;
1379 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
1380 nd.ni_cnd.cn_proc = procp;
1381 nd.ni_cnd.cn_cred = cred;
1382 if (error = lookup(&nd)) {
1383 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1384 nfsm_reply(0);
1385 }
1386 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1387 if (nd.ni_cnd.cn_flags & ISSYMLINK) {
1388 vrele(nd.ni_dvp);
1389 vput(nd.ni_vp);
1390 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1391 error = EINVAL;
1392 nfsm_reply(0);
1393 }
1394 } else {
1395 vrele(nd.ni_startdir);
1396 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1397 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1398 vput(nd.ni_dvp);
1399 error = ENXIO;
1400 }
1401 vp = nd.ni_vp;
1402 } else {
1403 vrele(nd.ni_startdir);
1404 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1405 vp = nd.ni_vp;
1406 if (nd.ni_dvp == vp)
1407 vrele(nd.ni_dvp);
1408 else
1409 vput(nd.ni_dvp);
1410 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1411 if (vap->va_size != -1) {
1412 error = nfsrv_access(vp, VWRITE, cred,
1413 (nd.ni_cnd.cn_flags & RDONLY), procp);
1414 if (!error) {
1415 nqsrv_getl(vp, ND_WRITE);
1416 tempsize = vap->va_size;
1417 VATTR_NULL(vap);
1418 vap->va_size = tempsize;
1419 error = VOP_SETATTR(vp, vap, cred,
1420 procp);
1421 }
1422 if (error)
1423 vput(vp);
1424 }
1425 }
1426 if (!error) {
1427 bzero((caddr_t)fhp, sizeof(nfh));
1428 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1429 error = VFS_VPTOFH(vp, &fhp->fh_fid);
1430 if (!error)
1431 error = VOP_GETATTR(vp, vap, cred, procp);
1432 vput(vp);
1433 }
1434 if (v3) {
1435 if (exclusive_flag && !error &&
1436 bcmp(cverf, (caddr_t)&vap->va_atime, NFSX_V3CREATEVERF))
1437 error = EEXIST;
1438 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1439 vrele(dirp);
1440 }
1441 nfsm_reply(NFSX_SRVFH(v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3));
1442 if (v3) {
1443 if (!error) {
1444 nfsm_srvpostop_fh(fhp);
1445 nfsm_srvpostop_attr(0, vap);
1446 }
1447 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1448 } else {
1449 nfsm_srvfhtom(fhp, v3);
1450 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1451 nfsm_srvfillattr(vap, fp);
1452 }
1453 return (0);
1454 nfsmout:
1455 if (dirp)
1456 vrele(dirp);
1457 if (nd.ni_cnd.cn_nameiop) {
1458 vrele(nd.ni_startdir);
1459 free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1460 }
1461 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1462 if (nd.ni_dvp == nd.ni_vp)
1463 vrele(nd.ni_dvp);
1464 else
1465 vput(nd.ni_dvp);
1466 if (nd.ni_vp)
1467 vput(nd.ni_vp);
1468 return (error);
1469 }
1470
1471 /*
1472 * nfs v3 mknod service
1473 */
1474 int
nfsrv_mknod(nfsd,slp,procp,mrq)1475 nfsrv_mknod(nfsd, slp, procp, mrq)
1476 struct nfsrv_descript *nfsd;
1477 struct nfssvc_sock *slp;
1478 struct proc *procp;
1479 struct mbuf **mrq;
1480 {
1481 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1482 struct mbuf *nam = nfsd->nd_nam;
1483 caddr_t dpos = nfsd->nd_dpos;
1484 struct ucred *cred = &nfsd->nd_cr;
1485 register struct nfs_fattr *fp;
1486 struct vattr va, dirfor, diraft;
1487 register struct vattr *vap = &va;
1488 register u_long *tl;
1489 struct nameidata nd;
1490 register caddr_t cp;
1491 register long t1;
1492 caddr_t bpos;
1493 int error = 0, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1;
1494 u_long major, minor;
1495 enum vtype vtyp;
1496 char *cp2;
1497 struct mbuf *mb, *mb2, *mreq;
1498 struct vnode *vp, *dirp = (struct vnode *)0;
1499 nfsfh_t nfh;
1500 fhandle_t *fhp;
1501 u_quad_t frev;
1502
1503 nd.ni_cnd.cn_nameiop = 0;
1504 fhp = &nfh.fh_generic;
1505 nfsm_srvmtofh(fhp);
1506 nfsm_srvnamesiz(len);
1507 nd.ni_cnd.cn_cred = cred;
1508 nd.ni_cnd.cn_nameiop = CREATE;
1509 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
1510 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1511 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1512 if (dirp)
1513 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp);
1514 if (error) {
1515 nfsm_reply(NFSX_WCCDATA(1));
1516 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1517 if (dirp)
1518 vrele(dirp);
1519 return (0);
1520 }
1521 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1522 vtyp = nfsv3tov_type(*tl);
1523 if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
1524 vrele(nd.ni_startdir);
1525 free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1526 error = NFSERR_BADTYPE;
1527 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1528 vput(nd.ni_dvp);
1529 goto out;
1530 }
1531 VATTR_NULL(vap);
1532 nfsm_srvsattr(vap);
1533 if (vtyp == VCHR || vtyp == VBLK) {
1534 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
1535 major = fxdr_unsigned(u_long, *tl++);
1536 minor = fxdr_unsigned(u_long, *tl);
1537 vap->va_rdev = makedev(major, minor);
1538 }
1539
1540 /*
1541 * Iff doesn't exist, create it.
1542 */
1543 if (nd.ni_vp) {
1544 vrele(nd.ni_startdir);
1545 free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1546 error = EEXIST;
1547 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1548 vput(nd.ni_dvp);
1549 goto out;
1550 }
1551 vap->va_type = vtyp;
1552 if (vtyp == VSOCK) {
1553 vrele(nd.ni_startdir);
1554 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1555 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
1556 if (!error)
1557 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1558 } else {
1559 if (error = suser(cred, (u_short *)0)) {
1560 vrele(nd.ni_startdir);
1561 free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1562 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1563 vput(nd.ni_dvp);
1564 goto out;
1565 }
1566 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1567 if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) {
1568 vrele(nd.ni_startdir);
1569 goto out;
1570 }
1571 nd.ni_cnd.cn_nameiop = LOOKUP;
1572 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
1573 nd.ni_cnd.cn_proc = procp;
1574 nd.ni_cnd.cn_cred = procp->p_ucred;
1575 error = lookup(&nd);
1576 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1577 if (error)
1578 goto out;
1579 if (nd.ni_cnd.cn_flags & ISSYMLINK) {
1580 vrele(nd.ni_dvp);
1581 vput(nd.ni_vp);
1582 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1583 error = EINVAL;
1584 }
1585 }
1586 out:
1587 vp = nd.ni_vp;
1588 if (!error) {
1589 bzero((caddr_t)fhp, sizeof(nfh));
1590 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1591 error = VFS_VPTOFH(vp, &fhp->fh_fid);
1592 if (!error)
1593 error = VOP_GETATTR(vp, vap, cred, procp);
1594 vput(vp);
1595 }
1596 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1597 vrele(dirp);
1598 nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
1599 if (!error) {
1600 nfsm_srvpostop_fh(fhp);
1601 nfsm_srvpostop_attr(0, vap);
1602 }
1603 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1604 return (0);
1605 nfsmout:
1606 if (dirp)
1607 vrele(dirp);
1608 if (nd.ni_cnd.cn_nameiop) {
1609 vrele(nd.ni_startdir);
1610 free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1611 }
1612 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1613 if (nd.ni_dvp == nd.ni_vp)
1614 vrele(nd.ni_dvp);
1615 else
1616 vput(nd.ni_dvp);
1617 if (nd.ni_vp)
1618 vput(nd.ni_vp);
1619 return (error);
1620 }
1621
1622 /*
1623 * nfs remove service
1624 */
1625 int
nfsrv_remove(nfsd,slp,procp,mrq)1626 nfsrv_remove(nfsd, slp, procp, mrq)
1627 struct nfsrv_descript *nfsd;
1628 struct nfssvc_sock *slp;
1629 struct proc *procp;
1630 struct mbuf **mrq;
1631 {
1632 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1633 struct mbuf *nam = nfsd->nd_nam;
1634 caddr_t dpos = nfsd->nd_dpos;
1635 struct ucred *cred = &nfsd->nd_cr;
1636 struct nameidata nd;
1637 register u_long *tl;
1638 register long t1;
1639 caddr_t bpos;
1640 int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
1641 int v3 = (nfsd->nd_flag & ND_NFSV3);
1642 char *cp2;
1643 struct mbuf *mb, *mreq, *mb2;
1644 struct vnode *vp, *dirp;
1645 struct vattr dirfor, diraft;
1646 nfsfh_t nfh;
1647 fhandle_t *fhp;
1648 u_quad_t frev;
1649
1650 #ifndef nolint
1651 vp = (struct vnode *)0;
1652 #endif
1653 fhp = &nfh.fh_generic;
1654 nfsm_srvmtofh(fhp);
1655 nfsm_srvnamesiz(len);
1656 nd.ni_cnd.cn_cred = cred;
1657 nd.ni_cnd.cn_nameiop = DELETE;
1658 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1659 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1660 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1661 if (dirp) {
1662 if (v3)
1663 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
1664 procp);
1665 else
1666 vrele(dirp);
1667 }
1668 if (!error) {
1669 vp = nd.ni_vp;
1670 if (vp->v_type == VDIR &&
1671 (error = suser(cred, (u_short *)0)))
1672 goto out;
1673 /*
1674 * The root of a mounted filesystem cannot be deleted.
1675 */
1676 if (vp->v_flag & VROOT) {
1677 error = EBUSY;
1678 goto out;
1679 }
1680 if (vp->v_flag & VTEXT)
1681 (void) vnode_pager_uncache(vp);
1682 out:
1683 if (!error) {
1684 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1685 nqsrv_getl(vp, ND_WRITE);
1686 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1687 } else {
1688 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1689 if (nd.ni_dvp == vp)
1690 vrele(nd.ni_dvp);
1691 else
1692 vput(nd.ni_dvp);
1693 vput(vp);
1694 }
1695 }
1696 if (dirp && v3) {
1697 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1698 vrele(dirp);
1699 }
1700 nfsm_reply(NFSX_WCCDATA(v3));
1701 if (v3) {
1702 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1703 return (0);
1704 }
1705 nfsm_srvdone;
1706 }
1707
1708 /*
1709 * nfs rename service
1710 */
1711 int
nfsrv_rename(nfsd,slp,procp,mrq)1712 nfsrv_rename(nfsd, slp, procp, mrq)
1713 struct nfsrv_descript *nfsd;
1714 struct nfssvc_sock *slp;
1715 struct proc *procp;
1716 struct mbuf **mrq;
1717 {
1718 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1719 struct mbuf *nam = nfsd->nd_nam;
1720 caddr_t dpos = nfsd->nd_dpos;
1721 struct ucred *cred = &nfsd->nd_cr;
1722 register u_long *tl;
1723 register long t1;
1724 caddr_t bpos;
1725 int error = 0, cache, len, len2, fdirfor_ret = 1, fdiraft_ret = 1;
1726 int tdirfor_ret = 1, tdiraft_ret = 1;
1727 int v3 = (nfsd->nd_flag & ND_NFSV3);
1728 char *cp2;
1729 struct mbuf *mb, *mreq, *mb2;
1730 struct nameidata fromnd, tond;
1731 struct vnode *fvp, *tvp, *tdvp, *fdirp = (struct vnode *)0;
1732 struct vnode *tdirp = (struct vnode *)0;
1733 struct vattr fdirfor, fdiraft, tdirfor, tdiraft;
1734 nfsfh_t fnfh, tnfh;
1735 fhandle_t *ffhp, *tfhp;
1736 u_quad_t frev;
1737 uid_t saved_uid;
1738
1739 #ifndef nolint
1740 fvp = (struct vnode *)0;
1741 #endif
1742 ffhp = &fnfh.fh_generic;
1743 tfhp = &tnfh.fh_generic;
1744 fromnd.ni_cnd.cn_nameiop = 0;
1745 tond.ni_cnd.cn_nameiop = 0;
1746 nfsm_srvmtofh(ffhp);
1747 nfsm_srvnamesiz(len);
1748 /*
1749 * Remember our original uid so that we can reset cr_uid before
1750 * the second nfs_namei() call, in case it is remapped.
1751 */
1752 saved_uid = cred->cr_uid;
1753 fromnd.ni_cnd.cn_cred = cred;
1754 fromnd.ni_cnd.cn_nameiop = DELETE;
1755 fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART;
1756 error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md,
1757 &dpos, &fdirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1758 if (fdirp) {
1759 if (v3)
1760 fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred,
1761 procp);
1762 else {
1763 vrele(fdirp);
1764 fdirp = (struct vnode *)0;
1765 }
1766 }
1767 if (error) {
1768 nfsm_reply(2 * NFSX_WCCDATA(v3));
1769 nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1770 nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1771 if (fdirp)
1772 vrele(fdirp);
1773 return (0);
1774 }
1775 fvp = fromnd.ni_vp;
1776 nfsm_srvmtofh(tfhp);
1777 nfsm_strsiz(len2, NFS_MAXNAMLEN);
1778 cred->cr_uid = saved_uid;
1779 tond.ni_cnd.cn_cred = cred;
1780 tond.ni_cnd.cn_nameiop = RENAME;
1781 tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
1782 error = nfs_namei(&tond, tfhp, len2, slp, nam, &md,
1783 &dpos, &tdirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1784 if (tdirp) {
1785 if (v3)
1786 tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred,
1787 procp);
1788 else {
1789 vrele(tdirp);
1790 tdirp = (struct vnode *)0;
1791 }
1792 }
1793 if (error) {
1794 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1795 vrele(fromnd.ni_dvp);
1796 vrele(fvp);
1797 goto out1;
1798 }
1799 tdvp = tond.ni_dvp;
1800 tvp = tond.ni_vp;
1801 if (tvp != NULL) {
1802 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
1803 if (v3)
1804 error = EEXIST;
1805 else
1806 error = EISDIR;
1807 goto out;
1808 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1809 if (v3)
1810 error = EEXIST;
1811 else
1812 error = ENOTDIR;
1813 goto out;
1814 }
1815 if (tvp->v_type == VDIR && tvp->v_mountedhere) {
1816 if (v3)
1817 error = EXDEV;
1818 else
1819 error = ENOTEMPTY;
1820 goto out;
1821 }
1822 }
1823 if (fvp->v_type == VDIR && fvp->v_mountedhere) {
1824 if (v3)
1825 error = EXDEV;
1826 else
1827 error = ENOTEMPTY;
1828 goto out;
1829 }
1830 if (fvp->v_mount != tdvp->v_mount) {
1831 if (v3)
1832 error = EXDEV;
1833 else
1834 error = ENOTEMPTY;
1835 goto out;
1836 }
1837 if (fvp == tdvp)
1838 if (v3)
1839 error = EINVAL;
1840 else
1841 error = ENOTEMPTY;
1842 /*
1843 * If source is the same as the destination (that is the
1844 * same vnode with the same name in the same directory),
1845 * then there is nothing to do.
1846 */
1847 if (fvp == tvp && fromnd.ni_dvp == tdvp &&
1848 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
1849 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
1850 fromnd.ni_cnd.cn_namelen))
1851 error = -1;
1852 out:
1853 if (!error) {
1854 nqsrv_getl(fromnd.ni_dvp, ND_WRITE);
1855 nqsrv_getl(tdvp, ND_WRITE);
1856 if (tvp)
1857 nqsrv_getl(tvp, ND_WRITE);
1858 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
1859 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
1860 } else {
1861 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
1862 if (tdvp == tvp)
1863 vrele(tdvp);
1864 else
1865 vput(tdvp);
1866 if (tvp)
1867 vput(tvp);
1868 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1869 vrele(fromnd.ni_dvp);
1870 vrele(fvp);
1871 if (error == -1)
1872 error = 0;
1873 }
1874 vrele(tond.ni_startdir);
1875 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
1876 out1:
1877 if (fdirp) {
1878 fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, procp);
1879 vrele(fdirp);
1880 }
1881 if (tdirp) {
1882 tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, procp);
1883 vrele(tdirp);
1884 }
1885 vrele(fromnd.ni_startdir);
1886 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
1887 nfsm_reply(2 * NFSX_WCCDATA(v3));
1888 if (v3) {
1889 nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1890 nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1891 }
1892 return (0);
1893
1894 nfsmout:
1895 if (fdirp)
1896 vrele(fdirp);
1897 if (tdirp)
1898 vrele(tdirp);
1899 if (tond.ni_cnd.cn_nameiop) {
1900 vrele(tond.ni_startdir);
1901 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
1902 }
1903 if (fromnd.ni_cnd.cn_nameiop) {
1904 vrele(fromnd.ni_startdir);
1905 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
1906 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1907 vrele(fromnd.ni_dvp);
1908 vrele(fvp);
1909 }
1910 return (error);
1911 }
1912
1913 /*
1914 * nfs link service
1915 */
1916 int
nfsrv_link(nfsd,slp,procp,mrq)1917 nfsrv_link(nfsd, slp, procp, mrq)
1918 struct nfsrv_descript *nfsd;
1919 struct nfssvc_sock *slp;
1920 struct proc *procp;
1921 struct mbuf **mrq;
1922 {
1923 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1924 struct mbuf *nam = nfsd->nd_nam;
1925 caddr_t dpos = nfsd->nd_dpos;
1926 struct ucred *cred = &nfsd->nd_cr;
1927 struct nameidata nd;
1928 register u_long *tl;
1929 register long t1;
1930 caddr_t bpos;
1931 int error = 0, rdonly, cache, len, dirfor_ret = 1, diraft_ret = 1;
1932 int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3);
1933 char *cp2;
1934 struct mbuf *mb, *mreq, *mb2;
1935 struct vnode *vp, *xp, *dirp = (struct vnode *)0;
1936 struct vattr dirfor, diraft, at;
1937 nfsfh_t nfh, dnfh;
1938 fhandle_t *fhp, *dfhp;
1939 u_quad_t frev;
1940
1941 fhp = &nfh.fh_generic;
1942 dfhp = &dnfh.fh_generic;
1943 nfsm_srvmtofh(fhp);
1944 nfsm_srvmtofh(dfhp);
1945 nfsm_srvnamesiz(len);
1946 if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, slp, nam,
1947 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
1948 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
1949 nfsm_srvpostop_attr(getret, &at);
1950 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1951 return (0);
1952 }
1953 if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0)))
1954 goto out1;
1955 nd.ni_cnd.cn_cred = cred;
1956 nd.ni_cnd.cn_nameiop = CREATE;
1957 nd.ni_cnd.cn_flags = LOCKPARENT;
1958 error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos,
1959 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1960 if (dirp) {
1961 if (v3)
1962 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
1963 procp);
1964 else {
1965 vrele(dirp);
1966 dirp = (struct vnode *)0;
1967 }
1968 }
1969 if (error)
1970 goto out1;
1971 xp = nd.ni_vp;
1972 if (xp != NULL) {
1973 error = EEXIST;
1974 goto out;
1975 }
1976 xp = nd.ni_dvp;
1977 if (vp->v_mount != xp->v_mount)
1978 error = EXDEV;
1979 out:
1980 if (!error) {
1981 nqsrv_getl(vp, ND_WRITE);
1982 nqsrv_getl(xp, ND_WRITE);
1983 error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd);
1984 } else {
1985 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1986 if (nd.ni_dvp == nd.ni_vp)
1987 vrele(nd.ni_dvp);
1988 else
1989 vput(nd.ni_dvp);
1990 if (nd.ni_vp)
1991 vrele(nd.ni_vp);
1992 }
1993 out1:
1994 if (v3)
1995 getret = VOP_GETATTR(vp, &at, cred, procp);
1996 if (dirp) {
1997 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1998 vrele(dirp);
1999 }
2000 vrele(vp);
2001 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2002 if (v3) {
2003 nfsm_srvpostop_attr(getret, &at);
2004 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2005 return (0);
2006 }
2007 nfsm_srvdone;
2008 }
2009
2010 /*
2011 * nfs symbolic link service
2012 */
2013 int
nfsrv_symlink(nfsd,slp,procp,mrq)2014 nfsrv_symlink(nfsd, slp, procp, mrq)
2015 struct nfsrv_descript *nfsd;
2016 struct nfssvc_sock *slp;
2017 struct proc *procp;
2018 struct mbuf **mrq;
2019 {
2020 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2021 struct mbuf *nam = nfsd->nd_nam;
2022 caddr_t dpos = nfsd->nd_dpos;
2023 struct ucred *cred = &nfsd->nd_cr;
2024 struct vattr va, dirfor, diraft;
2025 struct nameidata nd;
2026 register struct vattr *vap = &va;
2027 register u_long *tl;
2028 register long t1;
2029 struct nfsv2_sattr *sp;
2030 char *bpos, *cp, *pathcp = (char *)0, *cp2;
2031 struct uio io;
2032 struct iovec iv;
2033 int error = 0, cache, len, len2, dirfor_ret = 1, diraft_ret = 1;
2034 int v3 = (nfsd->nd_flag & ND_NFSV3);
2035 struct mbuf *mb, *mreq, *mb2;
2036 struct vnode *dirp = (struct vnode *)0;
2037 nfsfh_t nfh;
2038 fhandle_t *fhp;
2039 u_quad_t frev;
2040
2041 nd.ni_cnd.cn_nameiop = 0;
2042 fhp = &nfh.fh_generic;
2043 nfsm_srvmtofh(fhp);
2044 nfsm_srvnamesiz(len);
2045 nd.ni_cnd.cn_cred = cred;
2046 nd.ni_cnd.cn_nameiop = CREATE;
2047 nd.ni_cnd.cn_flags = LOCKPARENT | SAVESTART;
2048 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2049 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
2050 if (dirp) {
2051 if (v3)
2052 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2053 procp);
2054 else {
2055 vrele(dirp);
2056 dirp = (struct vnode *)0;
2057 }
2058 }
2059 if (error)
2060 goto out;
2061 VATTR_NULL(vap);
2062 if (v3)
2063 nfsm_srvsattr(vap);
2064 nfsm_strsiz(len2, NFS_MAXPATHLEN);
2065 MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK);
2066 iv.iov_base = pathcp;
2067 iv.iov_len = len2;
2068 io.uio_resid = len2;
2069 io.uio_offset = 0;
2070 io.uio_iov = &iv;
2071 io.uio_iovcnt = 1;
2072 io.uio_segflg = UIO_SYSSPACE;
2073 io.uio_rw = UIO_READ;
2074 io.uio_procp = (struct proc *)0;
2075 nfsm_mtouio(&io, len2);
2076 if (!v3) {
2077 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
2078 vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode);
2079 }
2080 *(pathcp + len2) = '\0';
2081 if (nd.ni_vp) {
2082 vrele(nd.ni_startdir);
2083 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
2084 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2085 if (nd.ni_dvp == nd.ni_vp)
2086 vrele(nd.ni_dvp);
2087 else
2088 vput(nd.ni_dvp);
2089 vrele(nd.ni_vp);
2090 error = EEXIST;
2091 goto out;
2092 }
2093 nqsrv_getl(nd.ni_dvp, ND_WRITE);
2094 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp);
2095 if (error)
2096 vrele(nd.ni_startdir);
2097 else {
2098 if (v3) {
2099 nd.ni_cnd.cn_nameiop = LOOKUP;
2100 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART | FOLLOW);
2101 nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF);
2102 nd.ni_cnd.cn_proc = procp;
2103 nd.ni_cnd.cn_cred = cred;
2104 error = lookup(&nd);
2105 if (!error) {
2106 bzero((caddr_t)fhp, sizeof(nfh));
2107 fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid;
2108 error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid);
2109 if (!error)
2110 error = VOP_GETATTR(nd.ni_vp, vap, cred,
2111 procp);
2112 vput(nd.ni_vp);
2113 }
2114 } else
2115 vrele(nd.ni_startdir);
2116 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
2117 }
2118 out:
2119 if (pathcp)
2120 FREE(pathcp, M_TEMP);
2121 if (dirp) {
2122 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2123 vrele(dirp);
2124 }
2125 nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2126 if (v3) {
2127 if (!error) {
2128 nfsm_srvpostop_fh(fhp);
2129 nfsm_srvpostop_attr(0, vap);
2130 }
2131 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2132 }
2133 return (0);
2134 nfsmout:
2135 if (nd.ni_cnd.cn_nameiop) {
2136 vrele(nd.ni_startdir);
2137 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
2138 }
2139 if (dirp)
2140 vrele(dirp);
2141 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2142 if (nd.ni_dvp == nd.ni_vp)
2143 vrele(nd.ni_dvp);
2144 else
2145 vput(nd.ni_dvp);
2146 if (nd.ni_vp)
2147 vrele(nd.ni_vp);
2148 if (pathcp)
2149 FREE(pathcp, M_TEMP);
2150 return (error);
2151 }
2152
2153 /*
2154 * nfs mkdir service
2155 */
2156 int
nfsrv_mkdir(nfsd,slp,procp,mrq)2157 nfsrv_mkdir(nfsd, slp, procp, mrq)
2158 struct nfsrv_descript *nfsd;
2159 struct nfssvc_sock *slp;
2160 struct proc *procp;
2161 struct mbuf **mrq;
2162 {
2163 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2164 struct mbuf *nam = nfsd->nd_nam;
2165 caddr_t dpos = nfsd->nd_dpos;
2166 struct ucred *cred = &nfsd->nd_cr;
2167 struct vattr va, dirfor, diraft;
2168 register struct vattr *vap = &va;
2169 register struct nfs_fattr *fp;
2170 struct nameidata nd;
2171 register caddr_t cp;
2172 register u_long *tl;
2173 register long t1;
2174 caddr_t bpos;
2175 int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
2176 int v3 = (nfsd->nd_flag & ND_NFSV3);
2177 char *cp2;
2178 struct mbuf *mb, *mb2, *mreq;
2179 struct vnode *vp, *dirp = (struct vnode *)0;
2180 nfsfh_t nfh;
2181 fhandle_t *fhp;
2182 u_quad_t frev;
2183
2184 fhp = &nfh.fh_generic;
2185 nfsm_srvmtofh(fhp);
2186 nfsm_srvnamesiz(len);
2187 nd.ni_cnd.cn_cred = cred;
2188 nd.ni_cnd.cn_nameiop = CREATE;
2189 nd.ni_cnd.cn_flags = LOCKPARENT;
2190 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2191 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
2192 if (dirp) {
2193 if (v3)
2194 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2195 procp);
2196 else {
2197 vrele(dirp);
2198 dirp = (struct vnode *)0;
2199 }
2200 }
2201 if (error) {
2202 nfsm_reply(NFSX_WCCDATA(v3));
2203 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2204 if (dirp)
2205 vrele(dirp);
2206 return (0);
2207 }
2208 VATTR_NULL(vap);
2209 if (v3) {
2210 nfsm_srvsattr(vap);
2211 } else {
2212 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2213 vap->va_mode = nfstov_mode(*tl++);
2214 }
2215 vap->va_type = VDIR;
2216 vp = nd.ni_vp;
2217 if (vp != NULL) {
2218 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2219 if (nd.ni_dvp == vp)
2220 vrele(nd.ni_dvp);
2221 else
2222 vput(nd.ni_dvp);
2223 vrele(vp);
2224 error = EEXIST;
2225 goto out;
2226 }
2227 nqsrv_getl(nd.ni_dvp, ND_WRITE);
2228 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
2229 if (!error) {
2230 vp = nd.ni_vp;
2231 bzero((caddr_t)fhp, sizeof(nfh));
2232 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
2233 error = VFS_VPTOFH(vp, &fhp->fh_fid);
2234 if (!error)
2235 error = VOP_GETATTR(vp, vap, cred, procp);
2236 vput(vp);
2237 }
2238 out:
2239 if (dirp) {
2240 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2241 vrele(dirp);
2242 }
2243 nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2244 if (v3) {
2245 if (!error) {
2246 nfsm_srvpostop_fh(fhp);
2247 nfsm_srvpostop_attr(0, vap);
2248 }
2249 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2250 } else {
2251 nfsm_srvfhtom(fhp, v3);
2252 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
2253 nfsm_srvfillattr(vap, fp);
2254 }
2255 return (0);
2256 nfsmout:
2257 if (dirp)
2258 vrele(dirp);
2259 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2260 if (nd.ni_dvp == nd.ni_vp)
2261 vrele(nd.ni_dvp);
2262 else
2263 vput(nd.ni_dvp);
2264 if (nd.ni_vp)
2265 vrele(nd.ni_vp);
2266 return (error);
2267 }
2268
2269 /*
2270 * nfs rmdir service
2271 */
2272 int
nfsrv_rmdir(nfsd,slp,procp,mrq)2273 nfsrv_rmdir(nfsd, slp, procp, mrq)
2274 struct nfsrv_descript *nfsd;
2275 struct nfssvc_sock *slp;
2276 struct proc *procp;
2277 struct mbuf **mrq;
2278 {
2279 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2280 struct mbuf *nam = nfsd->nd_nam;
2281 caddr_t dpos = nfsd->nd_dpos;
2282 struct ucred *cred = &nfsd->nd_cr;
2283 register u_long *tl;
2284 register long t1;
2285 caddr_t bpos;
2286 int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
2287 int v3 = (nfsd->nd_flag & ND_NFSV3);
2288 char *cp2;
2289 struct mbuf *mb, *mreq, *mb2;
2290 struct vnode *vp, *dirp = (struct vnode *)0;
2291 struct vattr dirfor, diraft;
2292 nfsfh_t nfh;
2293 fhandle_t *fhp;
2294 struct nameidata nd;
2295 u_quad_t frev;
2296
2297 fhp = &nfh.fh_generic;
2298 nfsm_srvmtofh(fhp);
2299 nfsm_srvnamesiz(len);
2300 nd.ni_cnd.cn_cred = cred;
2301 nd.ni_cnd.cn_nameiop = DELETE;
2302 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
2303 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2304 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
2305 if (dirp) {
2306 if (v3)
2307 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2308 procp);
2309 else {
2310 vrele(dirp);
2311 dirp = (struct vnode *)0;
2312 }
2313 }
2314 if (error) {
2315 nfsm_reply(NFSX_WCCDATA(v3));
2316 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2317 if (dirp)
2318 vrele(dirp);
2319 return (0);
2320 }
2321 vp = nd.ni_vp;
2322 if (vp->v_type != VDIR) {
2323 error = ENOTDIR;
2324 goto out;
2325 }
2326 /*
2327 * No rmdir "." please.
2328 */
2329 if (nd.ni_dvp == vp) {
2330 error = EINVAL;
2331 goto out;
2332 }
2333 /*
2334 * The root of a mounted filesystem cannot be deleted.
2335 */
2336 if (vp->v_flag & VROOT)
2337 error = EBUSY;
2338 out:
2339 if (!error) {
2340 nqsrv_getl(nd.ni_dvp, ND_WRITE);
2341 nqsrv_getl(vp, ND_WRITE);
2342 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2343 } else {
2344 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2345 if (nd.ni_dvp == nd.ni_vp)
2346 vrele(nd.ni_dvp);
2347 else
2348 vput(nd.ni_dvp);
2349 vput(vp);
2350 }
2351 if (dirp) {
2352 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2353 vrele(dirp);
2354 }
2355 nfsm_reply(NFSX_WCCDATA(v3));
2356 if (v3) {
2357 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2358 return (0);
2359 }
2360 nfsm_srvdone;
2361 }
2362
2363 /*
2364 * nfs readdir service
2365 * - mallocs what it thinks is enough to read
2366 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
2367 * - calls VOP_READDIR()
2368 * - loops around building the reply
2369 * if the output generated exceeds count break out of loop
2370 * The nfsm_clget macro is used here so that the reply will be packed
2371 * tightly in mbuf clusters.
2372 * - it only knows that it has encountered eof when the VOP_READDIR()
2373 * reads nothing
2374 * - as such one readdir rpc will return eof false although you are there
2375 * and then the next will return eof
2376 * - it trims out records with d_fileno == 0
2377 * this doesn't matter for Unix clients, but they might confuse clients
2378 * for other os'.
2379 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
2380 * than requested, but this may not apply to all filesystems. For
2381 * example, client NFS does not { although it is never remote mounted
2382 * anyhow }
2383 * The alternate call nfsrv_readdirplus() does lookups as well.
2384 * PS: The NFS protocol spec. does not clarify what the "count" byte
2385 * argument is a count of.. just name strings and file id's or the
2386 * entire reply rpc or ...
2387 * I tried just file name and id sizes and it confused the Sun client,
2388 * so I am using the full rpc size now. The "paranoia.." comment refers
2389 * to including the status longwords that are not a part of the dir.
2390 * "entry" structures, but are in the rpc.
2391 */
2392 struct flrep {
2393 nfsuint64 fl_off;
2394 u_long fl_postopok;
2395 u_long fl_fattr[NFSX_V3FATTR / sizeof (u_long)];
2396 u_long fl_fhok;
2397 u_long fl_fhsize;
2398 u_long fl_nfh[NFSX_V3FH / sizeof (u_long)];
2399 };
2400
2401 int
nfsrv_readdir(nfsd,slp,procp,mrq)2402 nfsrv_readdir(nfsd, slp, procp, mrq)
2403 struct nfsrv_descript *nfsd;
2404 struct nfssvc_sock *slp;
2405 struct proc *procp;
2406 struct mbuf **mrq;
2407 {
2408 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2409 struct mbuf *nam = nfsd->nd_nam;
2410 caddr_t dpos = nfsd->nd_dpos;
2411 struct ucred *cred = &nfsd->nd_cr;
2412 register char *bp, *be;
2413 register struct mbuf *mp;
2414 register struct dirent *dp;
2415 register caddr_t cp;
2416 register u_long *tl;
2417 register long t1;
2418 caddr_t bpos;
2419 struct mbuf *mb, *mb2, *mreq, *mp2;
2420 char *cpos, *cend, *cp2, *rbuf;
2421 struct vnode *vp;
2422 struct vattr at;
2423 nfsfh_t nfh;
2424 fhandle_t *fhp;
2425 struct uio io;
2426 struct iovec iv;
2427 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
2428 int siz, cnt, fullsiz, eofflag, rdonly, cache, ncookies;
2429 int v3 = (nfsd->nd_flag & ND_NFSV3);
2430 u_quad_t frev, off, toff, verf;
2431 u_long *cookies = NULL, *cookiep;
2432
2433 fhp = &nfh.fh_generic;
2434 nfsm_srvmtofh(fhp);
2435 if (v3) {
2436 nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
2437 fxdr_hyper(tl, &toff);
2438 tl += 2;
2439 fxdr_hyper(tl, &verf);
2440 tl += 2;
2441 } else {
2442 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2443 toff = fxdr_unsigned(u_quad_t, *tl++);
2444 }
2445 off = toff;
2446 cnt = fxdr_unsigned(int, *tl);
2447 siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
2448 xfer = NFS_SRVMAXDATA(nfsd);
2449 if (siz > xfer)
2450 siz = xfer;
2451 fullsiz = siz;
2452 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
2453 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
2454 nfsm_reply(NFSX_UNSIGNED);
2455 nfsm_srvpostop_attr(getret, &at);
2456 return (0);
2457 }
2458 nqsrv_getl(vp, ND_READ);
2459 if (v3) {
2460 error = getret = VOP_GETATTR(vp, &at, cred, procp);
2461 if (!error && toff && verf != at.va_filerev)
2462 error = NFSERR_BAD_COOKIE;
2463 }
2464 if (!error)
2465 error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
2466 if (error) {
2467 vput(vp);
2468 nfsm_reply(NFSX_POSTOPATTR(v3));
2469 nfsm_srvpostop_attr(getret, &at);
2470 return (0);
2471 }
2472 VOP_UNLOCK(vp, 0, procp);
2473 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
2474 again:
2475 iv.iov_base = rbuf;
2476 iv.iov_len = fullsiz;
2477 io.uio_iov = &iv;
2478 io.uio_iovcnt = 1;
2479 io.uio_offset = (off_t)off;
2480 io.uio_resid = fullsiz;
2481 io.uio_segflg = UIO_SYSSPACE;
2482 io.uio_rw = UIO_READ;
2483 io.uio_procp = (struct proc *)0;
2484 eofflag = 0;
2485 if (cookies) {
2486 free((caddr_t)cookies, M_TEMP);
2487 cookies = NULL;
2488 }
2489 error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
2490 off = (off_t)io.uio_offset;
2491 if (!cookies && !error)
2492 error = NFSERR_PERM;
2493 if (v3) {
2494 getret = VOP_GETATTR(vp, &at, cred, procp);
2495 if (!error)
2496 error = getret;
2497 }
2498 if (error) {
2499 vrele(vp);
2500 free((caddr_t)rbuf, M_TEMP);
2501 if (cookies)
2502 free((caddr_t)cookies, M_TEMP);
2503 nfsm_reply(NFSX_POSTOPATTR(v3));
2504 nfsm_srvpostop_attr(getret, &at);
2505 return (0);
2506 }
2507 if (io.uio_resid) {
2508 siz -= io.uio_resid;
2509
2510 /*
2511 * If nothing read, return eof
2512 * rpc reply
2513 */
2514 if (siz == 0) {
2515 vrele(vp);
2516 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
2517 2 * NFSX_UNSIGNED);
2518 if (v3) {
2519 nfsm_srvpostop_attr(getret, &at);
2520 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
2521 txdr_hyper(&at.va_filerev, tl);
2522 tl += 2;
2523 } else
2524 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
2525 *tl++ = nfs_false;
2526 *tl = nfs_true;
2527 FREE((caddr_t)rbuf, M_TEMP);
2528 FREE((caddr_t)cookies, M_TEMP);
2529 return (0);
2530 }
2531 }
2532
2533 /*
2534 * Check for degenerate cases of nothing useful read.
2535 * If so go try again
2536 */
2537 cpos = rbuf;
2538 cend = rbuf + siz;
2539 dp = (struct dirent *)cpos;
2540 cookiep = cookies;
2541 while (dp->d_fileno == 0 && cpos < cend && ncookies > 0) {
2542 cpos += dp->d_reclen;
2543 dp = (struct dirent *)cpos;
2544 cookiep++;
2545 ncookies--;
2546 }
2547 if (cpos >= cend || ncookies == 0) {
2548 toff = off;
2549 siz = fullsiz;
2550 goto again;
2551 }
2552
2553 len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */
2554 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
2555 if (v3) {
2556 nfsm_srvpostop_attr(getret, &at);
2557 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
2558 txdr_hyper(&at.va_filerev, tl);
2559 }
2560 mp = mp2 = mb;
2561 bp = bpos;
2562 be = bp + M_TRAILINGSPACE(mp);
2563
2564 /* Loop through the records and build reply */
2565 while (cpos < cend && ncookies > 0) {
2566 if (dp->d_fileno != 0) {
2567 nlen = dp->d_namlen;
2568 rem = nfsm_rndup(nlen)-nlen;
2569 len += (4 * NFSX_UNSIGNED + nlen + rem);
2570 if (v3)
2571 len += 2 * NFSX_UNSIGNED;
2572 if (len > cnt) {
2573 eofflag = 0;
2574 break;
2575 }
2576 /*
2577 * Build the directory record xdr from
2578 * the dirent entry.
2579 */
2580 nfsm_clget;
2581 *tl = nfs_true;
2582 bp += NFSX_UNSIGNED;
2583 if (v3) {
2584 nfsm_clget;
2585 *tl = 0;
2586 bp += NFSX_UNSIGNED;
2587 }
2588 nfsm_clget;
2589 *tl = txdr_unsigned(dp->d_fileno);
2590 bp += NFSX_UNSIGNED;
2591 nfsm_clget;
2592 *tl = txdr_unsigned(nlen);
2593 bp += NFSX_UNSIGNED;
2594
2595 /* And loop around copying the name */
2596 xfer = nlen;
2597 cp = dp->d_name;
2598 while (xfer > 0) {
2599 nfsm_clget;
2600 if ((bp+xfer) > be)
2601 tsiz = be-bp;
2602 else
2603 tsiz = xfer;
2604 bcopy(cp, bp, tsiz);
2605 bp += tsiz;
2606 xfer -= tsiz;
2607 if (xfer > 0)
2608 cp += tsiz;
2609 }
2610 /* And null pad to a long boundary */
2611 for (i = 0; i < rem; i++)
2612 *bp++ = '\0';
2613 nfsm_clget;
2614
2615 /* Finish off the record */
2616 if (v3) {
2617 *tl = 0;
2618 bp += NFSX_UNSIGNED;
2619 nfsm_clget;
2620 }
2621 *tl = txdr_unsigned(*cookiep);
2622 bp += NFSX_UNSIGNED;
2623 }
2624 cpos += dp->d_reclen;
2625 dp = (struct dirent *)cpos;
2626 cookiep++;
2627 ncookies--;
2628 }
2629 vrele(vp);
2630 nfsm_clget;
2631 *tl = nfs_false;
2632 bp += NFSX_UNSIGNED;
2633 nfsm_clget;
2634 if (eofflag)
2635 *tl = nfs_true;
2636 else
2637 *tl = nfs_false;
2638 bp += NFSX_UNSIGNED;
2639 if (mp != mb) {
2640 if (bp < be)
2641 mp->m_len = bp - mtod(mp, caddr_t);
2642 } else
2643 mp->m_len += bp - bpos;
2644 FREE((caddr_t)rbuf, M_TEMP);
2645 FREE((caddr_t)cookies, M_TEMP);
2646 nfsm_srvdone;
2647 }
2648
2649 int
nfsrv_readdirplus(nfsd,slp,procp,mrq)2650 nfsrv_readdirplus(nfsd, slp, procp, mrq)
2651 struct nfsrv_descript *nfsd;
2652 struct nfssvc_sock *slp;
2653 struct proc *procp;
2654 struct mbuf **mrq;
2655 {
2656 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2657 struct mbuf *nam = nfsd->nd_nam;
2658 caddr_t dpos = nfsd->nd_dpos;
2659 struct ucred *cred = &nfsd->nd_cr;
2660 register char *bp, *be;
2661 register struct mbuf *mp;
2662 register struct dirent *dp;
2663 register caddr_t cp;
2664 register u_long *tl;
2665 register long t1;
2666 caddr_t bpos;
2667 struct mbuf *mb, *mb2, *mreq, *mp2;
2668 char *cpos, *cend, *cp2, *rbuf;
2669 struct vnode *vp, *nvp;
2670 struct flrep fl;
2671 nfsfh_t nfh;
2672 fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh;
2673 struct uio io;
2674 struct iovec iv;
2675 struct vattr va, at, *vap = &va;
2676 struct nfs_fattr *fp;
2677 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
2678 int siz, cnt, fullsiz, eofflag, rdonly, cache, dirlen, ncookies;
2679 u_quad_t frev, off, toff, verf;
2680 u_long *cookies = NULL, *cookiep;
2681
2682 fhp = &nfh.fh_generic;
2683 nfsm_srvmtofh(fhp);
2684 nfsm_dissect(tl, u_long *, 6 * NFSX_UNSIGNED);
2685 fxdr_hyper(tl, &toff);
2686 tl += 2;
2687 fxdr_hyper(tl, &verf);
2688 tl += 2;
2689 siz = fxdr_unsigned(int, *tl++);
2690 cnt = fxdr_unsigned(int, *tl);
2691 off = toff;
2692 siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
2693 xfer = NFS_SRVMAXDATA(nfsd);
2694 if (siz > xfer)
2695 siz = xfer;
2696 fullsiz = siz;
2697 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
2698 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
2699 nfsm_reply(NFSX_UNSIGNED);
2700 nfsm_srvpostop_attr(getret, &at);
2701 return (0);
2702 }
2703 error = getret = VOP_GETATTR(vp, &at, cred, procp);
2704 if (!error && toff && verf != at.va_filerev)
2705 error = NFSERR_BAD_COOKIE;
2706 if (!error) {
2707 nqsrv_getl(vp, ND_READ);
2708 error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
2709 }
2710 if (error) {
2711 vput(vp);
2712 nfsm_reply(NFSX_V3POSTOPATTR);
2713 nfsm_srvpostop_attr(getret, &at);
2714 return (0);
2715 }
2716 VOP_UNLOCK(vp, 0, procp);
2717 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
2718 again:
2719 iv.iov_base = rbuf;
2720 iv.iov_len = fullsiz;
2721 io.uio_iov = &iv;
2722 io.uio_iovcnt = 1;
2723 io.uio_offset = (off_t)off;
2724 io.uio_resid = fullsiz;
2725 io.uio_segflg = UIO_SYSSPACE;
2726 io.uio_rw = UIO_READ;
2727 io.uio_procp = (struct proc *)0;
2728 eofflag = 0;
2729 if (cookies) {
2730 free((caddr_t)cookies, M_TEMP);
2731 cookies = NULL;
2732 }
2733 error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
2734 off = (u_quad_t)io.uio_offset;
2735 getret = VOP_GETATTR(vp, &at, cred, procp);
2736 if (!cookies && !error)
2737 error = NFSERR_PERM;
2738 if (!error)
2739 error = getret;
2740 if (error) {
2741 vrele(vp);
2742 if (cookies)
2743 free((caddr_t)cookies, M_TEMP);
2744 free((caddr_t)rbuf, M_TEMP);
2745 nfsm_reply(NFSX_V3POSTOPATTR);
2746 nfsm_srvpostop_attr(getret, &at);
2747 return (0);
2748 }
2749 if (io.uio_resid) {
2750 siz -= io.uio_resid;
2751
2752 /*
2753 * If nothing read, return eof
2754 * rpc reply
2755 */
2756 if (siz == 0) {
2757 vrele(vp);
2758 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
2759 2 * NFSX_UNSIGNED);
2760 nfsm_srvpostop_attr(getret, &at);
2761 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
2762 txdr_hyper(&at.va_filerev, tl);
2763 tl += 2;
2764 *tl++ = nfs_false;
2765 *tl = nfs_true;
2766 FREE((caddr_t)cookies, M_TEMP);
2767 FREE((caddr_t)rbuf, M_TEMP);
2768 return (0);
2769 }
2770 }
2771
2772 /*
2773 * Check for degenerate cases of nothing useful read.
2774 * If so go try again
2775 */
2776 cpos = rbuf;
2777 cend = rbuf + siz;
2778 dp = (struct dirent *)cpos;
2779 cookiep = cookies;
2780 while (dp->d_fileno == 0 && cpos < cend && ncookies > 0) {
2781 cpos += dp->d_reclen;
2782 dp = (struct dirent *)cpos;
2783 cookiep++;
2784 ncookies--;
2785 }
2786 if (cpos >= cend || ncookies == 0) {
2787 toff = off;
2788 siz = fullsiz;
2789 goto again;
2790 }
2791
2792 dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
2793 nfsm_reply(cnt);
2794 nfsm_srvpostop_attr(getret, &at);
2795 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
2796 txdr_hyper(&at.va_filerev, tl);
2797 mp = mp2 = mb;
2798 bp = bpos;
2799 be = bp + M_TRAILINGSPACE(mp);
2800
2801 /* Loop through the records and build reply */
2802 while (cpos < cend && ncookies > 0) {
2803 if (dp->d_fileno != 0) {
2804 nlen = dp->d_namlen;
2805 rem = nfsm_rndup(nlen)-nlen;
2806
2807 /*
2808 * For readdir_and_lookup get the vnode using
2809 * the file number.
2810 */
2811 if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp))
2812 goto invalid;
2813 bzero((caddr_t)nfhp, NFSX_V3FH);
2814 nfhp->fh_fsid =
2815 nvp->v_mount->mnt_stat.f_fsid;
2816 if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) {
2817 vput(nvp);
2818 goto invalid;
2819 }
2820 if (VOP_GETATTR(nvp, vap, cred, procp)) {
2821 vput(nvp);
2822 goto invalid;
2823 }
2824 vput(nvp);
2825
2826 /*
2827 * If either the dircount or maxcount will be
2828 * exceeded, get out now. Both of these lengths
2829 * are calculated conservatively, including all
2830 * XDR overheads.
2831 */
2832 len += (7 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH +
2833 NFSX_V3POSTOPATTR);
2834 dirlen += (6 * NFSX_UNSIGNED + nlen + rem);
2835 if (len > cnt || dirlen > fullsiz) {
2836 eofflag = 0;
2837 break;
2838 }
2839
2840 /*
2841 * Build the directory record xdr from
2842 * the dirent entry.
2843 */
2844 fp = (struct nfs_fattr *)&fl.fl_fattr;
2845 nfsm_srvfillattr(vap, fp);
2846 fl.fl_fhsize = txdr_unsigned(NFSX_V3FH);
2847 fl.fl_fhok = nfs_true;
2848 fl.fl_postopok = nfs_true;
2849 fl.fl_off.nfsuquad[0] = 0;
2850 fl.fl_off.nfsuquad[1] = txdr_unsigned(*cookiep);
2851
2852 nfsm_clget;
2853 *tl = nfs_true;
2854 bp += NFSX_UNSIGNED;
2855 nfsm_clget;
2856 *tl = 0;
2857 bp += NFSX_UNSIGNED;
2858 nfsm_clget;
2859 *tl = txdr_unsigned(dp->d_fileno);
2860 bp += NFSX_UNSIGNED;
2861 nfsm_clget;
2862 *tl = txdr_unsigned(nlen);
2863 bp += NFSX_UNSIGNED;
2864
2865 /* And loop around copying the name */
2866 xfer = nlen;
2867 cp = dp->d_name;
2868 while (xfer > 0) {
2869 nfsm_clget;
2870 if ((bp + xfer) > be)
2871 tsiz = be - bp;
2872 else
2873 tsiz = xfer;
2874 bcopy(cp, bp, tsiz);
2875 bp += tsiz;
2876 xfer -= tsiz;
2877 if (xfer > 0)
2878 cp += tsiz;
2879 }
2880 /* And null pad to a long boundary */
2881 for (i = 0; i < rem; i++)
2882 *bp++ = '\0';
2883
2884 /*
2885 * Now copy the flrep structure out.
2886 */
2887 xfer = sizeof (struct flrep);
2888 cp = (caddr_t)&fl;
2889 while (xfer > 0) {
2890 nfsm_clget;
2891 if ((bp + xfer) > be)
2892 tsiz = be - bp;
2893 else
2894 tsiz = xfer;
2895 bcopy(cp, bp, tsiz);
2896 bp += tsiz;
2897 xfer -= tsiz;
2898 if (xfer > 0)
2899 cp += tsiz;
2900 }
2901 }
2902 invalid:
2903 cpos += dp->d_reclen;
2904 dp = (struct dirent *)cpos;
2905 cookiep++;
2906 ncookies--;
2907 }
2908 vrele(vp);
2909 nfsm_clget;
2910 *tl = nfs_false;
2911 bp += NFSX_UNSIGNED;
2912 nfsm_clget;
2913 if (eofflag)
2914 *tl = nfs_true;
2915 else
2916 *tl = nfs_false;
2917 bp += NFSX_UNSIGNED;
2918 if (mp != mb) {
2919 if (bp < be)
2920 mp->m_len = bp - mtod(mp, caddr_t);
2921 } else
2922 mp->m_len += bp - bpos;
2923 FREE((caddr_t)cookies, M_TEMP);
2924 FREE((caddr_t)rbuf, M_TEMP);
2925 nfsm_srvdone;
2926 }
2927
2928 /*
2929 * nfs commit service
2930 */
2931 int
nfsrv_commit(nfsd,slp,procp,mrq)2932 nfsrv_commit(nfsd, slp, procp, mrq)
2933 struct nfsrv_descript *nfsd;
2934 struct nfssvc_sock *slp;
2935 struct proc *procp;
2936 struct mbuf **mrq;
2937 {
2938 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2939 struct mbuf *nam = nfsd->nd_nam;
2940 caddr_t dpos = nfsd->nd_dpos;
2941 struct ucred *cred = &nfsd->nd_cr;
2942 struct vattr bfor, aft;
2943 struct vnode *vp;
2944 nfsfh_t nfh;
2945 fhandle_t *fhp;
2946 register u_long *tl;
2947 register long t1;
2948 caddr_t bpos;
2949 int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt, cache;
2950 char *cp2;
2951 struct mbuf *mb, *mb2, *mreq;
2952 u_quad_t frev, off;
2953
2954 #ifndef nolint
2955 cache = 0;
2956 #endif
2957 fhp = &nfh.fh_generic;
2958 nfsm_srvmtofh(fhp);
2959 nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2960
2961 /*
2962 * XXX At this time VOP_FSYNC() does not accept offset and byte
2963 * count parameters, so these arguments are useless (someday maybe).
2964 */
2965 fxdr_hyper(tl, &off);
2966 tl += 2;
2967 cnt = fxdr_unsigned(int, *tl);
2968 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
2969 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
2970 nfsm_reply(2 * NFSX_UNSIGNED);
2971 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
2972 return (0);
2973 }
2974 for_ret = VOP_GETATTR(vp, &bfor, cred, procp);
2975 error = VOP_FSYNC(vp, cred, MNT_WAIT, procp);
2976 aft_ret = VOP_GETATTR(vp, &aft, cred, procp);
2977 vput(vp);
2978 nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF);
2979 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
2980 if (!error) {
2981 nfsm_build(tl, u_long *, NFSX_V3WRITEVERF);
2982 *tl++ = txdr_unsigned(boottime.tv_sec);
2983 *tl = txdr_unsigned(boottime.tv_usec);
2984 } else
2985 return (0);
2986 nfsm_srvdone;
2987 }
2988
2989 /*
2990 * nfs statfs service
2991 */
2992 int
nfsrv_statfs(nfsd,slp,procp,mrq)2993 nfsrv_statfs(nfsd, slp, procp, mrq)
2994 struct nfsrv_descript *nfsd;
2995 struct nfssvc_sock *slp;
2996 struct proc *procp;
2997 struct mbuf **mrq;
2998 {
2999 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3000 struct mbuf *nam = nfsd->nd_nam;
3001 caddr_t dpos = nfsd->nd_dpos;
3002 struct ucred *cred = &nfsd->nd_cr;
3003 register struct statfs *sf;
3004 register struct nfs_statfs *sfp;
3005 register u_long *tl;
3006 register long t1;
3007 caddr_t bpos;
3008 int error = 0, rdonly, cache, getret = 1;
3009 int v3 = (nfsd->nd_flag & ND_NFSV3);
3010 char *cp2;
3011 struct mbuf *mb, *mb2, *mreq;
3012 struct vnode *vp;
3013 struct vattr at;
3014 nfsfh_t nfh;
3015 fhandle_t *fhp;
3016 struct statfs statfs;
3017 u_quad_t frev, tval;
3018
3019 #ifndef nolint
3020 cache = 0;
3021 #endif
3022 fhp = &nfh.fh_generic;
3023 nfsm_srvmtofh(fhp);
3024 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3025 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
3026 nfsm_reply(NFSX_UNSIGNED);
3027 nfsm_srvpostop_attr(getret, &at);
3028 return (0);
3029 }
3030 sf = &statfs;
3031 error = VFS_STATFS(vp->v_mount, sf, procp);
3032 getret = VOP_GETATTR(vp, &at, cred, procp);
3033 vput(vp);
3034 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
3035 if (v3)
3036 nfsm_srvpostop_attr(getret, &at);
3037 if (error)
3038 return (0);
3039 nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
3040 if (v3) {
3041 tval = (u_quad_t)sf->f_blocks;
3042 tval *= (u_quad_t)sf->f_bsize;
3043 txdr_hyper(&tval, &sfp->sf_tbytes);
3044 tval = (u_quad_t)sf->f_bfree;
3045 tval *= (u_quad_t)sf->f_bsize;
3046 txdr_hyper(&tval, &sfp->sf_fbytes);
3047 tval = (u_quad_t)sf->f_bavail;
3048 tval *= (u_quad_t)sf->f_bsize;
3049 txdr_hyper(&tval, &sfp->sf_abytes);
3050 sfp->sf_tfiles.nfsuquad[0] = 0;
3051 sfp->sf_tfiles.nfsuquad[1] = txdr_unsigned(sf->f_files);
3052 sfp->sf_ffiles.nfsuquad[0] = 0;
3053 sfp->sf_ffiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
3054 sfp->sf_afiles.nfsuquad[0] = 0;
3055 sfp->sf_afiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
3056 sfp->sf_invarsec = 0;
3057 } else {
3058 sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
3059 sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
3060 sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
3061 sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
3062 sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
3063 }
3064 nfsm_srvdone;
3065 }
3066
3067 /*
3068 * nfs fsinfo service
3069 */
3070 int
nfsrv_fsinfo(nfsd,slp,procp,mrq)3071 nfsrv_fsinfo(nfsd, slp, procp, mrq)
3072 struct nfsrv_descript *nfsd;
3073 struct nfssvc_sock *slp;
3074 struct proc *procp;
3075 struct mbuf **mrq;
3076 {
3077 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3078 struct mbuf *nam = nfsd->nd_nam;
3079 caddr_t dpos = nfsd->nd_dpos;
3080 struct ucred *cred = &nfsd->nd_cr;
3081 register u_long *tl;
3082 register struct nfsv3_fsinfo *sip;
3083 register long t1;
3084 caddr_t bpos;
3085 int error = 0, rdonly, cache, getret = 1, pref;
3086 char *cp2;
3087 struct mbuf *mb, *mb2, *mreq;
3088 struct vnode *vp;
3089 struct vattr at;
3090 nfsfh_t nfh;
3091 fhandle_t *fhp;
3092 u_quad_t frev;
3093
3094 #ifndef nolint
3095 cache = 0;
3096 #endif
3097 fhp = &nfh.fh_generic;
3098 nfsm_srvmtofh(fhp);
3099 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3100 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
3101 nfsm_reply(NFSX_UNSIGNED);
3102 nfsm_srvpostop_attr(getret, &at);
3103 return (0);
3104 }
3105 getret = VOP_GETATTR(vp, &at, cred, procp);
3106 vput(vp);
3107 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
3108 nfsm_srvpostop_attr(getret, &at);
3109 nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
3110
3111 /*
3112 * XXX
3113 * There should be file system VFS OP(s) to get this information.
3114 * For now, assume ufs.
3115 */
3116 if (slp->ns_so->so_type == SOCK_DGRAM)
3117 pref = NFS_MAXDGRAMDATA;
3118 else
3119 pref = NFS_MAXDATA;
3120 sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA);
3121 sip->fs_rtpref = txdr_unsigned(pref);
3122 sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
3123 sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA);
3124 sip->fs_wtpref = txdr_unsigned(pref);
3125 sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
3126 sip->fs_dtpref = txdr_unsigned(pref);
3127 sip->fs_maxfilesize.nfsuquad[0] = 0xffffffff;
3128 sip->fs_maxfilesize.nfsuquad[1] = 0xffffffff;
3129 sip->fs_timedelta.nfsv3_sec = 0;
3130 sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
3131 sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
3132 NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
3133 NFSV3FSINFO_CANSETTIME);
3134 nfsm_srvdone;
3135 }
3136
3137 /*
3138 * nfs pathconf service
3139 */
3140 int
nfsrv_pathconf(nfsd,slp,procp,mrq)3141 nfsrv_pathconf(nfsd, slp, procp, mrq)
3142 struct nfsrv_descript *nfsd;
3143 struct nfssvc_sock *slp;
3144 struct proc *procp;
3145 struct mbuf **mrq;
3146 {
3147 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3148 struct mbuf *nam = nfsd->nd_nam;
3149 caddr_t dpos = nfsd->nd_dpos;
3150 struct ucred *cred = &nfsd->nd_cr;
3151 register u_long *tl;
3152 register struct nfsv3_pathconf *pc;
3153 register long t1;
3154 caddr_t bpos;
3155 int error = 0, rdonly, cache, getret = 1, linkmax, namemax;
3156 int chownres, notrunc;
3157 char *cp2;
3158 struct mbuf *mb, *mb2, *mreq;
3159 struct vnode *vp;
3160 struct vattr at;
3161 nfsfh_t nfh;
3162 fhandle_t *fhp;
3163 u_quad_t frev;
3164
3165 #ifndef nolint
3166 cache = 0;
3167 #endif
3168 fhp = &nfh.fh_generic;
3169 nfsm_srvmtofh(fhp);
3170 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3171 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
3172 nfsm_reply(NFSX_UNSIGNED);
3173 nfsm_srvpostop_attr(getret, &at);
3174 return (0);
3175 }
3176 error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax);
3177 if (!error)
3178 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax);
3179 if (!error)
3180 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres);
3181 if (!error)
3182 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, ¬runc);
3183 getret = VOP_GETATTR(vp, &at, cred, procp);
3184 vput(vp);
3185 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF);
3186 nfsm_srvpostop_attr(getret, &at);
3187 if (error)
3188 return (0);
3189 nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
3190
3191 pc->pc_linkmax = txdr_unsigned(linkmax);
3192 pc->pc_namemax = txdr_unsigned(namemax);
3193 pc->pc_notrunc = txdr_unsigned(notrunc);
3194 pc->pc_chownrestricted = txdr_unsigned(chownres);
3195
3196 /*
3197 * These should probably be supported by VOP_PATHCONF(), but
3198 * until msdosfs is exportable (why would you want to?), the
3199 * Unix defaults should be ok.
3200 */
3201 pc->pc_caseinsensitive = nfs_false;
3202 pc->pc_casepreserving = nfs_true;
3203 nfsm_srvdone;
3204 }
3205
3206 /*
3207 * Null operation, used by clients to ping server
3208 */
3209 /* ARGSUSED */
3210 int
nfsrv_null(nfsd,slp,procp,mrq)3211 nfsrv_null(nfsd, slp, procp, mrq)
3212 struct nfsrv_descript *nfsd;
3213 struct nfssvc_sock *slp;
3214 struct proc *procp;
3215 struct mbuf **mrq;
3216 {
3217 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3218 struct mbuf *nam = nfsd->nd_nam;
3219 caddr_t dpos = nfsd->nd_dpos;
3220 struct ucred *cred = &nfsd->nd_cr;
3221 caddr_t bpos;
3222 int error = NFSERR_RETVOID, cache;
3223 struct mbuf *mb, *mreq;
3224 u_quad_t frev;
3225
3226 #ifndef nolint
3227 cache = 0;
3228 #endif
3229 nfsm_reply(0);
3230 return (0);
3231 }
3232
3233 /*
3234 * No operation, used for obsolete procedures
3235 */
3236 /* ARGSUSED */
3237 int
nfsrv_noop(nfsd,slp,procp,mrq)3238 nfsrv_noop(nfsd, slp, procp, mrq)
3239 struct nfsrv_descript *nfsd;
3240 struct nfssvc_sock *slp;
3241 struct proc *procp;
3242 struct mbuf **mrq;
3243 {
3244 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3245 struct mbuf *nam = nfsd->nd_nam;
3246 caddr_t dpos = nfsd->nd_dpos;
3247 struct ucred *cred = &nfsd->nd_cr;
3248 caddr_t bpos;
3249 int error, cache;
3250 struct mbuf *mb, *mreq;
3251 u_quad_t frev;
3252
3253 #ifndef nolint
3254 cache = 0;
3255 #endif
3256 if (nfsd->nd_repstat)
3257 error = nfsd->nd_repstat;
3258 else
3259 error = EPROCUNAVAIL;
3260 nfsm_reply(0);
3261 return (0);
3262 }
3263
3264 /*
3265 * Perform access checking for vnodes obtained from file handles that would
3266 * refer to files already opened by a Unix client. You cannot just use
3267 * vn_writechk() and VOP_ACCESS() for two reasons.
3268 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
3269 * 2 - The owner is to be given access irrespective of mode bits so that
3270 * processes that chmod after opening a file don't break. I don't like
3271 * this because it opens a security hole, but since the nfs server opens
3272 * a security hole the size of a barn door anyhow, what the heck.
3273 */
3274 int
nfsrv_access(vp,flags,cred,rdonly,p)3275 nfsrv_access(vp, flags, cred, rdonly, p)
3276 register struct vnode *vp;
3277 int flags;
3278 register struct ucred *cred;
3279 int rdonly;
3280 struct proc *p;
3281 {
3282 struct vattr vattr;
3283 int error;
3284 if (flags & VWRITE) {
3285 /* Just vn_writechk() changed to check rdonly */
3286 /*
3287 * Disallow write attempts on read-only file systems;
3288 * unless the file is a socket or a block or character
3289 * device resident on the file system.
3290 */
3291 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
3292 switch (vp->v_type) {
3293 case VREG: case VDIR: case VLNK:
3294 return (EROFS);
3295 }
3296 }
3297 /*
3298 * If there's shared text associated with
3299 * the inode, try to free it up once. If
3300 * we fail, we can't allow writing.
3301 */
3302 if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
3303 return (ETXTBSY);
3304 }
3305 if (error = VOP_GETATTR(vp, &vattr, cred, p))
3306 return (error);
3307 if ((error = VOP_ACCESS(vp, flags, cred, p)) &&
3308 cred->cr_uid != vattr.va_uid)
3309 return (error);
3310 return (0);
3311 }
3312