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