2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
25 * Copyright (c) 1989, 1993
26 * The Regents of the University of California. All rights reserved.
28 * This code is derived from software contributed to Berkeley by
29 * Rick Macklem at The University of Guelph.
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed by the University of
42 * California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * @(#)nfs_serv.c 8.7 (Berkeley) 5/14/95
60 * FreeBSD-Id: nfs_serv.c,v 1.52 1997/10/28 15:59:05 bde Exp $
64 * nfs version 2 and 3 server calls to vnode ops
65 * - these routines generally have 3 phases
66 * 1 - break down and validate rpc request in mbuf list
67 * 2 - do the vnode ops for the request
68 * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
69 * 3 - build the rpc reply in an mbuf list
71 * - do not mix the phases, since the nfsm_?? macros can return failures
72 * on a bad rpc or similar and do not do any vnode_rele()s or vnode_put()s
74 * - the nfsm_reply() macro generates an nfs rpc reply with the nfs
75 * error number iff error != 0 whereas
76 * returning an error from the server function implies a fatal error
77 * such as a badly constructed rpc request that should be dropped without
79 * For Version 3, nfsm_reply() does not return for the error case, since
80 * most version 3 rpcs return more than the status for error cases.
83 #include <sys/param.h>
84 #include <sys/systm.h>
86 #include <sys/kauth.h>
87 #include <sys/unistd.h>
88 #include <sys/malloc.h>
89 #include <sys/vnode.h>
90 #include <sys/mount_internal.h>
91 #include <sys/socket.h>
92 #include <sys/socketvar.h>
93 #include <sys/kpi_mbuf.h>
94 #include <sys/dirent.h>
96 #include <sys/kernel.h>
97 #include <sys/sysctl.h>
99 #include <sys/vnode_internal.h>
100 #include <sys/uio_internal.h>
101 #include <libkern/OSAtomic.h>
104 #include <sys/vmparam.h>
106 #include <nfs/nfsproto.h>
107 #include <nfs/rpcv2.h>
109 #include <nfs/xdr_subs.h>
110 #include <nfs/nfsm_subs.h>
112 nfstype nfsv3_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFSOCK
,
115 nfstype nfsv2_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFNON
,
118 extern u_long nfs_xdrneg1
;
119 extern u_long nfs_false
, nfs_true
;
120 extern enum vtype nv3tov_type
[8];
121 extern struct nfsstats nfsstats
;
123 int nfsrvw_procrastinate
= NFS_GATHERDELAY
* 1000;
124 int nfsrvw_procrastinate_v3
= 0;
128 /* XXX CSM 11/25/97 Upgrade sysctl.h someday */
129 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, async
, CTLFLAG_RW
, &nfs_async
, 0, "");
132 static int nfsrv_authorize(vnode_t
,vnode_t
,kauth_action_t
,vfs_context_t
,struct nfs_export_options
*,int);
133 static void nfsrvw_coalesce(struct nfsrv_descript
*, struct nfsrv_descript
*);
135 #define THREAD_SAFE_FS(VP) \
136 ((VP)->v_mount ? (VP)->v_mount->mnt_vtable->vfc_threadsafe : 0)
139 * nfs v3 access service
142 nfsrv3_access(nfsd
, slp
, procp
, mrq
)
143 struct nfsrv_descript
*nfsd
;
144 struct nfssvc_sock
*slp
;
148 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
149 mbuf_t nam
= nfsd
->nd_nam
;
150 caddr_t dpos
= nfsd
->nd_dpos
;
152 struct nfs_filehandle nfh
;
156 int error
= 0, getret
;
158 mbuf_t mb
, mreq
, mb2
;
159 struct vnode_attr vattr
, *vap
= &vattr
;
161 kauth_action_t testaction
;
162 struct vfs_context context
;
163 struct nfs_export
*nx
;
164 struct nfs_export_options
*nxo
;
167 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
168 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
169 nfsm_reply(NFSX_UNSIGNED
);
170 nfsm_srvpostop_attr(1, NULL
);
173 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
175 nfsm_reply(NFSX_UNSIGNED
);
176 nfsm_srvpostop_attr(1, NULL
);
179 nfsmode
= fxdr_unsigned(u_long
, *tl
);
181 context
.vc_proc
= procp
;
182 context
.vc_ucred
= nfsd
->nd_cr
;
185 * Each NFS mode bit is tested separately.
187 * XXX this code is nominally correct, but returns a pessimistic
188 * rather than optimistic result. It will be necessary to add
189 * an NFS-specific interface to the vnode_authorize code to
190 * obtain good performance in the optimistic mode.
192 if (nfsmode
& NFSV3ACCESS_READ
) {
193 if (vnode_isdir(vp
)) {
195 KAUTH_VNODE_LIST_DIRECTORY
|
196 KAUTH_VNODE_READ_EXTATTRIBUTES
;
199 KAUTH_VNODE_READ_DATA
|
200 KAUTH_VNODE_READ_EXTATTRIBUTES
;
202 if (nfsrv_authorize(vp
, NULL
, testaction
, &context
, nxo
, 0))
203 nfsmode
&= ~NFSV3ACCESS_READ
;
205 if ((nfsmode
& NFSV3ACCESS_LOOKUP
) &&
207 nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, &context
, nxo
, 0)))
208 nfsmode
&= ~NFSV3ACCESS_LOOKUP
;
209 if (nfsmode
& NFSV3ACCESS_MODIFY
) {
210 if (vnode_isdir(vp
)) {
212 KAUTH_VNODE_ADD_FILE
|
213 KAUTH_VNODE_ADD_SUBDIRECTORY
|
214 KAUTH_VNODE_DELETE_CHILD
;
217 KAUTH_VNODE_WRITE_DATA
|
218 KAUTH_VNODE_WRITE_ATTRIBUTES
|
219 KAUTH_VNODE_WRITE_EXTATTRIBUTES
|
220 KAUTH_VNODE_WRITE_SECURITY
;
222 if (nfsrv_authorize(vp
, NULL
, testaction
, &context
, nxo
, 0))
223 nfsmode
&= ~NFSV3ACCESS_MODIFY
;
225 if (nfsmode
& NFSV3ACCESS_EXTEND
) {
226 if (vnode_isdir(vp
)) {
228 KAUTH_VNODE_ADD_FILE
|
229 KAUTH_VNODE_ADD_SUBDIRECTORY
;
232 KAUTH_VNODE_WRITE_DATA
|
233 KAUTH_VNODE_APPEND_DATA
;
235 if (nfsrv_authorize(vp
, NULL
, testaction
, &context
, nxo
, 0))
236 nfsmode
&= ~NFSV3ACCESS_EXTEND
;
240 * Note concerning NFSV3ACCESS_DELETE:
241 * For hard links, the answer may be wrong if the vnode
242 * has multiple parents with different permissions.
243 * Also, some clients (e.g. MacOSX 10.3) may incorrectly
244 * interpret the missing/cleared DELETE bit.
245 * So we'll just leave the DELETE bit alone. At worst,
246 * we're telling the client it might be able to do
247 * something it really can't.
250 if ((nfsmode
& NFSV3ACCESS_EXECUTE
) &&
252 nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_EXECUTE
, &context
, nxo
, 0)))
253 nfsmode
&= ~NFSV3ACCESS_EXECUTE
;
255 nfsm_srv_vattr_init(vap
, 1);
256 getret
= vnode_getattr(vp
, vap
, &context
);
258 nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED
);
259 nfsm_srvpostop_attr(getret
, vap
);
260 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
261 *tl
= txdr_unsigned(nfsmode
);
267 * nfs getattr service
270 nfsrv_getattr(nfsd
, slp
, procp
, mrq
)
271 struct nfsrv_descript
*nfsd
;
272 struct nfssvc_sock
*slp
;
276 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
277 mbuf_t nam
= nfsd
->nd_nam
;
278 caddr_t dpos
= nfsd
->nd_dpos
;
279 struct nfs_fattr
*fp
;
280 struct vnode_attr va
;
281 struct vnode_attr
*vap
= &va
;
283 struct nfs_filehandle nfh
;
289 mbuf_t mb
, mb2
, mreq
;
290 struct vfs_context context
;
291 struct nfs_export
*nx
;
292 struct nfs_export_options
*nxo
;
293 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
296 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
300 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
305 context
.vc_proc
= procp
;
306 context
.vc_ucred
= nfsd
->nd_cr
;
308 nfsm_srv_vattr_init(vap
, v3
);
309 error
= vnode_getattr(vp
, vap
, &context
);
311 nfsm_reply(NFSX_FATTR(v3
));
314 nfsm_build(fp
, struct nfs_fattr
*, NFSX_FATTR(v3
));
315 nfsm_srvfillattr(vap
, fp
);
321 * nfs setattr service
324 nfsrv_setattr(nfsd
, slp
, procp
, mrq
)
325 struct nfsrv_descript
*nfsd
;
326 struct nfssvc_sock
*slp
;
330 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
331 mbuf_t nam
= nfsd
->nd_nam
;
332 caddr_t dpos
= nfsd
->nd_dpos
;
333 struct vnode_attr preat
;
334 struct vnode_attr postat
;
335 struct vnode_attr va
;
336 struct vnode_attr
*vap
= &va
;
337 struct nfsv2_sattr
*sp
;
338 struct nfs_fattr
*fp
;
340 struct nfs_filehandle nfh
;
341 struct nfs_export
*nx
;
342 struct nfs_export_options
*nxo
;
346 int error
= 0, preat_ret
= 1, postat_ret
= 1;
347 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), gcheck
= 0;
349 mbuf_t mb
, mb2
, mreq
;
350 struct timespec guard
;
351 struct vfs_context context
;
352 kauth_action_t action
;
359 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
360 gcheck
= fxdr_unsigned(int, *tl
);
362 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
363 fxdr_nfsv3time(tl
, &guard
);
366 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
368 * Nah nah nah nah na nah
369 * There is a bug in the Sun client that puts 0xffff in the mode
370 * field of sattr when it should put in 0xffffffff. The u_short
371 * doesn't sign extend.
372 * --> check the low order 2 bytes for 0xffff
374 if ((fxdr_unsigned(int, sp
->sa_mode
) & 0xffff) != 0xffff)
375 VATTR_SET(vap
, va_mode
, nfstov_mode(sp
->sa_mode
));
376 if (sp
->sa_uid
!= nfs_xdrneg1
)
377 VATTR_SET(vap
, va_uid
, fxdr_unsigned(uid_t
, sp
->sa_uid
));
378 if (sp
->sa_gid
!= nfs_xdrneg1
)
379 VATTR_SET(vap
, va_gid
, fxdr_unsigned(gid_t
, sp
->sa_gid
));
380 if (sp
->sa_size
!= nfs_xdrneg1
)
381 VATTR_SET(vap
, va_data_size
, fxdr_unsigned(u_quad_t
, sp
->sa_size
));
382 if (sp
->sa_atime
.nfsv2_sec
!= nfs_xdrneg1
) {
383 fxdr_nfsv2time(&sp
->sa_atime
, &vap
->va_access_time
);
384 VATTR_SET_ACTIVE(vap
, va_access_time
);
386 if (sp
->sa_mtime
.nfsv2_sec
!= nfs_xdrneg1
) {
387 fxdr_nfsv2time(&sp
->sa_mtime
, &vap
->va_modify_time
);
388 VATTR_SET_ACTIVE(vap
, va_modify_time
);
393 * Save the original credential UID in case they are
394 * mapped and we need to map the IDs in the attributes.
396 saved_uid
= kauth_cred_getuid(nfsd
->nd_cr
);
399 * Now that we have all the fields, lets do it.
401 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
402 nfsm_reply(2 * NFSX_UNSIGNED
);
403 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, &postat
);
406 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
408 nfsm_reply(2 * NFSX_UNSIGNED
);
409 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, &postat
);
413 context
.vc_proc
= procp
;
414 context
.vc_ucred
= nfsd
->nd_cr
;
417 nfsm_srv_pre_vattr_init(&preat
, v3
);
418 error
= preat_ret
= vnode_getattr(vp
, &preat
, &context
);
419 if (!error
&& gcheck
&& VATTR_IS_SUPPORTED(&preat
, va_change_time
) &&
420 (preat
.va_change_time
.tv_sec
!= guard
.tv_sec
||
421 preat
.va_change_time
.tv_nsec
!= guard
.tv_nsec
))
422 error
= NFSERR_NOT_SYNC
;
423 if (!preat_ret
&& !VATTR_ALL_SUPPORTED(&preat
))
427 nfsm_reply(NFSX_WCCDATA(v3
));
428 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, &postat
);
434 * If the credentials were mapped, we should
435 * map the same values in the attributes.
437 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nfsd
->nd_cr
) != saved_uid
)) {
439 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nfsd
->nd_cr
));
440 if (kauth_cred_ismember_gid(nfsd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
441 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nfsd
->nd_cr
));
445 * Authorize the attribute changes.
447 if (((error
= vnode_authattr(vp
, vap
, &action
, &context
))) ||
448 ((error
= nfsrv_authorize(vp
, NULL
, action
, &context
, nxo
, 0))))
450 error
= vnode_setattr(vp
, vap
, &context
);
452 nfsm_srv_vattr_init(&postat
, v3
);
453 postat_ret
= vnode_getattr(vp
, &postat
, &context
);
458 nfsm_reply(NFSX_WCCORFATTR(v3
));
460 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, &postat
);
463 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
464 nfsm_srvfillattr(&postat
, fp
);
474 nfsrv_lookup(nfsd
, slp
, procp
, mrq
)
475 struct nfsrv_descript
*nfsd
;
476 struct nfssvc_sock
*slp
;
480 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
481 mbuf_t nam
= nfsd
->nd_nam
;
482 caddr_t dpos
= nfsd
->nd_dpos
;
483 struct nfs_fattr
*fp
;
484 struct nameidata nd
, *ndp
= &nd
;
485 /* XXX Revisit when enabling WebNFS */
486 #ifdef WEBNFS_ENABLED
487 struct nameidata ind
;
489 vnode_t vp
, dirp
= NULL
;
490 struct nfs_filehandle dnfh
, nfh
;
491 struct nfs_export
*nx
;
492 struct nfs_export_options
*nxo
;
497 int error
= 0, len
, dirattr_ret
= 1, isdotdot
;
498 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), pubflag
;
500 mbuf_t mb
, mb2
, mreq
;
501 struct vnode_attr va
, dirattr
, *vap
= &va
;
502 struct vfs_context context
;
504 context
.vc_proc
= procp
;
505 context
.vc_ucred
= nfsd
->nd_cr
;
507 nfsm_srvmtofh(&dnfh
);
508 nfsm_srvnamesiz(len
, v3
);
510 pubflag
= nfs_ispublicfh(&dnfh
);
512 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
513 nd
.ni_cnd
.cn_flags
= LOCKLEAF
;
514 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, pubflag
, &len
, &nd
);
515 isdotdot
= ((len
== 2) && (nd
.ni_cnd
.cn_pnbuf
[0] == '.') && (nd
.ni_cnd
.cn_pnbuf
[1] == '.'));
517 error
= nfs_namei(nfsd
, &context
, &nd
, &dnfh
, nam
, pubflag
, &dirp
, &nx
, &nxo
);
519 /* XXX Revisit when enabling WebNFS */
520 #ifdef WEBNFS_ENABLED
521 if (!error
&& pubflag
) {
522 if (vnode_vtype(nd
.ni_vp
) == VDIR
&& nfs_pub
.np_index
!= NULL
) {
524 * Setup call to lookup() to see if we can find
525 * the index file. Arguably, this doesn't belong
529 ind
.ni_pathlen
= strlen(nfs_pub
.np_index
);
530 ind
.ni_cnd
.cn_nameptr
= ind
.ni_cnd
.cn_pnbuf
=
532 ind
.ni_startdir
= nd
.ni_vp
;
533 ind
.ni_usedvp
= nd
.ni_vp
;
535 if (!(error
= lookup(&ind
))) {
537 * Found an index file. Get rid of
538 * the old references.
543 vnode_put(nd
.ni_startdir
);
549 * If the public filehandle was used, check that this lookup
550 * didn't result in a filehandle outside the publicly exported
554 if (!error
&& vnode_mount(ndp
->ni_vp
) != nfs_pub
.np_mount
) {
564 nfsm_srv_vattr_init(&dirattr
, v3
);
565 dirattr_ret
= vnode_getattr(dirp
, &dirattr
, &context
);
571 nfsm_reply(NFSX_POSTOPATTR(v3
));
572 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
578 error
= nfsrv_vptofh(nx
, !v3
, (isdotdot
? &dnfh
: NULL
), vp
, &context
, &nfh
);
580 nfsm_srv_vattr_init(vap
, v3
);
581 error
= vnode_getattr(vp
, vap
, &context
);
584 nfsm_reply(NFSX_SRVFH(v3
, &nfh
) + NFSX_POSTOPORFATTR(v3
) + NFSX_POSTOPATTR(v3
));
586 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
589 nfsm_srvfhtom(&nfh
, v3
);
591 nfsm_srvpostop_attr(0, vap
);
592 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
594 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
595 nfsm_srvfillattr(vap
, fp
);
602 * nfs readlink service
605 nfsrv_readlink(nfsd
, slp
, procp
, mrq
)
606 struct nfsrv_descript
*nfsd
;
607 struct nfssvc_sock
*slp
;
611 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
612 mbuf_t nam
= nfsd
->nd_nam
;
613 caddr_t dpos
= nfsd
->nd_dpos
;
618 int error
= 0, i
, tlen
, len
, getret
= 1;
619 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
621 mbuf_t mb
, mb2
, mp2
, mp3
, mreq
;
623 struct vnode_attr attr
;
624 struct nfs_filehandle nfh
;
625 struct nfs_export
*nx
;
626 struct nfs_export_options
*nxo
;
628 char uio_buf
[ UIO_SIZEOF(4) ];
629 char *uio_bufp
= &uio_buf
[0];
630 int uio_buflen
= UIO_SIZEOF(4);
632 struct vfs_context context
;
640 while (len
< NFS_MAXPATHLEN
) {
642 if ((error
= mbuf_mclget(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mp
)))
644 mblen
= mbuf_maxlen(mp
);
645 mbuf_setlen(mp
, mblen
);
649 if ((error
= mbuf_setnext(mp2
, mp
))) {
655 if ((len
+ mblen
) > NFS_MAXPATHLEN
) {
656 mbuf_setlen(mp
, NFS_MAXPATHLEN
- len
);
657 len
= NFS_MAXPATHLEN
;
663 uio_buflen
= UIO_SIZEOF(i
);
664 MALLOC(uio_bufp
, char*, uio_buflen
, M_TEMP
, M_WAITOK
);
668 nfsm_reply(2 * NFSX_UNSIGNED
);
669 nfsm_srvpostop_attr(1, NULL
);
673 uiop
= uio_createwithbuffer(i
, 0, UIO_SYSSPACE
, UIO_READ
, uio_bufp
, uio_buflen
);
677 if (uio_bufp
!= &uio_buf
[0]) {
678 FREE(uio_bufp
, M_TEMP
);
679 uio_bufp
= &uio_buf
[0];
681 nfsm_reply(2 * NFSX_UNSIGNED
);
682 nfsm_srvpostop_attr(1, NULL
);
687 uio_addiov(uiop
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(mp
)), mbuf_len(mp
));
691 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
693 if (uio_bufp
!= &uio_buf
[0]) {
694 FREE(uio_bufp
, M_TEMP
);
695 uio_bufp
= &uio_buf
[0];
697 nfsm_reply(2 * NFSX_UNSIGNED
);
698 nfsm_srvpostop_attr(1, NULL
);
701 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
704 if (uio_bufp
!= &uio_buf
[0]) {
705 FREE(uio_bufp
, M_TEMP
);
706 uio_bufp
= &uio_buf
[0];
708 nfsm_reply(2 * NFSX_UNSIGNED
);
709 nfsm_srvpostop_attr(1, NULL
);
712 if (vnode_vtype(vp
) != VLNK
) {
720 context
.vc_proc
= procp
;
721 context
.vc_ucred
= nfsd
->nd_cr
;
723 if ((error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, &context
, nxo
, 0)))
725 error
= VNOP_READLINK(vp
, uiop
, &context
);
729 nfsm_srv_vattr_init(&attr
, v3
);
730 getret
= vnode_getattr(vp
, &attr
, &context
);
738 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_UNSIGNED
);
740 nfsm_srvpostop_attr(getret
, &attr
);
742 if (uio_bufp
!= &uio_buf
[0])
743 FREE(uio_bufp
, M_TEMP
);
748 if (uiop
&& (uio_resid(uiop
) > 0)) {
749 // LP64todo - fix this
750 len
-= uio_resid(uiop
);
751 tlen
= nfsm_rndup(len
);
752 nfsm_adj(mp3
, NFS_MAXPATHLEN
-tlen
, tlen
-len
);
754 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
755 *tl
= txdr_unsigned(len
);
756 mbuf_setnext(mb
, mp3
);
759 if (uio_bufp
!= &uio_buf
[0])
760 FREE(uio_bufp
, M_TEMP
);
768 nfsrv_read(nfsd
, slp
, procp
, mrq
)
769 struct nfsrv_descript
*nfsd
;
770 struct nfssvc_sock
*slp
;
774 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
775 mbuf_t nam
= nfsd
->nd_nam
;
776 caddr_t dpos
= nfsd
->nd_dpos
;
778 struct nfs_fattr
*fp
;
783 int error
= 0, count
, len
, left
, siz
, tlen
, getret
;
784 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), reqlen
;
786 mbuf_t mb
, mb2
, mreq
;
789 struct nfs_filehandle nfh
;
790 struct nfs_export
*nx
;
791 struct nfs_export_options
*nxo
;
793 char *uio_bufp
= NULL
;
794 struct vnode_attr va
, *vap
= &va
;
796 char uio_buf
[ UIO_SIZEOF(0) ];
797 struct vfs_context context
;
801 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
802 fxdr_hyper(tl
, &off
);
804 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
805 off
= (off_t
)fxdr_unsigned(u_long
, *tl
);
807 nfsm_srvstrsiz(reqlen
, NFS_SRVMAXDATA(nfsd
));
808 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
809 nfsm_reply(2 * NFSX_UNSIGNED
);
810 nfsm_srvpostop_attr(1, NULL
);
813 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
815 nfsm_reply(2 * NFSX_UNSIGNED
);
816 nfsm_srvpostop_attr(1, NULL
);
819 if (vnode_vtype(vp
) != VREG
) {
823 error
= (vnode_vtype(vp
) == VDIR
) ? EISDIR
: EACCES
;
826 context
.vc_proc
= procp
;
827 context
.vc_ucred
= nfsd
->nd_cr
;
830 if ((error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, &context
, nxo
, 1)))
831 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_EXECUTE
, &context
, nxo
, 1);
833 nfsm_srv_vattr_init(vap
, v3
);
834 getret
= vnode_getattr(vp
, vap
, &context
);
839 nfsm_reply(NFSX_POSTOPATTR(v3
));
840 nfsm_srvpostop_attr(getret
, vap
);
843 if ((u_quad_t
)off
>= vap
->va_data_size
)
845 else if (((u_quad_t
)off
+ reqlen
) > vap
->va_data_size
)
846 count
= nfsm_rndup(vap
->va_data_size
- off
);
849 nfsm_reply(NFSX_POSTOPORFATTR(v3
) + 3 * NFSX_UNSIGNED
+nfsm_rndup(count
));
851 nfsm_build(tl
, u_long
*, NFSX_V3FATTR
+ 4 * NFSX_UNSIGNED
);
853 fp
= (struct nfs_fattr
*)tl
;
854 tl
+= (NFSX_V3FATTR
/ sizeof (u_long
));
856 nfsm_build(tl
, u_long
*, NFSX_V2FATTR
+ NFSX_UNSIGNED
);
857 fp
= (struct nfs_fattr
*)tl
;
858 tl
+= (NFSX_V2FATTR
/ sizeof (u_long
));
863 * Generate the mbuf list with the uio_iov ref. to it.
868 siz
= min(mbuf_trailingspace(m
), left
);
875 if ((error
= mbuf_mclget(MBUF_WAITOK
, MBUF_TYPE_DATA
, &m
)))
881 MALLOC(uio_bufp
, char *, UIO_SIZEOF(i
), M_TEMP
, M_WAITOK
);
886 uiop
= uio_createwithbuffer(i
, off
, UIO_SYSSPACE
, UIO_READ
,
887 uio_bufp
, UIO_SIZEOF(i
));
897 panic("nfsrv_read iov");
898 siz
= min(mbuf_trailingspace(m
), left
);
901 uio_addiov(uiop
, CAST_USER_ADDR_T((char *)mbuf_data(m
) + tlen
), siz
);
902 mbuf_setlen(m
, tlen
+ siz
);
908 error
= VNOP_READ(vp
, uiop
, IO_NODELOCKED
, &context
);
909 off
= uio_offset(uiop
);
912 * This may seem a little weird that we drop the whole
913 * successful read if we get an error on the getattr.
914 * The reason is because we've already set up the reply
915 * to have postop attrs and omitting these optional bits
916 * would require shifting all the data in the reply.
918 * It would be more correct if we would simply drop the
919 * postop attrs if the getattr fails. We might be able to
920 * do that easier if we allocated separate mbufs for the data.
922 nfsm_srv_vattr_init(vap
, v3
);
923 if (error
|| (getret
= vnode_getattr(vp
, vap
, &context
))) {
928 nfsm_reply(NFSX_POSTOPATTR(v3
));
929 nfsm_srvpostop_attr(getret
, vap
);
930 if (uio_bufp
!= NULL
) {
931 FREE(uio_bufp
, M_TEMP
);
936 uiop
= uio_createwithbuffer(0, 0, UIO_SYSSPACE
, UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
943 nfsm_srvfillattr(vap
, fp
);
944 // LP64todo - fix this
945 len
-= uio_resid(uiop
);
946 tlen
= nfsm_rndup(len
);
947 if (count
!= tlen
|| tlen
!= len
)
948 nfsm_adj(mb
, count
- tlen
, tlen
- len
);
950 *tl
++ = txdr_unsigned(len
);
956 *tl
= txdr_unsigned(len
);
958 if (uio_bufp
!= NULL
) {
959 FREE(uio_bufp
, M_TEMP
);
968 nfsrv_write(nfsd
, slp
, procp
, mrq
)
969 struct nfsrv_descript
*nfsd
;
970 struct nfssvc_sock
*slp
;
974 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
975 mbuf_t nam
= nfsd
->nd_nam
;
976 caddr_t dpos
= nfsd
->nd_dpos
;
979 struct nfs_fattr
*fp
;
980 struct vnode_attr va
, forat
;
981 struct vnode_attr
*vap
= &va
;
985 int error
= 0, len
, forat_ret
= 1;
986 int ioflags
, aftat_ret
= 1, retlen
, zeroing
, adjust
, tlen
;
987 int stable
= NFSV3WRITE_FILESYNC
;
988 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
990 mbuf_t mb
, mb2
, mreq
;
992 struct nfs_filehandle nfh
;
993 struct nfs_export
*nx
;
994 struct nfs_export_options
*nxo
;
997 char *uio_bufp
= NULL
;
998 struct vfs_context context
;
1004 nfsm_srvmtofh(&nfh
);
1006 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
1007 fxdr_hyper(tl
, &off
);
1009 stable
= fxdr_unsigned(int, *tl
++);
1011 nfsm_dissect(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1012 off
= (off_t
)fxdr_unsigned(u_long
, *++tl
);
1015 stable
= NFSV3WRITE_UNSTABLE
;
1017 retlen
= len
= fxdr_unsigned(long, *tl
);
1021 * For NFS Version 2, it is not obvious what a write of zero length
1022 * should do, but I might as well be consistent with Version 3,
1023 * which is to return ok so long as there are no permission problems.
1031 tpos
= mbuf_data(mp
);
1032 tlen
= mbuf_len(mp
);
1033 adjust
= dpos
- tpos
;
1035 mbuf_setlen(mp
, tlen
);
1036 if (tlen
> 0 && adjust
> 0) {
1038 if ((error
= mbuf_setdata(mp
, tpos
, tlen
))) {
1039 nfsm_reply(2 * NFSX_UNSIGNED
);
1040 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1047 else if ((tlen
= mbuf_len(mp
)) > 0) {
1050 mbuf_setlen(mp
, tlen
- (i
- len
));
1053 if (mbuf_len(mp
) > 0)
1059 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
1061 nfsm_reply(2 * NFSX_UNSIGNED
);
1062 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1065 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
1066 nfsm_reply(2 * NFSX_UNSIGNED
);
1067 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1070 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
1072 nfsm_reply(2 * NFSX_UNSIGNED
);
1073 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1076 context
.vc_proc
= procp
;
1077 context
.vc_ucred
= nfsd
->nd_cr
;
1080 nfsm_srv_pre_vattr_init(&forat
, v3
);
1081 forat_ret
= vnode_getattr(vp
, &forat
, &context
);
1083 if (vnode_vtype(vp
) != VREG
) {
1087 error
= (vnode_vtype(vp
) == VDIR
) ? EISDIR
: EACCES
;
1090 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_DATA
, &context
, nxo
, 1);
1094 nfsm_reply(NFSX_WCCDATA(v3
));
1095 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1100 MALLOC(uio_bufp
, char *, UIO_SIZEOF(count
), M_TEMP
, M_WAITOK
);
1104 nfsm_reply(NFSX_WCCDATA(v3
));
1105 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1108 uiop
= uio_createwithbuffer(count
, off
, UIO_SYSSPACE
, UIO_WRITE
, uio_bufp
, UIO_SIZEOF(count
));
1112 nfsm_reply(NFSX_WCCDATA(v3
));
1113 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1114 if (uio_bufp
!= NULL
) {
1115 FREE(uio_bufp
, M_TEMP
);
1121 if ((tlen
= mbuf_len(mp
)) > 0)
1122 uio_addiov(uiop
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(mp
)), tlen
);
1128 * The IO_METASYNC flag indicates that all metadata (and not just
1129 * enough to ensure data integrity) mus be written to stable storage
1131 * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
1133 if (stable
== NFSV3WRITE_UNSTABLE
)
1134 ioflags
= IO_NODELOCKED
;
1135 else if (stable
== NFSV3WRITE_DATASYNC
)
1136 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1138 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1140 error
= VNOP_WRITE(vp
, uiop
, ioflags
, &context
);
1141 OSAddAtomic(1, (SInt32
*)(SInt32
*)&nfsstats
.srvvop_writes
);
1143 nfsm_srv_vattr_init(vap
, v3
);
1144 aftat_ret
= vnode_getattr(vp
, vap
, &context
);
1148 nfsm_reply(NFSX_PREOPATTR(v3
) + NFSX_POSTOPORFATTR(v3
) +
1149 2 * NFSX_UNSIGNED
+ NFSX_WRITEVERF(v3
));
1151 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1153 if (uio_bufp
!= NULL
) {
1154 FREE(uio_bufp
, M_TEMP
);
1158 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1159 *tl
++ = txdr_unsigned(retlen
);
1161 * If nfs_async is set, then pretend the write was FILESYNC.
1163 if (stable
== NFSV3WRITE_UNSTABLE
&& !nfs_async
)
1164 *tl
++ = txdr_unsigned(stable
);
1166 *tl
++ = txdr_unsigned(NFSV3WRITE_FILESYNC
);
1168 * Actually, there is no need to txdr these fields,
1169 * but it may make the values more human readable,
1170 * for debugging purposes.
1172 *tl
++ = txdr_unsigned(boottime_sec());
1173 *tl
= txdr_unsigned(0);
1175 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1176 nfsm_srvfillattr(vap
, fp
);
1179 if (uio_bufp
!= NULL
) {
1180 FREE(uio_bufp
, M_TEMP
);
1186 * NFS write service with write gathering support. Called when
1187 * nfsrvw_procrastinate > 0.
1188 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
1189 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
1193 nfsrv_writegather(ndp
, slp
, procp
, mrq
)
1194 struct nfsrv_descript
**ndp
;
1195 struct nfssvc_sock
*slp
;
1200 struct nfsrv_descript
*wp
, *nfsd
, *owp
, *swp
;
1201 struct nfs_export
*nx
;
1202 struct nfs_export_options
*nxo
;
1203 struct nfs_fattr
*fp
;
1205 struct nfsrvw_delayhash
*wpp
;
1207 struct vnode_attr va
, forat
;
1210 caddr_t bpos
, dpos
, tpos
;
1211 int error
= 0, len
, forat_ret
= 1;
1212 int ioflags
, aftat_ret
= 1, adjust
, v3
, zeroing
, tlen
;
1214 mbuf_t mb
, mb2
, mreq
, mrep
, md
;
1217 char *uio_bufp
= NULL
;
1220 struct vfs_context context
;
1222 context
.vc_proc
= procp
;
1233 mrep
= nfsd
->nd_mrep
;
1235 dpos
= nfsd
->nd_dpos
;
1237 context
.vc_ucred
= cred
;
1238 v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1239 LIST_INIT(&nfsd
->nd_coalesce
);
1240 nfsd
->nd_mreq
= NULL
;
1241 nfsd
->nd_stable
= NFSV3WRITE_FILESYNC
;
1243 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 + (u_quad_t
)now
.tv_usec
;
1244 nfsd
->nd_time
= cur_usec
+
1245 (v3
? nfsrvw_procrastinate_v3
: nfsrvw_procrastinate
);
1248 * Now, get the write header..
1250 nfsm_srvmtofh(&nfsd
->nd_fh
);
1251 /* XXX shouldn't we be checking for invalid FHs before doing any more work? */
1253 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
1254 fxdr_hyper(tl
, &nfsd
->nd_off
);
1256 nfsd
->nd_stable
= fxdr_unsigned(int, *tl
++);
1258 nfsm_dissect(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1259 nfsd
->nd_off
= (off_t
)fxdr_unsigned(u_long
, *++tl
);
1262 nfsd
->nd_stable
= NFSV3WRITE_UNSTABLE
;
1264 len
= fxdr_unsigned(long, *tl
);
1266 nfsd
->nd_eoff
= nfsd
->nd_off
+ len
;
1269 * Trim the header out of the mbuf list and trim off any trailing
1270 * junk so that the mbuf list has only the write data.
1278 tpos
= mbuf_data(mp
);
1279 tlen
= mbuf_len(mp
);
1280 adjust
= dpos
- tpos
;
1282 mbuf_setlen(mp
, tlen
);
1283 if (tlen
> 0 && adjust
> 0) {
1285 if ((error
= mbuf_setdata(mp
, tpos
, tlen
)))
1292 tlen
= mbuf_len(mp
);
1295 mbuf_setlen(mp
, tlen
- (i
- len
));
1301 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
1306 nfsm_writereply(2 * NFSX_UNSIGNED
, v3
);
1308 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1309 nfsd
->nd_mreq
= mreq
;
1310 nfsd
->nd_mrep
= NULL
;
1315 * Add this entry to the hash and time queues.
1317 lck_mtx_lock(&slp
->ns_wgmutex
);
1319 wp
= slp
->ns_tq
.lh_first
;
1320 while (wp
&& wp
->nd_time
< nfsd
->nd_time
) {
1322 wp
= wp
->nd_tq
.le_next
;
1325 LIST_INSERT_AFTER(owp
, nfsd
, nd_tq
);
1327 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1329 if (nfsd
->nd_mrep
) {
1330 wpp
= NWDELAYHASH(slp
, nfsd
->nd_fh
.nfh_fid
);
1333 while (wp
&& !nfsrv_fhmatch(&nfsd
->nd_fh
, &wp
->nd_fh
)) {
1335 wp
= wp
->nd_hash
.le_next
;
1337 while (wp
&& (wp
->nd_off
< nfsd
->nd_off
) &&
1338 nfsrv_fhmatch(&nfsd
->nd_fh
, &wp
->nd_fh
)) {
1340 wp
= wp
->nd_hash
.le_next
;
1343 LIST_INSERT_AFTER(owp
, nfsd
, nd_hash
);
1346 * Search the hash list for overlapping entries and
1349 for(; nfsd
&& NFSW_CONTIG(owp
, nfsd
); nfsd
= wp
) {
1350 wp
= nfsd
->nd_hash
.le_next
;
1351 if (NFSW_SAMECRED(owp
, nfsd
))
1352 nfsrvw_coalesce(owp
, nfsd
);
1355 LIST_INSERT_HEAD(wpp
, nfsd
, nd_hash
);
1359 lck_mtx_lock(&slp
->ns_wgmutex
);
1363 * Now, do VNOP_WRITE()s for any one(s) that need to be done now
1364 * and generate the associated reply mbuf list(s).
1368 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 + (u_quad_t
)now
.tv_usec
;
1369 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= owp
) {
1370 owp
= nfsd
->nd_tq
.le_next
;
1371 if (nfsd
->nd_time
> cur_usec
)
1375 LIST_REMOVE(nfsd
, nd_tq
);
1376 LIST_REMOVE(nfsd
, nd_hash
);
1377 mrep
= nfsd
->nd_mrep
;
1378 nfsd
->nd_mrep
= NULL
;
1379 v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1380 forat_ret
= aftat_ret
= 1;
1381 error
= nfsrv_fhtovp(&nfsd
->nd_fh
, nfsd
->nd_nam
, TRUE
, &vp
, &nx
, &nxo
);
1383 error
= nfsrv_credcheck(nfsd
, nx
, nxo
);
1388 context
.vc_ucred
= cred
;
1391 nfsm_srv_pre_vattr_init(&forat
, v3
);
1392 forat_ret
= vnode_getattr(vp
, &forat
, &context
);
1394 if (vnode_vtype(vp
) != VREG
) {
1398 error
= (vnode_vtype(vp
) == VDIR
) ? EISDIR
: EACCES
;
1403 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_DATA
, &context
, nxo
, 1);
1406 if (nfsd
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1407 ioflags
= IO_NODELOCKED
;
1408 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
)
1409 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1411 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1413 if (!error
&& ((nfsd
->nd_eoff
- nfsd
->nd_off
) > 0)) {
1417 if (mbuf_len(mp
) > 0)
1422 MALLOC(uio_bufp
, char *, UIO_SIZEOF(i
), M_TEMP
, M_WAITOK
);
1424 uiop
= uio_createwithbuffer(i
, nfsd
->nd_off
, UIO_SYSSPACE
,
1425 UIO_WRITE
, uio_bufp
, UIO_SIZEOF(i
));
1426 if (!uio_bufp
|| !uiop
)
1431 if ((tlen
= mbuf_len(mp
)) > 0)
1432 uio_addiov(uiop
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(mp
)), tlen
);
1435 error
= VNOP_WRITE(vp
, uiop
, ioflags
, &context
);
1436 OSAddAtomic(1, (SInt32
*)&nfsstats
.srvvop_writes
);
1439 FREE(uio_bufp
, M_TEMP
);
1446 nfsm_srv_pre_vattr_init(&va
, v3
);
1447 aftat_ret
= vnode_getattr(vp
, &va
, &context
);
1452 * Loop around generating replies for all write rpcs that have
1453 * now been completed.
1458 nfsm_writereply(NFSX_WCCDATA(v3
), v3
);
1460 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1463 nfsm_writereply(NFSX_PREOPATTR(v3
) +
1464 NFSX_POSTOPORFATTR(v3
) + 2 * NFSX_UNSIGNED
+
1465 NFSX_WRITEVERF(v3
), v3
);
1467 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1468 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1469 *tl
++ = txdr_unsigned(nfsd
->nd_len
);
1470 *tl
++ = txdr_unsigned(swp
->nd_stable
);
1472 * Actually, there is no need to txdr these fields,
1473 * but it may make the values more human readable,
1474 * for debugging purposes.
1476 *tl
++ = txdr_unsigned(boottime_sec());
1477 *tl
= txdr_unsigned(0);
1479 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1480 nfsm_srvfillattr(&va
, fp
);
1483 nfsd
->nd_mreq
= mreq
;
1485 panic("nfsrv_write: nd_mrep not free");
1488 * Done. Put it at the head of the timer queue so that
1489 * the final phase can return the reply.
1493 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1495 nfsd
= swp
->nd_coalesce
.lh_first
;
1497 LIST_REMOVE(nfsd
, nd_tq
);
1501 LIST_INSERT_HEAD(&slp
->ns_tq
, swp
, nd_tq
);
1506 * Search for a reply to return.
1508 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= nfsd
->nd_tq
.le_next
)
1509 if (nfsd
->nd_mreq
) {
1510 LIST_REMOVE(nfsd
, nd_tq
);
1511 *mrq
= nfsd
->nd_mreq
;
1515 slp
->ns_wgtime
= slp
->ns_tq
.lh_first
? slp
->ns_tq
.lh_first
->nd_time
: 0;
1516 lck_mtx_unlock(&slp
->ns_wgmutex
);
1521 * Coalesce the write request nfsd into owp. To do this we must:
1522 * - remove nfsd from the queues
1523 * - merge nfsd->nd_mrep into owp->nd_mrep
1524 * - update the nd_eoff and nd_stable for owp
1525 * - put nfsd on owp's nd_coalesce list
1529 struct nfsrv_descript
*owp
,
1530 struct nfsrv_descript
*nfsd
)
1534 struct nfsrv_descript
*p
;
1536 LIST_REMOVE(nfsd
, nd_hash
);
1537 LIST_REMOVE(nfsd
, nd_tq
);
1538 if (owp
->nd_eoff
< nfsd
->nd_eoff
) {
1539 overlap
= owp
->nd_eoff
- nfsd
->nd_off
;
1541 panic("nfsrv_coalesce: bad off");
1543 mbuf_adj(nfsd
->nd_mrep
, overlap
);
1545 while ((mpnext
= mbuf_next(mp
)))
1547 error
= mbuf_setnext(mp
, nfsd
->nd_mrep
);
1549 panic("nfsrvw_coalesce: mbuf_setnext failed: %d", error
);
1550 owp
->nd_eoff
= nfsd
->nd_eoff
;
1552 mbuf_freem(nfsd
->nd_mrep
);
1554 nfsd
->nd_mrep
= NULL
;
1555 if (nfsd
->nd_stable
== NFSV3WRITE_FILESYNC
)
1556 owp
->nd_stable
= NFSV3WRITE_FILESYNC
;
1557 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
&&
1558 owp
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1559 owp
->nd_stable
= NFSV3WRITE_DATASYNC
;
1560 LIST_INSERT_HEAD(&owp
->nd_coalesce
, nfsd
, nd_tq
);
1563 * If nfsd had anything else coalesced into it, transfer them
1564 * to owp, otherwise their replies will never get sent.
1566 for (p
= nfsd
->nd_coalesce
.lh_first
; p
;
1567 p
= nfsd
->nd_coalesce
.lh_first
) {
1568 LIST_REMOVE(p
, nd_tq
);
1569 LIST_INSERT_HEAD(&owp
->nd_coalesce
, p
, nd_tq
);
1574 * Sort the group list in increasing numerical order.
1575 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1576 * that used to be here.)
1581 nfsrvw_sort(list
, num
)
1588 /* Insertion sort. */
1589 for (i
= 1; i
< num
; i
++) {
1591 /* find correct slot for value v, moving others up */
1592 for (j
= i
; --j
>= 0 && v
< list
[j
];)
1593 list
[j
+ 1] = list
[j
];
1599 * copy credentials making sure that the result can be compared with bcmp().
1604 nfsrv_setcred(kauth_cred_t incred
, kauth_cred_t outcred
)
1608 bzero((caddr_t
)outcred
, sizeof (*outcred
));
1609 outcred
->cr_ref
= 1;
1610 outcred
->cr_uid
= kauth_cred_getuid(incred
);
1611 outcred
->cr_ngroups
= incred
->cr_ngroups
;
1612 for (i
= 0; i
< incred
->cr_ngroups
; i
++)
1613 outcred
->cr_groups
[i
] = incred
->cr_groups
[i
];
1614 nfsrvw_sort(outcred
->cr_groups
, outcred
->cr_ngroups
);
1618 * nfs create service
1619 * now does a truncate to 0 length via. setattr if it already exists
1622 nfsrv_create(nfsd
, slp
, procp
, mrq
)
1623 struct nfsrv_descript
*nfsd
;
1624 struct nfssvc_sock
*slp
;
1628 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
1629 mbuf_t nam
= nfsd
->nd_nam
;
1630 caddr_t dpos
= nfsd
->nd_dpos
;
1631 struct nfs_fattr
*fp
;
1632 struct vnode_attr dirfor
, diraft
, postat
;
1633 struct vnode_attr va
;
1634 struct vnode_attr
*vap
= &va
;
1635 struct nfsv2_sattr
*sp
;
1637 struct nameidata nd
;
1641 int error
= 0, rdev
, len
, tsize
, dirfor_ret
= 1, diraft_ret
= 1;
1642 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), how
, exclusive_flag
= 0;
1644 mbuf_t mb
, mb2
, mreq
;
1645 vnode_t vp
, dvp
, dirp
= NULL
;
1646 struct nfs_filehandle nfh
;
1647 struct nfs_export
*nx
;
1648 struct nfs_export_options
*nxo
;
1650 u_char cverf
[NFSX_V3CREATEVERF
];
1651 struct vfs_context context
;
1654 context
.vc_proc
= procp
;
1655 context
.vc_ucred
= nfsd
->nd_cr
;
1658 * Save the original credential UID in case they are
1659 * mapped and we need to map the IDs in the attributes.
1661 saved_uid
= kauth_cred_getuid(nfsd
->nd_cr
);
1666 nd
.ni_cnd
.cn_nameiop
= 0;
1668 nfsm_srvmtofh(&nfh
);
1669 nfsm_srvnamesiz(len
, v3
);
1671 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1672 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
1673 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
1675 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
1678 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
1679 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
1686 nd
.ni_cnd
.cn_nameiop
= 0;
1687 nfsm_reply(NFSX_WCCDATA(v3
));
1688 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1699 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
1700 how
= fxdr_unsigned(int, *tl
);
1702 case NFSV3CREATE_GUARDED
:
1707 case NFSV3CREATE_UNCHECKED
:
1710 case NFSV3CREATE_EXCLUSIVE
:
1711 nfsm_dissect(cp
, caddr_t
, NFSX_V3CREATEVERF
);
1712 bcopy(cp
, cverf
, NFSX_V3CREATEVERF
);
1715 VATTR_SET(vap
, va_mode
, 0);
1718 VATTR_SET(vap
, va_type
, VREG
);
1722 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
1723 v_type
= IFTOVT(fxdr_unsigned(u_long
, sp
->sa_mode
));
1726 VATTR_SET(vap
, va_type
, v_type
);
1727 VATTR_SET(vap
, va_mode
, nfstov_mode(sp
->sa_mode
));
1731 tsize
= fxdr_unsigned(long, sp
->sa_size
);
1733 VATTR_SET(vap
, va_data_size
, (u_quad_t
)tsize
);
1738 rdev
= fxdr_unsigned(long, sp
->sa_size
);
1746 * If it doesn't exist, create it
1747 * otherwise just truncate to 0 length
1748 * should I set the mode too ??
1751 kauth_acl_t xacl
= NULL
;
1754 * If the credentials were mapped, we should
1755 * map the same values in the attributes.
1757 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nfsd
->nd_cr
) != saved_uid
)) {
1759 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nfsd
->nd_cr
));
1760 if (kauth_cred_ismember_gid(nfsd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
1761 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nfsd
->nd_cr
));
1764 /* authorize before creating */
1765 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
, nxo
, 0);
1767 /* construct ACL and handle inheritance */
1769 error
= kauth_acl_inherit(dvp
,
1775 if (!error
&& xacl
!= NULL
)
1776 VATTR_SET(vap
, va_acl
, xacl
);
1778 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
1779 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
1781 /* validate new-file security information */
1783 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
1784 if (error
&& (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
))) {
1786 * Most NFS servers just ignore the UID/GID attributes, so we
1787 * try ignoring them if that'll help the request succeed.
1789 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
1790 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
1791 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
1795 if (vap
->va_type
== VREG
|| vap
->va_type
== VSOCK
) {
1798 error
= VNOP_CREATE(dvp
, &vp
, &nd
.ni_cnd
, vap
, &context
);
1800 if (!error
&& !VATTR_ALL_SUPPORTED(vap
))
1802 * If some of the requested attributes weren't handled by the VNOP,
1803 * use our fallback code.
1805 error
= vnode_setattr_fallback(vp
, vap
, &context
);
1808 kauth_acl_free(xacl
);
1811 if (exclusive_flag
) {
1814 bcopy(cverf
, (caddr_t
)&vap
->va_access_time
,
1816 VATTR_SET_ACTIVE(vap
, va_access_time
);
1817 // skip authorization, as this is an
1818 // NFS internal implementation detail.
1819 error
= vnode_setattr(vp
, vap
, &context
);
1823 } else if (vap
->va_type
== VCHR
|| vap
->va_type
== VBLK
||
1824 vap
->va_type
== VFIFO
) {
1825 if (vap
->va_type
== VCHR
&& rdev
== (int)0xffffffff)
1826 VATTR_SET(vap
, va_type
, VFIFO
);
1827 if (vap
->va_type
!= VFIFO
&&
1828 (error
= suser(nfsd
->nd_cr
, (u_short
*)0))) {
1831 VATTR_SET(vap
, va_rdev
, (dev_t
)rdev
);
1833 error
= VNOP_MKNOD(dvp
, &vp
, &nd
.ni_cnd
, vap
, &context
);
1836 kauth_acl_free(xacl
);
1846 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
1847 nd
.ni_cnd
.cn_flags
&= ~LOCKPARENT
;
1848 nd
.ni_cnd
.cn_context
= &context
;
1849 nd
.ni_startdir
= dvp
;
1851 error
= lookup(&nd
);
1853 if (nd
.ni_cnd
.cn_flags
& ISSYMLINK
)
1862 * nameidone has to happen before we vnode_put(dvp)
1863 * since it may need to release the fs_nodelock on the dvp
1866 nd
.ni_cnd
.cn_nameiop
= 0;
1871 * nameidone has to happen before we vnode_put(dvp)
1872 * since it may need to release the fs_nodelock on the dvp
1875 nd
.ni_cnd
.cn_nameiop
= 0;
1879 if (!error
&& VATTR_IS_ACTIVE(vap
, va_data_size
)) {
1880 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_DATA
,
1883 tempsize
= vap
->va_data_size
;
1885 VATTR_SET(vap
, va_data_size
, tempsize
);
1886 error
= vnode_setattr(vp
, vap
, &context
);
1891 error
= nfsrv_vptofh(nx
, !v3
, NULL
, vp
, &context
, &nfh
);
1893 nfsm_srv_vattr_init(&postat
, v3
);
1894 error
= vnode_getattr(vp
, &postat
, &context
);
1901 if (exclusive_flag
&& !error
&&
1902 bcmp(cverf
, (caddr_t
)&postat
.va_access_time
, NFSX_V3CREATEVERF
))
1904 nfsm_srv_vattr_init(&diraft
, v3
);
1905 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
1909 nfsm_reply(NFSX_SRVFH(v3
, &nfh
) + NFSX_FATTR(v3
) + NFSX_WCCDATA(v3
));
1913 nfsm_srvpostop_fh(&nfh
);
1914 nfsm_srvpostop_attr(0, &postat
);
1916 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1918 nfsm_srvfhtom(&nfh
, v3
);
1919 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1920 nfsm_srvfillattr(&postat
, fp
);
1924 if (nd
.ni_cnd
.cn_nameiop
) {
1926 * nameidone has to happen before we vnode_put(dvp)
1927 * since it may need to release the fs_nodelock on the dvp
1941 * nfs v3 mknod service
1944 nfsrv_mknod(nfsd
, slp
, procp
, mrq
)
1945 struct nfsrv_descript
*nfsd
;
1946 struct nfssvc_sock
*slp
;
1950 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
1951 mbuf_t nam
= nfsd
->nd_nam
;
1952 caddr_t dpos
= nfsd
->nd_dpos
;
1953 struct vnode_attr dirfor
, diraft
, postat
;
1954 struct vnode_attr va
;
1955 struct vnode_attr
*vap
= &va
;
1957 struct nameidata nd
;
1960 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
1961 u_long major
, minor
;
1964 mbuf_t mb
, mb2
, mreq
;
1965 vnode_t vp
, dvp
, dirp
= NULL
;
1966 struct nfs_filehandle nfh
;
1967 struct nfs_export
*nx
;
1968 struct nfs_export_options
*nxo
;
1969 struct vfs_context hacked_context
; /* XXX should we have this? */
1970 struct vfs_context context
;
1972 kauth_acl_t xacl
= NULL
;
1974 context
.vc_proc
= procp
;
1975 context
.vc_ucred
= nfsd
->nd_cr
;
1976 hacked_context
.vc_proc
= procp
;
1977 hacked_context
.vc_ucred
= proc_ucred(procp
);
1980 * Save the original credential UID in case they are
1981 * mapped and we need to map the IDs in the attributes.
1983 saved_uid
= kauth_cred_getuid(nfsd
->nd_cr
);
1986 nd
.ni_cnd
.cn_nameiop
= 0;
1987 nfsm_srvmtofh(&nfh
);
1988 nfsm_srvnamesiz(len
, 1);
1990 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1991 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
1992 error
= nfsm_path_mbuftond(&md
, &dpos
, 1, FALSE
, &len
, &nd
);
1994 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
1996 nfsm_srv_pre_vattr_init(&dirfor
, 1);
1997 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
2000 nd
.ni_cnd
.cn_nameiop
= 0;
2001 nfsm_reply(NFSX_WCCDATA(1));
2002 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2010 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
2011 vtyp
= nfsv3tov_type(*tl
);
2012 if (vtyp
!= VCHR
&& vtyp
!= VBLK
&& vtyp
!= VSOCK
&& vtyp
!= VFIFO
) {
2013 error
= NFSERR_BADTYPE
;
2019 if (vtyp
== VCHR
|| vtyp
== VBLK
) {
2020 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2021 major
= fxdr_unsigned(u_long
, *tl
++);
2022 minor
= fxdr_unsigned(u_long
, *tl
);
2023 VATTR_SET(vap
, va_rdev
, makedev(major
, minor
));
2027 * If it doesn't exist, create it.
2033 VATTR_SET(vap
, va_type
, vtyp
);
2036 * If the credentials were mapped, we should
2037 * map the same values in the attributes.
2039 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nfsd
->nd_cr
) != saved_uid
)) {
2041 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nfsd
->nd_cr
));
2042 if (kauth_cred_ismember_gid(nfsd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
2043 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nfsd
->nd_cr
));
2046 /* authorize before creating */
2047 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
, nxo
, 0);
2049 /* construct ACL and handle inheritance */
2051 error
= kauth_acl_inherit(dvp
,
2057 if (!error
&& xacl
!= NULL
)
2058 VATTR_SET(vap
, va_acl
, xacl
);
2060 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
2061 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
2063 /* validate new-file security information */
2065 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
2066 if (error
&& (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
))) {
2068 * Most NFS servers just ignore the UID/GID attributes, so we
2069 * try ignoring them if that'll help the request succeed.
2071 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
2072 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
2073 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
2077 if (vtyp
== VSOCK
) {
2078 error
= VNOP_CREATE(dvp
, &vp
, &nd
.ni_cnd
, vap
, &context
);
2080 if (!error
&& !VATTR_ALL_SUPPORTED(vap
))
2082 * If some of the requested attributes weren't handled by the VNOP,
2083 * use our fallback code.
2085 error
= vnode_setattr_fallback(vp
, vap
, &context
);
2087 if (vtyp
!= VFIFO
&& (error
= suser(nfsd
->nd_cr
, (u_short
*)0))) {
2090 if ((error
= VNOP_MKNOD(dvp
, &vp
, &nd
.ni_cnd
, vap
, &context
))) {
2098 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
2099 nd
.ni_cnd
.cn_flags
&= ~LOCKPARENT
;
2100 nd
.ni_cnd
.cn_context
= &hacked_context
;
2101 nd
.ni_startdir
= dvp
;
2103 error
= lookup(&nd
);
2106 if (nd
.ni_cnd
.cn_flags
& ISSYMLINK
)
2112 kauth_acl_free(xacl
);
2115 * nameidone has to happen before we vnode_put(dvp)
2116 * since it may need to release the fs_nodelock on the dvp
2119 nd
.ni_cnd
.cn_nameiop
= 0;
2124 error
= nfsrv_vptofh(nx
, 0, NULL
, vp
, &context
, &nfh
);
2126 nfsm_srv_vattr_init(&postat
, 1);
2127 error
= vnode_getattr(vp
, &postat
, &context
);
2133 nfsm_srv_vattr_init(&diraft
, 1);
2134 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
2138 nfsm_reply(NFSX_SRVFH(1, &nfh
) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
2140 nfsm_srvpostop_fh(&nfh
);
2141 nfsm_srvpostop_attr(0, &postat
);
2143 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2146 if (nd
.ni_cnd
.cn_nameiop
) {
2148 * nameidone has to happen before we vnode_put(dvp)
2149 * since it may need to release the fs_nodelock on the dvp
2163 * nfs remove service
2166 nfsrv_remove(nfsd
, slp
, procp
, mrq
)
2167 struct nfsrv_descript
*nfsd
;
2168 struct nfssvc_sock
*slp
;
2172 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
2173 mbuf_t nam
= nfsd
->nd_nam
;
2174 caddr_t dpos
= nfsd
->nd_dpos
;
2175 struct nameidata nd
;
2179 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
2180 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2183 vnode_t vp
, dvp
, dirp
= NULL
;
2184 struct vnode_attr dirfor
, diraft
;
2185 struct nfs_filehandle nfh
;
2186 struct nfs_export
*nx
;
2187 struct nfs_export_options
*nxo
;
2188 struct vfs_context context
;
2190 context
.vc_proc
= procp
;
2191 context
.vc_ucred
= nfsd
->nd_cr
;
2194 nfsm_srvmtofh(&nfh
);
2195 nfsm_srvnamesiz(len
, v3
);
2197 nd
.ni_cnd
.cn_nameiop
= DELETE
;
2198 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
2199 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
2201 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
2204 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
2205 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
2215 if (vnode_vtype(vp
) == VDIR
)
2216 error
= EPERM
; /* POSIX */
2217 else if (vnode_isvroot(vp
))
2219 * The root of a mounted filesystem cannot be deleted.
2223 error
= nfsrv_authorize(vp
, dvp
, KAUTH_VNODE_DELETE
, &context
, nxo
, 0);
2226 error
= VNOP_REMOVE(dvp
, vp
, &nd
.ni_cnd
, 0, &context
);
2229 * nameidone has to happen before we vnode_put(dvp)
2230 * since it may need to release the fs_nodelock on the dvp
2238 nfsm_srv_vattr_init(&diraft
, v3
);
2239 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
2242 nfsm_reply(NFSX_WCCDATA(v3
));
2244 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2252 * nfs rename service
2255 nfsrv_rename(nfsd
, slp
, procp
, mrq
)
2256 struct nfsrv_descript
*nfsd
;
2257 struct nfssvc_sock
*slp
;
2261 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
2262 mbuf_t nam
= nfsd
->nd_nam
;
2263 caddr_t dpos
= nfsd
->nd_dpos
;
2264 kauth_cred_t saved_cred
= NULL
;
2268 int error
= 0, fromlen
, tolen
;
2269 int fdirfor_ret
= 1, fdiraft_ret
= 1;
2270 int tdirfor_ret
= 1, tdiraft_ret
= 1;
2271 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2272 char *cp2
, *frompath
= NULL
, *topath
= NULL
;
2274 struct nameidata fromnd
, tond
;
2275 vnode_t fvp
, tvp
, tdvp
, fdvp
, fdirp
= NULL
;
2276 vnode_t tdirp
= NULL
;
2277 struct vnode_attr fdirfor
, fdiraft
, tdirfor
, tdiraft
;
2278 struct nfs_filehandle fnfh
, tnfh
;
2279 struct nfs_export
*fnx
, *tnx
;
2280 struct nfs_export_options
*fnxo
, *tnxo
;
2281 enum vtype fvtype
, tvtype
;
2282 int holding_mntlock
;
2284 struct vfs_context context
;
2286 context
.vc_proc
= procp
;
2287 context
.vc_ucred
= nfsd
->nd_cr
;
2294 * these need to be set before
2295 * calling any nfsm_xxxx macros
2296 * since they may take us out
2297 * through the error path
2299 holding_mntlock
= 0;
2304 nfsm_srvmtofh(&fnfh
);
2305 nfsm_srvnamesiz(fromlen
, v3
);
2306 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &fromlen
, &fromnd
);
2311 frompath
= fromnd
.ni_cnd
.cn_pnbuf
;
2312 nfsm_srvmtofh(&tnfh
);
2313 nfsm_strsiz(tolen
, NFS_MAXNAMLEN
, v3
);
2314 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &tolen
, &tond
);
2317 FREE_ZONE(frompath
, MAXPATHLEN
, M_NAMEI
);
2320 topath
= tond
.ni_cnd
.cn_pnbuf
;
2323 * Remember our original uid so that we can reset cr_uid before
2324 * the second nfs_namei() call, in case it is remapped.
2326 saved_cred
= nfsd
->nd_cr
;
2327 kauth_cred_ref(saved_cred
);
2329 fromnd
.ni_cnd
.cn_nameiop
= DELETE
;
2330 fromnd
.ni_cnd
.cn_flags
= WANTPARENT
;
2332 fromnd
.ni_cnd
.cn_pnbuf
= frompath
;
2334 fromnd
.ni_cnd
.cn_pnlen
= MAXPATHLEN
;
2335 fromnd
.ni_cnd
.cn_flags
|= HASBUF
;
2337 error
= nfs_namei(nfsd
, &context
, &fromnd
, &fnfh
, nam
, FALSE
, &fdirp
, &fnx
, &fnxo
);
2340 fdvp
= fromnd
.ni_dvp
;
2345 nfsm_srv_pre_vattr_init(&fdirfor
, v3
);
2346 fdirfor_ret
= vnode_getattr(fdirp
, &fdirfor
, &context
);
2352 fvtype
= vnode_vtype(fvp
);
2354 /* reset credential if it was remapped */
2355 if (nfsd
->nd_cr
!= saved_cred
) {
2356 kauth_cred_rele(nfsd
->nd_cr
);
2357 nfsd
->nd_cr
= saved_cred
;
2358 kauth_cred_ref(nfsd
->nd_cr
);
2361 tond
.ni_cnd
.cn_nameiop
= RENAME
;
2362 tond
.ni_cnd
.cn_flags
= WANTPARENT
;
2364 tond
.ni_cnd
.cn_pnbuf
= topath
;
2366 tond
.ni_cnd
.cn_pnlen
= MAXPATHLEN
;
2367 tond
.ni_cnd
.cn_flags
|= HASBUF
;
2370 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
2372 error
= nfs_namei(nfsd
, &context
, &tond
, &tnfh
, nam
, FALSE
, &tdirp
, &tnx
, &tnxo
);
2375 * Translate error code for rename("dir1", "dir2/.").
2377 if (error
== EISDIR
&& fvtype
== VDIR
) {
2390 nfsm_srv_pre_vattr_init(&tdirfor
, v3
);
2391 tdirfor_ret
= vnode_getattr(tdirp
, &tdirfor
, &context
);
2399 tvtype
= vnode_vtype(tvp
);
2401 if (fvtype
== VDIR
&& tvtype
!= VDIR
) {
2407 } else if (fvtype
!= VDIR
&& tvtype
== VDIR
) {
2414 if (tvtype
== VDIR
&& vnode_mountedhere(tvp
)) {
2433 * If tvp is a directory and not the same as fdvp, or tdvp is not the same as fdvp,
2434 * the node is moving between directories and we need rights to remove from the
2435 * old and add to the new.
2437 * If tvp already exists and is not a directory, we need to be allowed to delete it.
2439 * Note that we do not inherit when renaming. XXX this needs to be revisited to
2440 * implement the deferred-inherit bit.
2446 if ((tvp
!= NULL
) && vnode_isdir(tvp
)) {
2449 } else if (tdvp
!= fdvp
) {
2453 /* moving out of fdvp, must have delete rights */
2454 if ((error
= nfsrv_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
, &context
, fnxo
, 0)) != 0)
2456 /* moving into tdvp or tvp, must have rights to add */
2457 if ((error
= nfsrv_authorize(((tvp
!= NULL
) && vnode_isdir(tvp
)) ? tvp
: tdvp
,
2459 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
2460 &context
, tnxo
, 0)) != 0)
2463 /* node staying in same directory, must be allowed to add new name */
2464 if ((error
= nfsrv_authorize(fdvp
, NULL
,
2465 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
2466 &context
, fnxo
, 0)) != 0)
2469 /* overwriting tvp */
2470 if ((tvp
!= NULL
) && !vnode_isdir(tvp
) &&
2471 ((error
= nfsrv_authorize(tvp
, tdvp
, KAUTH_VNODE_DELETE
, &context
, tnxo
, 0)) != 0))
2474 /* XXX more checks? */
2477 /* authorization denied */
2482 if ((vnode_mount(fvp
) != vnode_mount(tdvp
)) ||
2483 (tvp
&& (vnode_mount(fvp
) != vnode_mount(tvp
)))) {
2491 * The following edge case is caught here:
2492 * (to cannot be a descendent of from)
2505 if (tdvp
->v_parent
== fvp
) {
2512 if (fvtype
== VDIR
&& vnode_mountedhere(fvp
)) {
2520 * If source is the same as the destination (that is the
2521 * same vnode) then there is nothing to do...
2522 * EXCEPT if the underlying file system supports case
2523 * insensitivity and is case preserving. In this case
2524 * the file system needs to handle the special case of
2525 * getting the same vnode as target (fvp) and source (tvp).
2527 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
2528 * and _PC_CASE_PRESERVING can have this exception, and they need to
2529 * handle the special case of getting the same vnode as target and
2530 * source. NOTE: Then the target is unlocked going into vnop_rename,
2531 * so not to cause locking problems. There is a single reference on tvp.
2533 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
2534 * that correct behaviour then is just to remove the source (link)
2536 if ((fvp
== tvp
) && (fdvp
== tdvp
)) {
2537 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
2538 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
2539 fromnd
.ni_cnd
.cn_namelen
)) {
2544 if (holding_mntlock
&& vnode_mount(fvp
) != locked_mp
) {
2546 * we're holding a reference and lock
2547 * on locked_mp, but it no longer matches
2548 * what we want to do... so drop our hold
2550 mount_unlock_renames(locked_mp
);
2551 mount_drop(locked_mp
, 0);
2552 holding_mntlock
= 0;
2554 if (tdvp
!= fdvp
&& fvtype
== VDIR
) {
2556 * serialize renames that re-shape
2557 * the tree... if holding_mntlock is
2558 * set, then we're ready to go...
2560 * first need to drop the iocounts
2561 * we picked up, second take the
2562 * lock to serialize the access,
2563 * then finally start the lookup
2564 * process over with the lock held
2566 if (!holding_mntlock
) {
2568 * need to grab a reference on
2569 * the mount point before we
2570 * drop all the iocounts... once
2571 * the iocounts are gone, the mount
2574 locked_mp
= vnode_mount(fvp
);
2575 mount_ref(locked_mp
, 0);
2577 /* make a copy of to path to pass to nfs_namei() again */
2578 MALLOC_ZONE(topath
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2580 bcopy(tond
.ni_cnd
.cn_pnbuf
, topath
, tolen
+ 1);
2583 * nameidone has to happen before we vnode_put(tdvp)
2584 * since it may need to release the fs_nodelock on the tdvp
2592 /* make a copy of from path to pass to nfs_namei() again */
2593 MALLOC_ZONE(frompath
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2595 bcopy(fromnd
.ni_cnd
.cn_pnbuf
, frompath
, fromlen
+ 1);
2598 * nameidone has to happen before we vnode_put(fdvp)
2599 * since it may need to release the fs_nodelock on the fdvp
2614 mount_lock_renames(locked_mp
);
2615 holding_mntlock
= 1;
2620 fdirfor_ret
= tdirfor_ret
= 1;
2622 if (!topath
|| !frompath
) {
2623 /* we couldn't allocate a path, so bail */
2632 * when we dropped the iocounts to take
2633 * the lock, we allowed the identity of
2634 * the various vnodes to change... if they did,
2635 * we may no longer be dealing with a rename
2636 * that reshapes the tree... once we're holding
2637 * the iocounts, the vnodes can't change type
2638 * so we're free to drop the lock at this point
2641 if (holding_mntlock
) {
2642 mount_unlock_renames(locked_mp
);
2643 mount_drop(locked_mp
, 0);
2644 holding_mntlock
= 0;
2648 // save these off so we can later verify that fvp is the same
2651 oname
= fvp
->v_name
;
2652 oparent
= fvp
->v_parent
;
2654 error
= VNOP_RENAME(fromnd
.ni_dvp
, fromnd
.ni_vp
, &fromnd
.ni_cnd
,
2655 tond
.ni_dvp
, tond
.ni_vp
, &tond
.ni_cnd
, &context
);
2657 * fix up name & parent pointers. note that we first
2658 * check that fvp has the same name/parent pointers it
2659 * had before the rename call... this is a 'weak' check
2662 if (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
) {
2664 update_flags
= VNODE_UPDATE_NAME
;
2666 update_flags
|= VNODE_UPDATE_PARENT
;
2667 vnode_update_identity(fvp
, tdvp
, tond
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_namelen
, tond
.ni_cnd
.cn_hash
, update_flags
);
2670 if (holding_mntlock
) {
2671 mount_unlock_renames(locked_mp
);
2672 mount_drop(locked_mp
, 0);
2673 holding_mntlock
= 0;
2677 * nameidone has to happen before we vnode_put(tdvp)
2678 * since it may need to release the fs_nodelock on the tdvp
2689 * nameidone has to happen before we vnode_put(fdvp)
2690 * since it may need to release the fs_nodelock on the fdvp
2701 nfsm_srv_vattr_init(&fdiraft
, v3
);
2702 fdiraft_ret
= vnode_getattr(fdirp
, &fdiraft
, &context
);
2707 nfsm_srv_vattr_init(&tdiraft
, v3
);
2708 tdiraft_ret
= vnode_getattr(tdirp
, &tdiraft
, &context
);
2712 nfsm_reply(2 * NFSX_WCCDATA(v3
));
2714 nfsm_srvwcc_data(fdirfor_ret
, &fdirfor
, fdiraft_ret
, &fdiraft
);
2715 nfsm_srvwcc_data(tdirfor_ret
, &tdirfor
, tdiraft_ret
, &tdiraft
);
2718 FREE_ZONE(frompath
, MAXPATHLEN
, M_NAMEI
);
2720 FREE_ZONE(topath
, MAXPATHLEN
, M_NAMEI
);
2722 kauth_cred_rele(saved_cred
);
2726 if (holding_mntlock
) {
2727 mount_unlock_renames(locked_mp
);
2728 mount_drop(locked_mp
, 0);
2732 * nameidone has to happen before we vnode_put(tdvp)
2733 * since it may need to release the fs_nodelock on the tdvp
2743 * nameidone has to happen before we vnode_put(fdvp)
2744 * since it may need to release the fs_nodelock on the fdvp
2757 FREE_ZONE(frompath
, MAXPATHLEN
, M_NAMEI
);
2759 FREE_ZONE(topath
, MAXPATHLEN
, M_NAMEI
);
2761 kauth_cred_rele(saved_cred
);
2769 nfsrv_link(nfsd
, slp
, procp
, mrq
)
2770 struct nfsrv_descript
*nfsd
;
2771 struct nfssvc_sock
*slp
;
2775 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
2776 mbuf_t nam
= nfsd
->nd_nam
;
2777 caddr_t dpos
= nfsd
->nd_dpos
;
2778 struct nameidata nd
;
2782 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
2783 int getret
= 1, v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2786 vnode_t vp
, xp
, dvp
, dirp
= NULL
;
2787 struct vnode_attr dirfor
, diraft
, at
;
2788 struct nfs_filehandle nfh
, dnfh
;
2789 struct nfs_export
*nx
;
2790 struct nfs_export_options
*nxo
;
2791 struct vfs_context context
;
2793 vp
= xp
= dvp
= NULL
;
2794 nfsm_srvmtofh(&nfh
);
2795 nfsm_srvmtofh(&dnfh
);
2796 nfsm_srvnamesiz(len
, v3
);
2797 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
2798 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2799 nfsm_srvpostop_attr(getret
, &at
);
2800 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2803 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
2805 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2806 nfsm_srvpostop_attr(getret
, &at
);
2807 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2811 /* we're not allowed to link to directories... */
2812 if (vnode_vtype(vp
) == VDIR
) {
2813 error
= EPERM
; /* POSIX */
2817 context
.vc_proc
= procp
;
2818 context
.vc_ucred
= nfsd
->nd_cr
;
2820 /* ...or to anything that kauth doesn't want us to (eg. immutable items) */
2821 if ((error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_LINKTARGET
, &context
, nxo
, 0)) != 0)
2824 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2825 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
2826 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
2828 error
= nfs_namei(nfsd
, &context
, &nd
, &dnfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
2831 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
2832 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
2845 else if (vnode_mount(vp
) != vnode_mount(dvp
))
2848 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
, nxo
, 0);
2851 error
= VNOP_LINK(vp
, dvp
, &nd
.ni_cnd
, &context
);
2854 * nameidone has to happen before we vnode_put(dvp)
2855 * since it may need to release the fs_nodelock on the dvp
2864 nfsm_srv_vattr_init(&at
, v3
);
2865 getret
= vnode_getattr(vp
, &at
, &context
);
2868 nfsm_srv_vattr_init(&diraft
, v3
);
2869 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
2874 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2876 nfsm_srvpostop_attr(getret
, &at
);
2877 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2885 * nfs symbolic link service
2888 nfsrv_symlink(nfsd
, slp
, procp
, mrq
)
2889 struct nfsrv_descript
*nfsd
;
2890 struct nfssvc_sock
*slp
;
2894 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
2895 mbuf_t nam
= nfsd
->nd_nam
;
2896 caddr_t dpos
= nfsd
->nd_dpos
;
2897 struct vnode_attr dirfor
, diraft
, postat
;
2898 struct nameidata nd
;
2899 struct vnode_attr va
;
2900 struct vnode_attr
*vap
= &va
;
2903 struct nfsv2_sattr
*sp
;
2904 char *bpos
, *linkdata
= NULL
, *cp2
;
2905 int error
= 0, len
, linkdatalen
;
2906 int dirfor_ret
= 1, diraft_ret
= 1;
2907 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2908 mbuf_t mb
, mreq
, mb2
;
2909 vnode_t vp
, dvp
, dirp
= NULL
;
2910 struct nfs_filehandle nfh
;
2911 struct nfs_export
*nx
;
2912 struct nfs_export_options
*nxo
;
2914 char uio_buf
[ UIO_SIZEOF(1) ];
2915 struct vfs_context context
;
2918 context
.vc_proc
= procp
;
2919 context
.vc_ucred
= nfsd
->nd_cr
;
2922 * Save the original credential UID in case they are
2923 * mapped and we need to map the IDs in the attributes.
2925 saved_uid
= kauth_cred_getuid(nfsd
->nd_cr
);
2927 nd
.ni_cnd
.cn_nameiop
= 0;
2929 nfsm_srvmtofh(&nfh
);
2930 nfsm_srvnamesiz(len
, v3
);
2932 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2933 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
2934 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
2936 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
2939 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
2940 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
2947 nd
.ni_cnd
.cn_nameiop
= 0;
2956 nfsm_strsiz(linkdatalen
, NFS_MAXPATHLEN
, v3
);
2957 MALLOC(linkdata
, caddr_t
, linkdatalen
+ 1, M_TEMP
, M_WAITOK
);
2960 nd
.ni_cnd
.cn_nameiop
= 0;
2961 vnode_put(nd
.ni_dvp
);
2962 vnode_put(nd
.ni_vp
);
2966 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
2967 &uio_buf
[0], sizeof(uio_buf
));
2970 nd
.ni_cnd
.cn_nameiop
= 0;
2971 vnode_put(nd
.ni_dvp
);
2972 vnode_put(nd
.ni_vp
);
2976 uio_addiov(auio
, CAST_USER_ADDR_T(linkdata
), linkdatalen
);
2977 nfsm_mtouio(auio
, linkdatalen
);
2979 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
2980 VATTR_SET(vap
, va_mode
, fxdr_unsigned(u_short
, sp
->sa_mode
));
2982 *(linkdata
+ linkdatalen
) = '\0';
2989 * If the credentials were mapped, we should
2990 * map the same values in the attributes.
2992 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nfsd
->nd_cr
) != saved_uid
)) {
2994 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nfsd
->nd_cr
));
2995 if (kauth_cred_ismember_gid(nfsd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
2996 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nfsd
->nd_cr
));
2998 VATTR_SET(vap
, va_type
, VLNK
);
2999 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
3000 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
3002 /* authorize before creating */
3003 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
, nxo
, 0);
3005 /* validate given attributes */
3007 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
3008 if (error
&& (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
))) {
3010 * Most NFS servers just ignore the UID/GID attributes, so we
3011 * try ignoring them if that'll help the request succeed.
3013 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
3014 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
3015 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
3019 error
= VNOP_SYMLINK(dvp
, &vp
, &nd
.ni_cnd
, vap
, linkdata
, &context
);
3023 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
3024 nd
.ni_cnd
.cn_flags
&= ~(LOCKPARENT
| FOLLOW
);
3025 nd
.ni_cnd
.cn_flags
|= (NOFOLLOW
| LOCKLEAF
);
3026 nd
.ni_cnd
.cn_context
= &context
;
3027 nd
.ni_startdir
= dvp
;
3029 error
= lookup(&nd
);
3034 error
= nfsrv_vptofh(nx
, !v3
, NULL
, vp
, &context
, &nfh
);
3036 nfsm_srv_vattr_init(&postat
, v3
);
3037 error
= vnode_getattr(vp
, &postat
, &context
);
3043 * nameidone has to happen before we vnode_put(dvp)
3044 * since it may need to release the fs_nodelock on the dvp
3047 nd
.ni_cnd
.cn_nameiop
= 0;
3054 FREE(linkdata
, M_TEMP
);
3056 nfsm_srv_vattr_init(&diraft
, v3
);
3057 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
3060 nfsm_reply(NFSX_SRVFH(v3
, &nfh
) + NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
3063 nfsm_srvpostop_fh(&nfh
);
3064 nfsm_srvpostop_attr(0, &postat
);
3066 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
3070 if (nd
.ni_cnd
.cn_nameiop
) {
3072 * nameidone has to happen before we vnode_put(dvp)
3073 * since it may need to release the fs_nodelock on the dvp
3084 FREE(linkdata
, M_TEMP
);
3092 nfsrv_mkdir(nfsd
, slp
, procp
, mrq
)
3093 struct nfsrv_descript
*nfsd
;
3094 struct nfssvc_sock
*slp
;
3098 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
3099 mbuf_t nam
= nfsd
->nd_nam
;
3100 caddr_t dpos
= nfsd
->nd_dpos
;
3101 struct vnode_attr dirfor
, diraft
, postat
;
3102 struct vnode_attr va
;
3103 struct vnode_attr
*vap
= &va
;
3104 struct nfs_fattr
*fp
;
3105 struct nameidata nd
;
3111 int dirfor_ret
= 1, diraft_ret
= 1;
3112 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
3114 mbuf_t mb
, mb2
, mreq
;
3115 vnode_t vp
, dvp
, dirp
= NULL
;
3116 struct nfs_filehandle nfh
;
3117 struct nfs_export
*nx
;
3118 struct nfs_export_options
*nxo
;
3119 struct vfs_context context
;
3121 kauth_acl_t xacl
= NULL
;
3123 context
.vc_proc
= procp
;
3124 context
.vc_ucred
= nfsd
->nd_cr
;
3127 * Save the original credential UID in case they are
3128 * mapped and we need to map the IDs in the attributes.
3130 saved_uid
= kauth_cred_getuid(nfsd
->nd_cr
);
3132 nd
.ni_cnd
.cn_nameiop
= 0;
3134 nfsm_srvmtofh(&nfh
);
3135 nfsm_srvnamesiz(len
, v3
);
3137 nd
.ni_cnd
.cn_nameiop
= CREATE
;
3138 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
3139 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
3141 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
3144 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
3145 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
3152 nd
.ni_cnd
.cn_nameiop
= 0;
3153 nfsm_reply(NFSX_WCCDATA(v3
));
3154 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
3166 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
3167 VATTR_SET(vap
, va_mode
, nfstov_mode(*tl
++));
3169 VATTR_SET(vap
, va_type
, VDIR
);
3173 * nameidone has to happen before we vnode_put(dvp)
3174 * since it may need to release the fs_nodelock on the dvp
3185 * If the credentials were mapped, we should
3186 * map the same values in the attributes.
3188 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nfsd
->nd_cr
) != saved_uid
)) {
3190 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nfsd
->nd_cr
));
3191 if (kauth_cred_ismember_gid(nfsd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
3192 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nfsd
->nd_cr
));
3195 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_SUBDIRECTORY
, &context
, nxo
, 0);
3197 /* construct ACL and handle inheritance */
3199 error
= kauth_acl_inherit(dvp
,
3205 if (!error
&& xacl
!= NULL
)
3206 VATTR_SET(vap
, va_acl
, xacl
);
3208 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
3209 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
3211 /* validate new-file security information */
3213 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
3214 if (error
&& (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
))) {
3216 * Most NFS servers just ignore the UID/GID attributes, so we
3217 * try ignoring them if that'll help the request succeed.
3219 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
3220 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
3221 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
3226 error
= VNOP_MKDIR(dvp
, &vp
, &nd
.ni_cnd
, vap
, &context
);
3228 if (!error
&& !VATTR_ALL_SUPPORTED(vap
))
3230 * If some of the requested attributes weren't handled by the VNOP,
3231 * use our fallback code.
3233 error
= vnode_setattr_fallback(vp
, vap
, &context
);
3236 kauth_acl_free(xacl
);
3239 error
= nfsrv_vptofh(nx
, !v3
, NULL
, vp
, &context
, &nfh
);
3241 nfsm_srv_vattr_init(&postat
, v3
);
3242 error
= vnode_getattr(vp
, &postat
, &context
);
3248 * nameidone has to happen before we vnode_put(dvp)
3249 * since it may need to release the fs_nodelock on the dvp
3255 nd
.ni_cnd
.cn_nameiop
= 0;
3258 nfsm_srv_vattr_init(&diraft
, v3
);
3259 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
3262 nfsm_reply(NFSX_SRVFH(v3
, &nfh
) + NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
3265 nfsm_srvpostop_fh(&nfh
);
3266 nfsm_srvpostop_attr(0, &postat
);
3268 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
3270 nfsm_srvfhtom(&nfh
, v3
);
3271 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
3272 nfsm_srvfillattr(&postat
, fp
);
3276 if (nd
.ni_cnd
.cn_nameiop
) {
3278 * nameidone has to happen before we vnode_put(dvp)
3279 * since it may need to release the fs_nodelock on the dvp
3295 nfsrv_rmdir(nfsd
, slp
, procp
, mrq
)
3296 struct nfsrv_descript
*nfsd
;
3297 struct nfssvc_sock
*slp
;
3301 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
3302 mbuf_t nam
= nfsd
->nd_nam
;
3303 caddr_t dpos
= nfsd
->nd_dpos
;
3308 int dirfor_ret
= 1, diraft_ret
= 1;
3309 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
3312 vnode_t vp
, dvp
, dirp
= NULL
;
3313 struct vnode_attr dirfor
, diraft
;
3314 struct nfs_filehandle nfh
;
3315 struct nfs_export
*nx
;
3316 struct nfs_export_options
*nxo
;
3317 struct nameidata nd
;
3318 struct vfs_context context
;
3320 context
.vc_proc
= procp
;
3321 context
.vc_ucred
= nfsd
->nd_cr
;
3324 nfsm_srvmtofh(&nfh
);
3325 nfsm_srvnamesiz(len
, v3
);
3327 nd
.ni_cnd
.cn_nameiop
= DELETE
;
3328 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
3329 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
3331 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
3334 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
3335 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
3342 nfsm_reply(NFSX_WCCDATA(v3
));
3343 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
3351 if (vnode_vtype(vp
) != VDIR
) {
3356 * No rmdir "." please.
3363 * The root of a mounted filesystem cannot be deleted.
3365 if (vnode_isvroot(vp
))
3368 error
= nfsrv_authorize(vp
, dvp
, KAUTH_VNODE_DELETE
, &context
, nxo
, 0);
3370 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, &context
);
3373 * nameidone has to happen before we vnode_put(dvp)
3374 * since it may need to release the fs_nodelock on the dvp
3382 nfsm_srv_vattr_init(&diraft
, v3
);
3383 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
3386 nfsm_reply(NFSX_WCCDATA(v3
));
3388 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
3396 * nfs readdir service
3397 * - mallocs what it thinks is enough to read
3398 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
3399 * - calls VNOP_READDIR()
3400 * - loops around building the reply
3401 * if the output generated exceeds count break out of loop
3402 * The nfsm_clget macro is used here so that the reply will be packed
3403 * tightly in mbuf clusters.
3404 * - it only knows that it has encountered eof when the VNOP_READDIR()
3406 * - as such one readdir rpc will return eof false although you are there
3407 * and then the next will return eof
3408 * - it trims out records with d_fileno == 0
3409 * this doesn't matter for Unix clients, but they might confuse clients
3411 * NB: It is tempting to set eof to true if the VNOP_READDIR() reads less
3412 * than requested, but this may not apply to all filesystems. For
3413 * example, client NFS does not { although it is never remote mounted
3415 * The alternate call nfsrv_readdirplus() does lookups as well.
3416 * PS: The XNFS protocol spec clearly describes what the "count"s arguments
3417 * are supposed to cover. For readdir, the count is the total number of
3418 * bytes included in everything from the directory's postopattr through
3419 * the EOF flag. For readdirplus, the maxcount is the same, and the
3420 * dircount includes all that except for the entry attributes and handles.
3424 nfsrv_readdir(nfsd
, slp
, procp
, mrq
)
3425 struct nfsrv_descript
*nfsd
;
3426 struct nfssvc_sock
*slp
;
3430 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
3431 mbuf_t nam
= nfsd
->nd_nam
;
3432 caddr_t dpos
= nfsd
->nd_dpos
;
3435 struct direntry
*dp
;
3440 mbuf_t mb
, mb2
, mreq
, mp2
;
3441 char *cpos
, *cend
, *cp2
, *rbuf
;
3443 struct vnode_attr at
;
3444 struct nfs_filehandle nfh
;
3445 struct nfs_export
*nx
;
3446 struct nfs_export_options
*nxo
;
3448 char uio_buf
[ UIO_SIZEOF(1) ];
3449 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
3450 int siz
, count
, fullsiz
, eofflag
, nentries
= 0;
3451 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
3452 u_quad_t off
, toff
, verf
;
3455 struct vfs_context context
;
3457 vnopflag
= VNODE_READDIR_EXTENDED
| VNODE_READDIR_REQSEEKOFF
;
3459 nfsm_srvmtofh(&nfh
);
3461 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
3462 fxdr_hyper(tl
, &toff
);
3464 fxdr_hyper(tl
, &verf
);
3467 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
3468 toff
= fxdr_unsigned(u_quad_t
, *tl
++);
3471 count
= fxdr_unsigned(int, *tl
);
3472 siz
= ((count
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
3473 xfer
= NFS_SRVMAXDATA(nfsd
);
3477 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
3478 nfsm_reply(NFSX_UNSIGNED
);
3479 nfsm_srvpostop_attr(getret
, &at
);
3482 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
3484 nfsm_reply(NFSX_UNSIGNED
);
3485 nfsm_srvpostop_attr(getret
, &at
);
3488 context
.vc_proc
= procp
;
3489 context
.vc_ucred
= nfsd
->nd_cr
;
3490 if (!v3
|| (nxo
->nxo_flags
& NX_32BITCLIENTS
))
3491 vnopflag
|= VNODE_READDIR_SEEKOFF32
;
3493 nfsm_srv_vattr_init(&at
, v3
);
3494 error
= getret
= vnode_getattr(vp
, &at
, &context
);
3495 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
3496 error
= NFSERR_BAD_COOKIE
;
3499 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_LIST_DIRECTORY
, &context
, nxo
, 0);
3502 nfsm_reply(NFSX_POSTOPATTR(v3
));
3503 nfsm_srvpostop_attr(getret
, &at
);
3506 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
3510 nfsm_reply(NFSX_POSTOPATTR(v3
));
3511 nfsm_srvpostop_attr(getret
, &at
);
3514 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
3515 &uio_buf
[0], sizeof(uio_buf
));
3520 nfsm_reply(NFSX_POSTOPATTR(v3
));
3521 nfsm_srvpostop_attr(getret
, &at
);
3525 uio_reset(auio
, off
, UIO_SYSSPACE
, UIO_READ
);
3526 uio_addiov(auio
, CAST_USER_ADDR_T(rbuf
), fullsiz
);
3529 error
= VNOP_READDIR(vp
, auio
, vnopflag
, &eofflag
, &nentries
, &context
);
3530 off
= uio_offset(auio
);
3533 nfsm_srv_vattr_init(&at
, v3
);
3534 getret
= vnode_getattr(vp
, &at
, &context
);
3541 nfsm_reply(NFSX_POSTOPATTR(v3
));
3542 nfsm_srvpostop_attr(getret
, &at
);
3545 if (uio_resid(auio
) != 0) {
3546 // LP64todo - fix this
3547 siz
-= uio_resid(auio
);
3550 * If nothing read, return eof
3555 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_COOKIEVERF(v3
) +
3558 nfsm_srvpostop_attr(getret
, &at
);
3559 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
3560 txdr_hyper(&at
.va_filerev
, tl
);
3563 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
3572 * Check for degenerate cases of nothing useful read.
3573 * If so go try again
3577 dp
= (struct direntry
*)cpos
;
3578 while (dp
->d_fileno
== 0 && cpos
< cend
&& nentries
> 0) {
3579 cpos
+= dp
->d_reclen
;
3580 dp
= (struct direntry
*)cpos
;
3583 if (cpos
>= cend
|| nentries
== 0) {
3590 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_COOKIEVERF(v3
) + siz
);
3592 len
= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
;
3593 nfsm_srvpostop_attr(getret
, &at
);
3594 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
3595 txdr_hyper(&at
.va_filerev
, tl
);
3597 len
= 2 * NFSX_UNSIGNED
;
3600 be
= bp
+ mbuf_trailingspace(mp
);
3602 /* Loop through the records and build reply */
3603 while (cpos
< cend
&& nentries
> 0) {
3604 if (dp
->d_fileno
!= 0) {
3605 nlen
= dp
->d_namlen
;
3606 if (!v3
&& (nlen
> NFS_MAXNAMLEN
))
3607 nlen
= NFS_MAXNAMLEN
;
3608 rem
= nfsm_rndup(nlen
)-nlen
;
3609 len
+= (4 * NFSX_UNSIGNED
+ nlen
+ rem
);
3611 len
+= 2 * NFSX_UNSIGNED
;
3617 * Build the directory record xdr from
3618 * the direntry entry.
3622 bp
+= NFSX_UNSIGNED
;
3625 txdr_hyper(&dp
->d_fileno
, &tquad
);
3626 *tl
= tquad
.nfsuquad
[0];
3627 bp
+= NFSX_UNSIGNED
;
3629 *tl
= tquad
.nfsuquad
[1];
3630 bp
+= NFSX_UNSIGNED
;
3632 *tl
= txdr_unsigned(dp
->d_fileno
);
3633 bp
+= NFSX_UNSIGNED
;
3636 *tl
= txdr_unsigned(nlen
);
3637 bp
+= NFSX_UNSIGNED
;
3639 /* And loop around copying the name */
3648 bcopy(cp
, bp
, tsiz
);
3654 /* And null pad to a long boundary */
3655 for (i
= 0; i
< rem
; i
++)
3658 /* Finish off the record with the cookie */
3661 if (vnopflag
& VNODE_READDIR_SEEKOFF32
)
3662 dp
->d_seekoff
&= 0x00000000ffffffffULL
;
3663 txdr_hyper(&dp
->d_seekoff
, &tquad
);
3664 *tl
= tquad
.nfsuquad
[0];
3665 bp
+= NFSX_UNSIGNED
;
3667 *tl
= tquad
.nfsuquad
[1];
3668 bp
+= NFSX_UNSIGNED
;
3670 *tl
= txdr_unsigned(dp
->d_seekoff
);
3671 bp
+= NFSX_UNSIGNED
;
3674 cpos
+= dp
->d_reclen
;
3675 dp
= (struct direntry
*)cpos
;
3680 bp
+= NFSX_UNSIGNED
;
3686 bp
+= NFSX_UNSIGNED
;
3689 mbuf_setlen(mp
, bp
- (char*)mbuf_data(mp
));
3691 mbuf_setlen(mp
, mbuf_len(mp
) + (bp
- bpos
));
3700 u_long fl_fattr
[NFSX_V3FATTR
/ sizeof (u_long
)];
3703 u_long fl_nfh
[NFSX_V3FHMAX
/ sizeof (u_long
)];
3707 nfsrv_readdirplus(nfsd
, slp
, procp
, mrq
)
3708 struct nfsrv_descript
*nfsd
;
3709 struct nfssvc_sock
*slp
;
3713 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
3714 mbuf_t nam
= nfsd
->nd_nam
;
3715 caddr_t dpos
= nfsd
->nd_dpos
;
3718 struct direntry
*dp
;
3723 mbuf_t mb
, mb2
, mreq
, mp2
;
3724 char *cpos
, *cend
, *cp2
, *rbuf
;
3727 struct nfs_filehandle dnfh
, *nfhp
= (struct nfs_filehandle
*)&fl
.fl_fhsize
;
3728 struct nfs_export
*nx
;
3729 struct nfs_export_options
*nxo
;
3731 char uio_buf
[ UIO_SIZEOF(1) ];
3732 struct vnode_attr va
, at
, *vap
= &va
;
3733 struct nfs_fattr
*fp
;
3734 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
3735 int siz
, count
, fullsiz
, eofflag
, dirlen
, nentries
= 0, isdotdot
;
3736 u_quad_t off
, toff
, verf
;
3739 struct vfs_context context
;
3741 vnopflag
= VNODE_READDIR_EXTENDED
| VNODE_READDIR_REQSEEKOFF
;
3743 nfsm_srvmtofh(&dnfh
);
3744 nfsm_dissect(tl
, u_long
*, 6 * NFSX_UNSIGNED
);
3745 fxdr_hyper(tl
, &toff
);
3747 fxdr_hyper(tl
, &verf
);
3749 siz
= fxdr_unsigned(int, *tl
++);
3750 count
= fxdr_unsigned(int, *tl
);
3752 siz
= ((siz
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
3753 xfer
= NFS_SRVMAXDATA(nfsd
);
3757 if ((error
= nfsrv_fhtovp(&dnfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
3758 nfsm_reply(NFSX_UNSIGNED
);
3759 nfsm_srvpostop_attr(getret
, &at
);
3762 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
3764 nfsm_reply(NFSX_UNSIGNED
);
3765 nfsm_srvpostop_attr(getret
, &at
);
3768 context
.vc_proc
= procp
;
3769 context
.vc_ucred
= nfsd
->nd_cr
;
3770 if (nxo
->nxo_flags
& NX_32BITCLIENTS
)
3771 vnopflag
|= VNODE_READDIR_SEEKOFF32
;
3772 nfsm_srv_vattr_init(&at
, 1);
3773 error
= getret
= vnode_getattr(vp
, &at
, &context
);
3774 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
3775 error
= NFSERR_BAD_COOKIE
;
3777 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_LIST_DIRECTORY
, &context
, nxo
, 0);
3781 nfsm_reply(NFSX_V3POSTOPATTR
);
3782 nfsm_srvpostop_attr(getret
, &at
);
3785 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
3790 nfsm_reply(NFSX_V3POSTOPATTR
);
3791 nfsm_srvpostop_attr(getret
, &at
);
3794 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
3795 &uio_buf
[0], sizeof(uio_buf
));
3801 nfsm_reply(NFSX_V3POSTOPATTR
);
3802 nfsm_srvpostop_attr(getret
, &at
);
3806 uio_reset(auio
, off
, UIO_SYSSPACE
, UIO_READ
);
3807 uio_addiov(auio
, CAST_USER_ADDR_T(rbuf
), fullsiz
);
3809 error
= VNOP_READDIR(vp
, auio
, vnopflag
, &eofflag
, &nentries
, &context
);
3810 off
= uio_offset(auio
);
3811 nfsm_srv_vattr_init(&at
, 1);
3812 getret
= vnode_getattr(vp
, &at
, &context
);
3820 nfsm_reply(NFSX_V3POSTOPATTR
);
3821 nfsm_srvpostop_attr(getret
, &at
);
3824 if (uio_resid(auio
) != 0) {
3825 // LP64todo - fix this
3826 siz
-= uio_resid(auio
);
3829 * If nothing read, return eof
3835 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+
3837 nfsm_srvpostop_attr(getret
, &at
);
3838 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
3839 txdr_hyper(&at
.va_filerev
, tl
);
3849 * Check for degenerate cases of nothing useful read.
3850 * If so go try again
3854 dp
= (struct direntry
*)cpos
;
3855 while (dp
->d_fileno
== 0 && cpos
< cend
&& nentries
> 0) {
3856 cpos
+= dp
->d_reclen
;
3857 dp
= (struct direntry
*)cpos
;
3860 if (cpos
>= cend
|| nentries
== 0) {
3867 * Probe one of the directory entries to see if the filesystem
3870 if ((error
= VFS_VGET(vnode_mount(vp
), (ino64_t
)dp
->d_fileno
, &nvp
, &context
))) {
3871 if (error
== ENOTSUP
) /* let others get passed back */
3872 error
= NFSERR_NOTSUPP
;
3876 nfsm_reply(NFSX_V3POSTOPATTR
);
3877 nfsm_srvpostop_attr(getret
, &at
);
3882 dirlen
= len
= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
;
3884 nfsm_srvpostop_attr(getret
, &at
);
3885 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
3886 txdr_hyper(&at
.va_filerev
, tl
);
3889 be
= bp
+ mbuf_trailingspace(mp
);
3891 /* Loop through the records and build reply */
3892 while (cpos
< cend
&& nentries
> 0) {
3893 if (dp
->d_fileno
!= 0) {
3894 nlen
= dp
->d_namlen
;
3895 rem
= nfsm_rndup(nlen
)-nlen
;
3898 * Got to get the vnode for lookup per entry.
3900 if (VFS_VGET(vnode_mount(vp
), (ino64_t
)dp
->d_fileno
, &nvp
, &context
))
3902 isdotdot
= ((dp
->d_namlen
== 2) &&
3903 (dp
->d_name
[0] == '.') && (dp
->d_name
[1] == '.'));
3904 if (nfsrv_vptofh(nx
, 0, (isdotdot
? &dnfh
: NULL
), nvp
, &context
, nfhp
)) {
3905 // XXX file handle is optional, so we should be able to
3906 // XXX return this entry without the file handle
3910 nfsm_srv_vattr_init(vap
, 1);
3911 if (vnode_getattr(nvp
, vap
, &context
)) {
3912 // XXX attributes are optional, so we should be able to
3913 // XXX return this entry without the attributes
3920 * If either the dircount or maxcount will be
3921 * exceeded, get out now. Both of these lengths
3922 * are calculated conservatively, including all
3925 len
+= (8 * NFSX_UNSIGNED
+ nlen
+ rem
+ nfhp
->nfh_len
+
3927 dirlen
+= (6 * NFSX_UNSIGNED
+ nlen
+ rem
);
3928 if (len
> count
|| dirlen
> fullsiz
) {
3934 * Build the directory record xdr from
3935 * the direntry entry.
3937 fp
= (struct nfs_fattr
*)&fl
.fl_fattr
;
3938 nfsm_srvfillattr(vap
, fp
);
3939 fl
.fl_fhsize
= txdr_unsigned(nfhp
->nfh_len
);
3940 fl
.fl_fhok
= nfs_true
;
3941 fl
.fl_postopok
= nfs_true
;
3942 if (vnopflag
& VNODE_READDIR_SEEKOFF32
)
3943 dp
->d_seekoff
&= 0x00000000ffffffffULL
;
3944 txdr_hyper(&dp
->d_seekoff
, &fl
.fl_off
);
3948 bp
+= NFSX_UNSIGNED
;
3951 txdr_hyper(&dp
->d_fileno
, &tquad
);
3952 *tl
= tquad
.nfsuquad
[0];
3953 bp
+= NFSX_UNSIGNED
;
3955 *tl
= tquad
.nfsuquad
[1];
3956 bp
+= NFSX_UNSIGNED
;
3959 *tl
= txdr_unsigned(nlen
);
3960 bp
+= NFSX_UNSIGNED
;
3962 /* And loop around copying the name */
3967 if ((bp
+ xfer
) > be
)
3971 bcopy(cp
, bp
, tsiz
);
3977 /* And null pad to a long boundary */
3978 for (i
= 0; i
< rem
; i
++)
3982 * Now copy the flrep structure out.
3984 xfer
= sizeof(struct flrep
) - sizeof(fl
.fl_nfh
) + fl
.fl_fhsize
;
3988 if ((bp
+ xfer
) > be
)
3992 bcopy(cp
, bp
, tsiz
);
4000 cpos
+= dp
->d_reclen
;
4001 dp
= (struct direntry
*)cpos
;
4008 bp
+= NFSX_UNSIGNED
;
4014 bp
+= NFSX_UNSIGNED
;
4017 mbuf_setlen(mp
, bp
- (char*)mbuf_data(mp
));
4019 mbuf_setlen(mp
, mbuf_len(mp
) + (bp
- bpos
));
4028 * nfs commit service
4031 nfsrv_commit(nfsd
, slp
, procp
, mrq
)
4032 struct nfsrv_descript
*nfsd
;
4033 struct nfssvc_sock
*slp
;
4037 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
4038 mbuf_t nam
= nfsd
->nd_nam
;
4039 caddr_t dpos
= nfsd
->nd_dpos
;
4040 struct vnode_attr bfor
, aft
;
4042 struct nfs_filehandle nfh
;
4043 struct nfs_export
*nx
;
4044 struct nfs_export_options
*nxo
;
4048 int error
= 0, for_ret
= 1, aft_ret
= 1, count
;
4050 mbuf_t mb
, mb2
, mreq
;
4052 struct vfs_context context
;
4054 nfsm_srvmtofh(&nfh
);
4055 nfsm_dissect(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
4058 * XXX At this time VNOP_FSYNC() does not accept offset and byte
4059 * count parameters, so these arguments are useless (someday maybe).
4061 fxdr_hyper(tl
, &off
);
4063 count
= fxdr_unsigned(int, *tl
);
4064 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
4065 nfsm_reply(2 * NFSX_UNSIGNED
);
4066 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
4069 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
4071 nfsm_reply(2 * NFSX_UNSIGNED
);
4072 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
4075 context
.vc_proc
= procp
;
4076 context
.vc_ucred
= nfsd
->nd_cr
;
4078 nfsm_srv_pre_vattr_init(&bfor
, 1);
4079 for_ret
= vnode_getattr(vp
, &bfor
, &context
);
4080 error
= VNOP_FSYNC(vp
, MNT_WAIT
, &context
);
4081 nfsm_srv_vattr_init(&aft
, 1);
4082 aft_ret
= vnode_getattr(vp
, &aft
, &context
);
4084 nfsm_reply(NFSX_V3WCCDATA
+ NFSX_V3WRITEVERF
);
4085 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
4087 nfsm_build(tl
, u_long
*, NFSX_V3WRITEVERF
);
4088 *tl
++ = txdr_unsigned(boottime_sec());
4089 *tl
= txdr_unsigned(0);
4097 * nfs statfs service
4100 nfsrv_statfs(nfsd
, slp
, procp
, mrq
)
4101 struct nfsrv_descript
*nfsd
;
4102 struct nfssvc_sock
*slp
;
4106 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
4107 mbuf_t nam
= nfsd
->nd_nam
;
4108 caddr_t dpos
= nfsd
->nd_dpos
;
4110 struct nfs_statfs
*sfp
;
4114 int error
= 0, getret
= 1;
4115 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
4117 mbuf_t mb
, mb2
, mreq
;
4119 struct vnode_attr at
;
4120 struct nfs_filehandle nfh
;
4121 struct nfs_export
*nx
;
4122 struct nfs_export_options
*nxo
;
4125 struct vfs_context context
;
4127 nfsm_srvmtofh(&nfh
);
4128 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
4129 nfsm_reply(NFSX_UNSIGNED
);
4130 nfsm_srvpostop_attr(getret
, &at
);
4133 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
4135 nfsm_reply(NFSX_UNSIGNED
);
4136 nfsm_srvpostop_attr(getret
, &at
);
4139 context
.vc_proc
= procp
;
4140 context
.vc_ucred
= nfsd
->nd_cr
;
4143 VFSATTR_WANTED(&va
, f_blocks
);
4144 VFSATTR_WANTED(&va
, f_bavail
);
4145 VFSATTR_WANTED(&va
, f_files
);
4146 VFSATTR_WANTED(&va
, f_ffree
);
4147 error
= vfs_getattr(vnode_mount(vp
), &va
, &context
);
4148 blksize
= vnode_mount(vp
)->mnt_vfsstat
.f_bsize
;
4149 nfsm_srv_vattr_init(&at
, v3
);
4150 getret
= vnode_getattr(vp
, &at
, &context
);
4152 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_STATFS(v3
));
4154 nfsm_srvpostop_attr(getret
, &at
);
4157 nfsm_build(sfp
, struct nfs_statfs
*, NFSX_STATFS(v3
));
4159 tval
= (u_quad_t
)(va
.f_blocks
* blksize
);
4160 txdr_hyper(&tval
, &sfp
->sf_tbytes
);
4161 tval
= (u_quad_t
)(va
.f_bfree
* blksize
);
4162 txdr_hyper(&tval
, &sfp
->sf_fbytes
);
4163 tval
= (u_quad_t
)(va
.f_bavail
* blksize
);
4164 txdr_hyper(&tval
, &sfp
->sf_abytes
);
4165 txdr_hyper(&va
.f_files
, &sfp
->sf_tfiles
);
4166 txdr_hyper(&va
.f_ffree
, &sfp
->sf_ffiles
);
4167 txdr_hyper(&va
.f_ffree
, &sfp
->sf_afiles
);
4168 sfp
->sf_invarsec
= 0;
4170 sfp
->sf_tsize
= txdr_unsigned(NFS_V2MAXDATA
);
4171 sfp
->sf_bsize
= txdr_unsigned((unsigned)blksize
);
4172 sfp
->sf_blocks
= txdr_unsigned((unsigned)va
.f_blocks
);
4173 sfp
->sf_bfree
= txdr_unsigned((unsigned)va
.f_bfree
);
4174 sfp
->sf_bavail
= txdr_unsigned((unsigned)va
.f_bavail
);
4181 * nfs fsinfo service
4184 nfsrv_fsinfo(nfsd
, slp
, procp
, mrq
)
4185 struct nfsrv_descript
*nfsd
;
4186 struct nfssvc_sock
*slp
;
4190 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
4191 mbuf_t nam
= nfsd
->nd_nam
;
4192 caddr_t dpos
= nfsd
->nd_dpos
;
4194 struct nfsv3_fsinfo
*sip
;
4197 int error
= 0, getret
= 1, prefsize
, maxsize
;
4199 mbuf_t mb
, mb2
, mreq
;
4201 struct vnode_attr at
;
4202 struct nfs_filehandle nfh
;
4203 struct nfs_export
*nx
;
4204 struct nfs_export_options
*nxo
;
4205 struct vfs_context context
;
4207 nfsm_srvmtofh(&nfh
);
4208 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
4209 nfsm_reply(NFSX_UNSIGNED
);
4210 nfsm_srvpostop_attr(getret
, &at
);
4213 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
4215 nfsm_reply(NFSX_UNSIGNED
);
4216 nfsm_srvpostop_attr(getret
, &at
);
4219 context
.vc_proc
= procp
;
4220 context
.vc_ucred
= nfsd
->nd_cr
;
4222 nfsm_srv_vattr_init(&at
, 1);
4223 getret
= vnode_getattr(vp
, &at
, &context
);
4225 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3FSINFO
);
4226 nfsm_srvpostop_attr(getret
, &at
);
4227 nfsm_build(sip
, struct nfsv3_fsinfo
*, NFSX_V3FSINFO
);
4231 * There should be file system VFS OP(s) to get this information.
4232 * For now, assume our usual NFS defaults.
4234 if (slp
->ns_sotype
== SOCK_DGRAM
) {
4235 maxsize
= NFS_MAXDGRAMDATA
;
4236 prefsize
= NFS_PREFDGRAMDATA
;
4238 maxsize
= prefsize
= NFS_MAXDATA
;
4239 sip
->fs_rtmax
= txdr_unsigned(maxsize
);
4240 sip
->fs_rtpref
= txdr_unsigned(prefsize
);
4241 sip
->fs_rtmult
= txdr_unsigned(NFS_FABLKSIZE
);
4242 sip
->fs_wtmax
= txdr_unsigned(maxsize
);
4243 sip
->fs_wtpref
= txdr_unsigned(prefsize
);
4244 sip
->fs_wtmult
= txdr_unsigned(NFS_FABLKSIZE
);
4245 sip
->fs_dtpref
= txdr_unsigned(prefsize
);
4246 sip
->fs_maxfilesize
.nfsuquad
[0] = 0xffffffff;
4247 sip
->fs_maxfilesize
.nfsuquad
[1] = 0xffffffff;
4248 sip
->fs_timedelta
.nfsv3_sec
= 0;
4249 sip
->fs_timedelta
.nfsv3_nsec
= txdr_unsigned(1);
4250 sip
->fs_properties
= txdr_unsigned(NFSV3FSINFO_LINK
|
4251 NFSV3FSINFO_SYMLINK
| NFSV3FSINFO_HOMOGENEOUS
|
4252 NFSV3FSINFO_CANSETTIME
);
4258 * nfs pathconf service
4261 nfsrv_pathconf(nfsd
, slp
, procp
, mrq
)
4262 struct nfsrv_descript
*nfsd
;
4263 struct nfssvc_sock
*slp
;
4267 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
4268 mbuf_t nam
= nfsd
->nd_nam
;
4269 caddr_t dpos
= nfsd
->nd_dpos
;
4271 struct nfsv3_pathconf
*pc
;
4274 int error
= 0, getret
= 1, linkmax
, namemax
;
4275 int chownres
, notrunc
, case_sensitive
, case_preserving
;
4277 mbuf_t mb
, mb2
, mreq
;
4279 struct vnode_attr at
;
4280 struct nfs_filehandle nfh
;
4281 struct nfs_export
*nx
;
4282 struct nfs_export_options
*nxo
;
4283 struct vfs_context context
;
4285 nfsm_srvmtofh(&nfh
);
4286 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
4287 nfsm_reply(NFSX_UNSIGNED
);
4288 nfsm_srvpostop_attr(getret
, &at
);
4291 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
4293 nfsm_reply(NFSX_UNSIGNED
);
4294 nfsm_srvpostop_attr(getret
, &at
);
4297 context
.vc_proc
= procp
;
4298 context
.vc_ucred
= nfsd
->nd_cr
;
4300 error
= VNOP_PATHCONF(vp
, _PC_LINK_MAX
, &linkmax
, &context
);
4302 error
= VNOP_PATHCONF(vp
, _PC_NAME_MAX
, &namemax
, &context
);
4304 error
= VNOP_PATHCONF(vp
, _PC_CHOWN_RESTRICTED
, &chownres
, &context
);
4306 error
= VNOP_PATHCONF(vp
, _PC_NO_TRUNC
, ¬runc
, &context
);
4308 error
= VNOP_PATHCONF(vp
, _PC_CASE_SENSITIVE
, &case_sensitive
, &context
);
4310 error
= VNOP_PATHCONF(vp
, _PC_CASE_PRESERVING
, &case_preserving
, &context
);
4311 nfsm_srv_vattr_init(&at
, 1);
4312 getret
= vnode_getattr(vp
, &at
, &context
);
4314 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3PATHCONF
);
4315 nfsm_srvpostop_attr(getret
, &at
);
4318 nfsm_build(pc
, struct nfsv3_pathconf
*, NFSX_V3PATHCONF
);
4320 pc
->pc_linkmax
= txdr_unsigned(linkmax
);
4321 pc
->pc_namemax
= txdr_unsigned(namemax
);
4322 pc
->pc_notrunc
= txdr_unsigned(notrunc
);
4323 pc
->pc_chownrestricted
= txdr_unsigned(chownres
);
4324 pc
->pc_caseinsensitive
= txdr_unsigned(!case_sensitive
);
4325 pc
->pc_casepreserving
= txdr_unsigned(case_preserving
);
4332 * Null operation, used by clients to ping server
4337 struct nfsrv_descript
*nfsd
,
4338 struct nfssvc_sock
*slp
,
4339 __unused proc_t procp
,
4342 mbuf_t mrep
= nfsd
->nd_mrep
;
4344 int error
= NFSERR_RETVOID
;
4353 * No operation, used for obsolete procedures
4358 struct nfsrv_descript
*nfsd
,
4359 struct nfssvc_sock
*slp
,
4360 __unused proc_t procp
,
4363 mbuf_t mrep
= nfsd
->nd_mrep
;
4368 if (nfsd
->nd_repstat
)
4369 error
= nfsd
->nd_repstat
;
4371 error
= EPROCUNAVAIL
;
4378 * Perform access checking for vnodes obtained from file handles that would
4379 * refer to files already opened by a Unix client. You cannot just use
4380 * vnode_authorize() for two reasons.
4381 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
4382 * 2 - The owner is to be given access irrespective of mode bits so that
4383 * processes that chmod after opening a file don't break. I don't like
4384 * this because it opens a security hole, but since the nfs server opens
4385 * a security hole the size of a barn door anyhow, what the heck.
4387 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, vnode_authorize()
4388 * will return EPERM instead of EACCESS. EPERM is always an error.
4395 kauth_action_t action
,
4396 vfs_context_t context
,
4397 struct nfs_export_options
*nxo
,
4400 struct vnode_attr vattr
;
4403 if (action
& KAUTH_VNODE_WRITE_RIGHTS
) {
4405 * Disallow write attempts on read-only exports;
4406 * unless the file is a socket or a block or character
4407 * device resident on the file system.
4409 if (nxo
->nxo_flags
& NX_READONLY
) {
4410 switch (vnode_vtype(vp
)) {
4411 case VREG
: case VDIR
: case VLNK
: case VCPLX
:
4418 error
= vnode_authorize(vp
, dvp
, action
, context
);
4420 * Allow certain operations for the owner (reads and writes
4421 * on files that are already open). Picking up from FreeBSD.
4423 if (override
&& (error
== EACCES
)) {
4425 VATTR_WANTED(&vattr
, va_uid
);
4426 if ((vnode_getattr(vp
, &vattr
, context
) == 0) &&
4427 (kauth_cred_getuid(vfs_context_ucred(context
)) == vattr
.va_uid
))
4432 #endif /* NFS_NOSERVER */