1/*
2 * Copyright (c) 2000-2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29/*
30 * Copyright (c) 1989, 1993
31 *	The Regents of the University of California.  All rights reserved.
32 * (c) UNIX System Laboratories, Inc.
33 * All or some portions of this file are derived from material licensed
34 * to the University of California by American Telephone and Telegraph
35 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
36 * the permission of UNIX System Laboratories, Inc.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 *    notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 *    notice, this list of conditions and the following disclaimer in the
45 *    documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 *    must display the following acknowledgement:
48 *	This product includes software developed by the University of
49 *	California, Berkeley and its contributors.
50 * 4. Neither the name of the University nor the names of its contributors
51 *    may be used to endorse or promote products derived from this software
52 *    without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * SUCH DAMAGE.
65 *
66 *	@(#)kpi_vfs.c
67 */
68/*
69 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
70 * support for mandatory and extensible security protections.  This notice
71 * is included in support of clause 2.2 (b) of the Apple Public License,
72 * Version 2.0.
73 */
74
75/*
76 * External virtual filesystem routines
77 */
78
79
80#include <sys/param.h>
81#include <sys/systm.h>
82#include <sys/proc_internal.h>
83#include <sys/kauth.h>
84#include <sys/mount.h>
85#include <sys/mount_internal.h>
86#include <sys/time.h>
87#include <sys/vnode_internal.h>
88#include <sys/stat.h>
89#include <sys/namei.h>
90#include <sys/ucred.h>
91#include <sys/buf.h>
92#include <sys/errno.h>
93#include <sys/malloc.h>
94#include <sys/domain.h>
95#include <sys/mbuf.h>
96#include <sys/syslog.h>
97#include <sys/ubc.h>
98#include <sys/vm.h>
99#include <sys/sysctl.h>
100#include <sys/filedesc.h>
101#include <sys/event.h>
102#include <sys/fsevents.h>
103#include <sys/user.h>
104#include <sys/lockf.h>
105#include <sys/xattr.h>
106
107#include <kern/assert.h>
108#include <kern/kalloc.h>
109#include <kern/task.h>
110
111#include <libkern/OSByteOrder.h>
112
113#include <miscfs/specfs/specdev.h>
114
115#include <mach/mach_types.h>
116#include <mach/memory_object_types.h>
117#include <mach/task.h>
118
119#if CONFIG_MACF
120#include <security/mac_framework.h>
121#endif
122
123#include <sys/sdt.h>
124
125#define ESUCCESS 0
126#undef mount_t
127#undef vnode_t
128
129#define COMPAT_ONLY
130
131#define NATIVE_XATTR(VP)  \
132	((VP)->v_mount ? (VP)->v_mount->mnt_kern_flag & MNTK_EXTENDED_ATTRS : 0)
133
134#if CONFIG_APPLEDOUBLE
135static void xattrfile_remove(vnode_t dvp, const char *basename,
136				vfs_context_t ctx, int force);
137static void xattrfile_setattr(vnode_t dvp, const char * basename,
138				struct vnode_attr * vap, vfs_context_t ctx);
139#endif /* CONFIG_APPLEDOUBLE */
140
141/*
142 * vnode_setneedinactive
143 *
144 * Description: Indicate that when the last iocount on this vnode goes away,
145 * 		and the usecount is also zero, we should inform the filesystem
146 * 		via VNOP_INACTIVE.
147 *
148 * Parameters:  vnode_t		vnode to mark
149 *
150 * Returns:     Nothing
151 *
152 * Notes:       Notably used when we're deleting a file--we need not have a
153 * 		usecount, so VNOP_INACTIVE may not get called by anyone.  We
154 * 		want it called when we drop our iocount.
155 */
156void
157vnode_setneedinactive(vnode_t vp)
158{
159        cache_purge(vp);
160
161        vnode_lock_spin(vp);
162	vp->v_lflag |= VL_NEEDINACTIVE;
163	vnode_unlock(vp);
164}
165
166
167/* ====================================================================== */
168/* ************  EXTERNAL KERNEL APIS  ********************************** */
169/* ====================================================================== */
170
171/*
172 * implementations of exported VFS operations
173 */
174int
175VFS_MOUNT(mount_t mp, vnode_t devvp, user_addr_t data, vfs_context_t ctx)
176{
177	int error;
178
179	if ((mp == dead_mountp) || (mp->mnt_op->vfs_mount == 0))
180		return(ENOTSUP);
181
182	if (vfs_context_is64bit(ctx)) {
183		if (vfs_64bitready(mp)) {
184			error = (*mp->mnt_op->vfs_mount)(mp, devvp, data, ctx);
185		}
186		else {
187			error = ENOTSUP;
188		}
189	}
190	else {
191		error = (*mp->mnt_op->vfs_mount)(mp, devvp, data, ctx);
192	}
193
194	return (error);
195}
196
197int
198VFS_START(mount_t mp, int flags, vfs_context_t ctx)
199{
200	int error;
201
202	if ((mp == dead_mountp) || (mp->mnt_op->vfs_start == 0))
203		return(ENOTSUP);
204
205	error = (*mp->mnt_op->vfs_start)(mp, flags, ctx);
206
207	return (error);
208}
209
210int
211VFS_UNMOUNT(mount_t mp, int flags, vfs_context_t ctx)
212{
213	int error;
214
215	if ((mp == dead_mountp) || (mp->mnt_op->vfs_unmount == 0))
216		return(ENOTSUP);
217
218	error = (*mp->mnt_op->vfs_unmount)(mp, flags, ctx);
219
220	return (error);
221}
222
223/*
224 * Returns:	0			Success
225 *		ENOTSUP			Not supported
226 *		<vfs_root>:ENOENT
227 *		<vfs_root>:???
228 *
229 * Note:	The return codes from the underlying VFS's root routine can't
230 *		be fully enumerated here, since third party VFS authors may not
231 *		limit their error returns to the ones documented here, even
232 *		though this may result in some programs functioning incorrectly.
233 *
234 *		The return codes documented above are those which may currently
235 *		be returned by HFS from hfs_vfs_root, which is a simple wrapper
236 *		for a call to hfs_vget on the volume mount poit, not including
237 *		additional error codes which may be propagated from underlying
238 *		routines called by hfs_vget.
239 */
240int
241VFS_ROOT(mount_t mp, struct vnode  ** vpp, vfs_context_t ctx)
242{
243	int error;
244
245	if ((mp == dead_mountp) || (mp->mnt_op->vfs_root == 0))
246		return(ENOTSUP);
247
248	if (ctx == NULL) {
249		ctx = vfs_context_current();
250	}
251
252	error = (*mp->mnt_op->vfs_root)(mp, vpp, ctx);
253
254	return (error);
255}
256
257int
258VFS_QUOTACTL(mount_t mp, int cmd, uid_t uid, caddr_t datap, vfs_context_t ctx)
259{
260	int error;
261
262	if ((mp == dead_mountp) || (mp->mnt_op->vfs_quotactl == 0))
263		return(ENOTSUP);
264
265	error = (*mp->mnt_op->vfs_quotactl)(mp, cmd, uid, datap, ctx);
266
267	return (error);
268}
269
270int
271VFS_GETATTR(mount_t mp, struct vfs_attr *vfa, vfs_context_t ctx)
272{
273	int error;
274
275	if ((mp == dead_mountp) || (mp->mnt_op->vfs_getattr == 0))
276		return(ENOTSUP);
277
278	if (ctx == NULL) {
279		ctx = vfs_context_current();
280	}
281
282	error = (*mp->mnt_op->vfs_getattr)(mp, vfa, ctx);
283
284	return(error);
285}
286
287int
288VFS_SETATTR(mount_t mp, struct vfs_attr *vfa, vfs_context_t ctx)
289{
290	int error;
291
292	if ((mp == dead_mountp) || (mp->mnt_op->vfs_setattr == 0))
293		return(ENOTSUP);
294
295	if (ctx == NULL) {
296		ctx = vfs_context_current();
297	}
298
299	error = (*mp->mnt_op->vfs_setattr)(mp, vfa, ctx);
300
301	return(error);
302}
303
304int
305VFS_SYNC(mount_t mp, int flags, vfs_context_t ctx)
306{
307	int error;
308
309	if ((mp == dead_mountp) || (mp->mnt_op->vfs_sync == 0))
310		return(ENOTSUP);
311
312	if (ctx == NULL) {
313		ctx = vfs_context_current();
314	}
315
316	error = (*mp->mnt_op->vfs_sync)(mp, flags, ctx);
317
318	return(error);
319}
320
321int
322VFS_VGET(mount_t mp, ino64_t ino, struct vnode **vpp, vfs_context_t ctx)
323{
324	int error;
325
326	if ((mp == dead_mountp) || (mp->mnt_op->vfs_vget == 0))
327		return(ENOTSUP);
328
329	if (ctx == NULL) {
330		ctx = vfs_context_current();
331	}
332
333	error = (*mp->mnt_op->vfs_vget)(mp, ino, vpp, ctx);
334
335	return(error);
336}
337
338int
339VFS_FHTOVP(mount_t mp, int fhlen, unsigned char * fhp, vnode_t * vpp, vfs_context_t ctx)
340{
341	int error;
342
343	if ((mp == dead_mountp) || (mp->mnt_op->vfs_fhtovp == 0))
344		return(ENOTSUP);
345
346	if (ctx == NULL) {
347		ctx = vfs_context_current();
348	}
349
350	error = (*mp->mnt_op->vfs_fhtovp)(mp, fhlen, fhp, vpp, ctx);
351
352	return(error);
353}
354
355int
356VFS_VPTOFH(struct vnode * vp, int *fhlenp, unsigned char * fhp, vfs_context_t ctx)
357{
358	int error;
359
360	if ((vp->v_mount == dead_mountp) || (vp->v_mount->mnt_op->vfs_vptofh == 0))
361		return(ENOTSUP);
362
363	if (ctx == NULL) {
364		ctx = vfs_context_current();
365	}
366
367	error = (*vp->v_mount->mnt_op->vfs_vptofh)(vp, fhlenp, fhp, ctx);
368
369	return(error);
370}
371
372
373/* returns the cached throttle mask for the mount_t */
374uint64_t
375vfs_throttle_mask(mount_t mp)
376{
377	return(mp->mnt_throttle_mask);
378}
379
380/* returns a  copy of vfs type name for the mount_t */
381void
382vfs_name(mount_t mp, char * buffer)
383{
384        strncpy(buffer, mp->mnt_vtable->vfc_name, MFSNAMELEN);
385}
386
387/* returns  vfs type number for the mount_t */
388int
389vfs_typenum(mount_t mp)
390{
391	return(mp->mnt_vtable->vfc_typenum);
392}
393
394/* Safe to cast to "struct label*"; returns "void*" to limit dependence of mount.h on security headers.  */
395void*
396vfs_mntlabel(mount_t mp)
397{
398	return (void*)mp->mnt_mntlabel;
399}
400
401/* returns command modifier flags of mount_t ie. MNT_CMDFLAGS */
402uint64_t
403vfs_flags(mount_t mp)
404{
405	return((uint64_t)(mp->mnt_flag & (MNT_CMDFLAGS | MNT_VISFLAGMASK)));
406}
407
408/* set any of the command modifier flags(MNT_CMDFLAGS) in mount_t */
409void
410vfs_setflags(mount_t mp, uint64_t flags)
411{
412	uint32_t lflags = (uint32_t)(flags & (MNT_CMDFLAGS | MNT_VISFLAGMASK));
413
414	mount_lock(mp);
415	mp->mnt_flag |= lflags;
416	mount_unlock(mp);
417}
418
419/* clear any of the command modifier flags(MNT_CMDFLAGS) in mount_t */
420void
421vfs_clearflags(mount_t mp , uint64_t flags)
422{
423	uint32_t lflags = (uint32_t)(flags & (MNT_CMDFLAGS | MNT_VISFLAGMASK));
424
425	mount_lock(mp);
426	mp->mnt_flag &= ~lflags;
427	mount_unlock(mp);
428}
429
430/* Is the mount_t ronly and upgrade read/write requested? */
431int
432vfs_iswriteupgrade(mount_t mp) /* ronly &&  MNTK_WANTRDWR */
433{
434	return ((mp->mnt_flag & MNT_RDONLY) && (mp->mnt_kern_flag & MNTK_WANTRDWR));
435}
436
437
438/* Is the mount_t mounted ronly */
439int
440vfs_isrdonly(mount_t mp)
441{
442	return (mp->mnt_flag & MNT_RDONLY);
443}
444
445/* Is the mount_t mounted for filesystem synchronous writes? */
446int
447vfs_issynchronous(mount_t mp)
448{
449	return (mp->mnt_flag & MNT_SYNCHRONOUS);
450}
451
452/* Is the mount_t mounted read/write? */
453int
454vfs_isrdwr(mount_t mp)
455{
456	return ((mp->mnt_flag & MNT_RDONLY) == 0);
457}
458
459
460/* Is mount_t marked for update (ie MNT_UPDATE) */
461int
462vfs_isupdate(mount_t mp)
463{
464	return (mp->mnt_flag & MNT_UPDATE);
465}
466
467
468/* Is mount_t marked for reload (ie MNT_RELOAD) */
469int
470vfs_isreload(mount_t mp)
471{
472	return ((mp->mnt_flag & MNT_UPDATE) && (mp->mnt_flag & MNT_RELOAD));
473}
474
475/* Is mount_t marked for forced unmount (ie MNT_FORCE or MNTK_FRCUNMOUNT) */
476int
477vfs_isforce(mount_t mp)
478{
479	if (mp->mnt_lflag & MNT_LFORCE)
480		return(1);
481	else
482		return(0);
483}
484
485int
486vfs_isunmount(mount_t mp)
487{
488	if ((mp->mnt_lflag & MNT_LUNMOUNT)) {
489		return 1;
490	} else {
491		return 0;
492	}
493}
494
495int
496vfs_64bitready(mount_t mp)
497{
498	if ((mp->mnt_vtable->vfc_vfsflags & VFC_VFS64BITREADY))
499		return(1);
500	else
501		return(0);
502}
503
504
505int
506vfs_authcache_ttl(mount_t mp)
507{
508        if ( (mp->mnt_kern_flag & (MNTK_AUTH_OPAQUE | MNTK_AUTH_CACHE_TTL)) )
509	        return (mp->mnt_authcache_ttl);
510	else
511	        return (CACHED_RIGHT_INFINITE_TTL);
512}
513
514void
515vfs_setauthcache_ttl(mount_t mp, int ttl)
516{
517	mount_lock(mp);
518	mp->mnt_kern_flag |= MNTK_AUTH_CACHE_TTL;
519	mp->mnt_authcache_ttl = ttl;
520	mount_unlock(mp);
521}
522
523void
524vfs_clearauthcache_ttl(mount_t mp)
525{
526	mount_lock(mp);
527	mp->mnt_kern_flag &= ~MNTK_AUTH_CACHE_TTL;
528	/*
529	 * back to the default TTL value in case
530	 * MNTK_AUTH_OPAQUE is set on this mount
531	 */
532	mp->mnt_authcache_ttl = CACHED_LOOKUP_RIGHT_TTL;
533	mount_unlock(mp);
534}
535
536int
537vfs_authopaque(mount_t mp)
538{
539	if ((mp->mnt_kern_flag & MNTK_AUTH_OPAQUE))
540		return(1);
541	else
542		return(0);
543}
544
545int
546vfs_authopaqueaccess(mount_t mp)
547{
548	if ((mp->mnt_kern_flag & MNTK_AUTH_OPAQUE_ACCESS))
549		return(1);
550	else
551		return(0);
552}
553
554void
555vfs_setauthopaque(mount_t mp)
556{
557	mount_lock(mp);
558	mp->mnt_kern_flag |= MNTK_AUTH_OPAQUE;
559	mount_unlock(mp);
560}
561
562void
563vfs_setauthopaqueaccess(mount_t mp)
564{
565	mount_lock(mp);
566	mp->mnt_kern_flag |= MNTK_AUTH_OPAQUE_ACCESS;
567	mount_unlock(mp);
568}
569
570void
571vfs_clearauthopaque(mount_t mp)
572{
573	mount_lock(mp);
574	mp->mnt_kern_flag &= ~MNTK_AUTH_OPAQUE;
575	mount_unlock(mp);
576}
577
578void
579vfs_clearauthopaqueaccess(mount_t mp)
580{
581	mount_lock(mp);
582	mp->mnt_kern_flag &= ~MNTK_AUTH_OPAQUE_ACCESS;
583	mount_unlock(mp);
584}
585
586void
587vfs_setextendedsecurity(mount_t mp)
588{
589	mount_lock(mp);
590	mp->mnt_kern_flag |= MNTK_EXTENDED_SECURITY;
591	mount_unlock(mp);
592}
593
594void
595vfs_clearextendedsecurity(mount_t mp)
596{
597	mount_lock(mp);
598	mp->mnt_kern_flag &= ~MNTK_EXTENDED_SECURITY;
599	mount_unlock(mp);
600}
601
602int
603vfs_extendedsecurity(mount_t mp)
604{
605	return(mp->mnt_kern_flag & MNTK_EXTENDED_SECURITY);
606}
607
608/* returns the max size of short symlink in this mount_t */
609uint32_t
610vfs_maxsymlen(mount_t mp)
611{
612	return(mp->mnt_maxsymlinklen);
613}
614
615/* set  max size of short symlink on mount_t */
616void
617vfs_setmaxsymlen(mount_t mp, uint32_t symlen)
618{
619	mp->mnt_maxsymlinklen = symlen;
620}
621
622/* return a pointer to the RO vfs_statfs associated with mount_t */
623struct vfsstatfs *
624vfs_statfs(mount_t mp)
625{
626	return(&mp->mnt_vfsstat);
627}
628
629int
630vfs_getattr(mount_t mp, struct vfs_attr *vfa, vfs_context_t ctx)
631{
632	int		error;
633
634	if ((error = VFS_GETATTR(mp, vfa, ctx)) != 0)
635		return(error);
636
637	/*
638 	 * If we have a filesystem create time, use it to default some others.
639 	 */
640 	if (VFSATTR_IS_SUPPORTED(vfa, f_create_time)) {
641 		if (VFSATTR_IS_ACTIVE(vfa, f_modify_time) && !VFSATTR_IS_SUPPORTED(vfa, f_modify_time))
642 			VFSATTR_RETURN(vfa, f_modify_time, vfa->f_create_time);
643 	}
644
645	return(0);
646}
647
648int
649vfs_setattr(mount_t mp, struct vfs_attr *vfa, vfs_context_t ctx)
650{
651	int error;
652
653	if (vfs_isrdonly(mp))
654		return EROFS;
655
656	error = VFS_SETATTR(mp, vfa, ctx);
657
658	/*
659	 * If we had alternate ways of setting vfs attributes, we'd
660	 * fall back here.
661	 */
662
663	return error;
664}
665
666/* return the private data handle stored in mount_t */
667void *
668vfs_fsprivate(mount_t mp)
669{
670	return(mp->mnt_data);
671}
672
673/* set the private data handle in mount_t */
674void
675vfs_setfsprivate(mount_t mp, void *mntdata)
676{
677	mount_lock(mp);
678	mp->mnt_data = mntdata;
679	mount_unlock(mp);
680}
681
682/* query whether the mount point supports native EAs */
683int
684vfs_nativexattrs(mount_t mp) {
685	return (mp->mnt_kern_flag & MNTK_EXTENDED_ATTRS);
686}
687
688/*
689 * return the block size of the underlying
690 * device associated with mount_t
691 */
692int
693vfs_devblocksize(mount_t mp) {
694
695        return(mp->mnt_devblocksize);
696}
697
698/*
699 * Returns vnode with an iocount that must be released with vnode_put()
700 */
701vnode_t
702vfs_vnodecovered(mount_t mp)
703{
704	vnode_t vp = mp->mnt_vnodecovered;
705	if ((vp == NULL) || (vnode_getwithref(vp) != 0)) {
706		return NULL;
707	} else {
708		return vp;
709	}
710}
711
712/*
713 * Returns device vnode backing a mountpoint with an iocount (if valid vnode exists).
714 * The iocount must be released with vnode_put().  Note that this KPI is subtle
715 * with respect to the validity of using this device vnode for anything substantial
716 * (which is discouraged).  If commands are sent to the device driver without
717 * taking proper steps to ensure that the device is still open, chaos may ensue.
718 * Similarly, this routine should only be called if there is some guarantee that
719 * the mount itself is still valid.
720 */
721vnode_t
722vfs_devvp(mount_t mp)
723{
724	vnode_t vp = mp->mnt_devvp;
725
726	if ((vp != NULLVP) && (vnode_get(vp) == 0)) {
727		return vp;
728	}
729
730	return NULLVP;
731}
732
733/*
734 * return the io attributes associated with mount_t
735 */
736void
737vfs_ioattr(mount_t mp, struct vfsioattr *ioattrp)
738{
739        if (mp == NULL) {
740	        ioattrp->io_maxreadcnt  = MAXPHYS;
741		ioattrp->io_maxwritecnt = MAXPHYS;
742		ioattrp->io_segreadcnt  = 32;
743		ioattrp->io_segwritecnt = 32;
744		ioattrp->io_maxsegreadsize  = MAXPHYS;
745		ioattrp->io_maxsegwritesize = MAXPHYS;
746		ioattrp->io_devblocksize = DEV_BSIZE;
747		ioattrp->io_flags = 0;
748	} else {
749	        ioattrp->io_maxreadcnt  = mp->mnt_maxreadcnt;
750		ioattrp->io_maxwritecnt = mp->mnt_maxwritecnt;
751		ioattrp->io_segreadcnt  = mp->mnt_segreadcnt;
752		ioattrp->io_segwritecnt = mp->mnt_segwritecnt;
753		ioattrp->io_maxsegreadsize  = mp->mnt_maxsegreadsize;
754		ioattrp->io_maxsegwritesize = mp->mnt_maxsegwritesize;
755		ioattrp->io_devblocksize = mp->mnt_devblocksize;
756		ioattrp->io_flags = mp->mnt_ioflags;
757	}
758	ioattrp->io_reserved[0] = NULL;
759	ioattrp->io_reserved[1] = NULL;
760}
761
762
763/*
764 * set the IO attributes associated with mount_t
765 */
766void
767vfs_setioattr(mount_t mp, struct vfsioattr * ioattrp)
768{
769        if (mp == NULL)
770	        return;
771        mp->mnt_maxreadcnt  = ioattrp->io_maxreadcnt;
772	mp->mnt_maxwritecnt = ioattrp->io_maxwritecnt;
773	mp->mnt_segreadcnt  = ioattrp->io_segreadcnt;
774	mp->mnt_segwritecnt = ioattrp->io_segwritecnt;
775	mp->mnt_maxsegreadsize = ioattrp->io_maxsegreadsize;
776	mp->mnt_maxsegwritesize = ioattrp->io_maxsegwritesize;
777	mp->mnt_devblocksize = ioattrp->io_devblocksize;
778	mp->mnt_ioflags = ioattrp->io_flags;
779}
780
781/*
782 * Add a new filesystem into the kernel specified in passed in
783 * vfstable structure. It fills in the vnode
784 * dispatch vector that is to be passed to when vnodes are created.
785 * It returns a handle which is to be used to when the FS is to be removed
786 */
787typedef int (*PFI)(void *);
788extern int vfs_opv_numops;
789errno_t
790vfs_fsadd(struct vfs_fsentry *vfe, vfstable_t * handle)
791{
792	struct vfstable	*newvfstbl = NULL;
793	int	i,j;
794	int	(***opv_desc_vector_p)(void *);
795	int	(**opv_desc_vector)(void *);
796	struct vnodeopv_entry_desc	*opve_descp;
797	int desccount;
798	int descsize;
799	PFI *descptr;
800
801	/*
802	 * This routine is responsible for all the initialization that would
803	 * ordinarily be done as part of the system startup;
804	 */
805
806	if (vfe == (struct vfs_fsentry *)0)
807		return(EINVAL);
808
809	desccount = vfe->vfe_vopcnt;
810	if ((desccount <=0) || ((desccount > 8)) || (vfe->vfe_vfsops == (struct vfsops *)NULL)
811		|| (vfe->vfe_opvdescs == (struct vnodeopv_desc **)NULL))
812		return(EINVAL);
813
814	/* Non-threadsafe filesystems are not supported */
815	if ((vfe->vfe_flags &  (VFS_TBLTHREADSAFE | VFS_TBLFSNODELOCK)) == 0) {
816		return (EINVAL);
817	}
818
819	MALLOC(newvfstbl, void *, sizeof(struct vfstable), M_TEMP,
820	       M_WAITOK);
821	bzero(newvfstbl, sizeof(struct vfstable));
822	newvfstbl->vfc_vfsops = vfe->vfe_vfsops;
823	strncpy(&newvfstbl->vfc_name[0], vfe->vfe_fsname, MFSNAMELEN);
824	if ((vfe->vfe_flags & VFS_TBLNOTYPENUM))
825		newvfstbl->vfc_typenum = maxvfstypenum++;
826	else
827		newvfstbl->vfc_typenum = vfe->vfe_fstypenum;
828
829	newvfstbl->vfc_refcount = 0;
830	newvfstbl->vfc_flags = 0;
831	newvfstbl->vfc_mountroot = NULL;
832	newvfstbl->vfc_next = NULL;
833	newvfstbl->vfc_vfsflags = 0;
834	if (vfe->vfe_flags &  VFS_TBL64BITREADY)
835		newvfstbl->vfc_vfsflags |= VFC_VFS64BITREADY;
836	if (vfe->vfe_flags &  VFS_TBLVNOP_PAGEINV2)
837		newvfstbl->vfc_vfsflags |= VFC_VFSVNOP_PAGEINV2;
838	if (vfe->vfe_flags &  VFS_TBLVNOP_PAGEOUTV2)
839		newvfstbl->vfc_vfsflags |= VFC_VFSVNOP_PAGEOUTV2;
840	if ((vfe->vfe_flags & VFS_TBLLOCALVOL) == VFS_TBLLOCALVOL)
841		newvfstbl->vfc_flags |= MNT_LOCAL;
842	if ((vfe->vfe_flags & VFS_TBLLOCALVOL) && (vfe->vfe_flags & VFS_TBLGENERICMNTARGS) == 0)
843		newvfstbl->vfc_vfsflags |= VFC_VFSLOCALARGS;
844	else
845		newvfstbl->vfc_vfsflags |= VFC_VFSGENERICARGS;
846
847	if (vfe->vfe_flags &  VFS_TBLNATIVEXATTR)
848		newvfstbl->vfc_vfsflags |= VFC_VFSNATIVEXATTR;
849	if (vfe->vfe_flags &  VFS_TBLUNMOUNT_PREFLIGHT)
850		newvfstbl->vfc_vfsflags |= VFC_VFSPREFLIGHT;
851	if (vfe->vfe_flags &  VFS_TBLREADDIR_EXTENDED)
852		newvfstbl->vfc_vfsflags |= VFC_VFSREADDIR_EXTENDED;
853	if (vfe->vfe_flags & VFS_TBLNOMACLABEL)
854		newvfstbl->vfc_vfsflags |= VFC_VFSNOMACLABEL;
855	if (vfe->vfe_flags & VFS_TBLVNOP_NOUPDATEID_RENAME)
856		newvfstbl->vfc_vfsflags |= VFC_VFSVNOP_NOUPDATEID_RENAME;
857
858	/*
859	 * Allocate and init the vectors.
860	 * Also handle backwards compatibility.
861	 *
862	 * We allocate one large block to hold all <desccount>
863	 * vnode operation vectors stored contiguously.
864	 */
865	/* XXX - shouldn't be M_TEMP */
866
867	descsize = desccount * vfs_opv_numops * sizeof(PFI);
868	MALLOC(descptr, PFI *, descsize,
869	       M_TEMP, M_WAITOK);
870	bzero(descptr, descsize);
871
872	newvfstbl->vfc_descptr = descptr;
873	newvfstbl->vfc_descsize = descsize;
874
875	newvfstbl->vfc_sysctl = NULL;
876
877	for (i= 0; i< desccount; i++ ) {
878	opv_desc_vector_p = vfe->vfe_opvdescs[i]->opv_desc_vector_p;
879	/*
880	 * Fill in the caller's pointer to the start of the i'th vector.
881	 * They'll need to supply it when calling vnode_create.
882	 */
883	opv_desc_vector = descptr + i * vfs_opv_numops;
884	*opv_desc_vector_p = opv_desc_vector;
885
886	for (j = 0; vfe->vfe_opvdescs[i]->opv_desc_ops[j].opve_op; j++) {
887		opve_descp = &(vfe->vfe_opvdescs[i]->opv_desc_ops[j]);
888
889		/*
890		 * Sanity check:  is this operation listed
891		 * in the list of operations?  We check this
892		 * by seeing if its offset is zero.  Since
893		 * the default routine should always be listed
894		 * first, it should be the only one with a zero
895		 * offset.  Any other operation with a zero
896		 * offset is probably not listed in
897		 * vfs_op_descs, and so is probably an error.
898		 *
899		 * A panic here means the layer programmer
900		 * has committed the all-too common bug
901		 * of adding a new operation to the layer's
902		 * list of vnode operations but
903		 * not adding the operation to the system-wide
904		 * list of supported operations.
905		 */
906		if (opve_descp->opve_op->vdesc_offset == 0 &&
907		    opve_descp->opve_op->vdesc_offset != VOFFSET(vnop_default)) {
908			printf("vfs_fsadd: operation %s not listed in %s.\n",
909			       opve_descp->opve_op->vdesc_name,
910			       "vfs_op_descs");
911			panic("vfs_fsadd: bad operation");
912		}
913		/*
914		 * Fill in this entry.
915		 */
916		opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
917		    opve_descp->opve_impl;
918	}
919
920
921	/*
922	 * Finally, go back and replace unfilled routines
923	 * with their default.  (Sigh, an O(n^3) algorithm.  I
924	 * could make it better, but that'd be work, and n is small.)
925	 */
926	opv_desc_vector_p = vfe->vfe_opvdescs[i]->opv_desc_vector_p;
927
928	/*
929	 * Force every operations vector to have a default routine.
930	 */
931	opv_desc_vector = *opv_desc_vector_p;
932	if (opv_desc_vector[VOFFSET(vnop_default)] == NULL)
933	    panic("vfs_fsadd: operation vector without default routine.");
934	for (j = 0; j < vfs_opv_numops; j++)
935		if (opv_desc_vector[j] == NULL)
936			opv_desc_vector[j] =
937			    opv_desc_vector[VOFFSET(vnop_default)];
938
939	} /* end of each vnodeopv_desc parsing */
940
941
942
943	*handle = vfstable_add(newvfstbl);
944
945	if (newvfstbl->vfc_typenum <= maxvfstypenum )
946			maxvfstypenum = newvfstbl->vfc_typenum + 1;
947
948	if (newvfstbl->vfc_vfsops->vfs_init) {
949		struct vfsconf vfsc;
950		bzero(&vfsc, sizeof(struct vfsconf));
951		vfsc.vfc_reserved1 = 0;
952		bcopy((*handle)->vfc_name, vfsc.vfc_name, sizeof(vfsc.vfc_name));
953		vfsc.vfc_typenum = (*handle)->vfc_typenum;
954		vfsc.vfc_refcount = (*handle)->vfc_refcount;
955		vfsc.vfc_flags = (*handle)->vfc_flags;
956		vfsc.vfc_reserved2 = 0;
957		vfsc.vfc_reserved3 = 0;
958
959		(*newvfstbl->vfc_vfsops->vfs_init)(&vfsc);
960	}
961
962	FREE(newvfstbl, M_TEMP);
963
964	return(0);
965}
966
967/*
968 * Removes the filesystem from kernel.
969 * The argument passed in is the handle that was given when
970 * file system was added
971 */
972errno_t
973vfs_fsremove(vfstable_t  handle)
974{
975	struct vfstable * vfstbl =  (struct vfstable *)handle;
976	void *old_desc = NULL;
977	errno_t err;
978
979	/* Preflight check for any mounts */
980	mount_list_lock();
981	if ( vfstbl->vfc_refcount != 0 ) {
982		mount_list_unlock();
983		return EBUSY;
984	}
985
986	/*
987	 * save the old descriptor; the free cannot occur unconditionally,
988	 * since vfstable_del() may fail.
989	 */
990	if (vfstbl->vfc_descptr && vfstbl->vfc_descsize) {
991		old_desc = vfstbl->vfc_descptr;
992	}
993	err = vfstable_del(vfstbl);
994
995	mount_list_unlock();
996
997	/* free the descriptor if the delete was successful */
998	if (err == 0 && old_desc) {
999		FREE(old_desc, M_TEMP);
1000	}
1001
1002	return(err);
1003}
1004
1005int
1006vfs_context_pid(vfs_context_t ctx)
1007{
1008	return (proc_pid(vfs_context_proc(ctx)));
1009}
1010
1011int
1012vfs_context_suser(vfs_context_t ctx)
1013{
1014	return (suser(ctx->vc_ucred, NULL));
1015}
1016
1017/*
1018 * Return bit field of signals posted to all threads in the context's process.
1019 *
1020 * XXX Signals should be tied to threads, not processes, for most uses of this
1021 * XXX call.
1022 */
1023int
1024vfs_context_issignal(vfs_context_t ctx, sigset_t mask)
1025{
1026	proc_t p = vfs_context_proc(ctx);
1027	if (p)
1028		return(proc_pendingsignals(p, mask));
1029	return(0);
1030}
1031
1032int
1033vfs_context_is64bit(vfs_context_t ctx)
1034{
1035	proc_t proc = vfs_context_proc(ctx);
1036
1037	if (proc)
1038		return(proc_is64bit(proc));
1039	return(0);
1040}
1041
1042
1043/*
1044 * vfs_context_proc
1045 *
1046 * Description:	Given a vfs_context_t, return the proc_t associated with it.
1047 *
1048 * Parameters:	vfs_context_t			The context to use
1049 *
1050 * Returns:	proc_t				The process for this context
1051 *
1052 * Notes:	This function will return the current_proc() if any of the
1053 *		following conditions are true:
1054 *
1055 *		o	The supplied context pointer is NULL
1056 *		o	There is no Mach thread associated with the context
1057 *		o	There is no Mach task associated with the Mach thread
1058 *		o	There is no proc_t associated with the Mach task
1059 *		o	The proc_t has no per process open file table
1060 *		o	The proc_t is post-vfork()
1061 *
1062 *		This causes this function to return a value matching as
1063 *		closely as possible the previous behaviour, while at the
1064 *		same time avoiding the task lending that results from vfork()
1065 */
1066proc_t
1067vfs_context_proc(vfs_context_t ctx)
1068{
1069	proc_t	proc = NULL;
1070
1071	if (ctx != NULL && ctx->vc_thread != NULL)
1072		proc = (proc_t)get_bsdthreadtask_info(ctx->vc_thread);
1073	if (proc != NULL && (proc->p_fd == NULL || (proc->p_lflag & P_LVFORK)))
1074		proc = NULL;
1075
1076	return(proc == NULL ? current_proc() : proc);
1077}
1078
1079/*
1080 * vfs_context_get_special_port
1081 *
1082 * Description: Return the requested special port from the task associated
1083 * 		with the given context.
1084 *
1085 * Parameters:	vfs_context_t			The context to use
1086 * 		int				Index of special port
1087 * 		ipc_port_t *			Pointer to returned port
1088 *
1089 * Returns:	kern_return_t			see task_get_special_port()
1090 */
1091kern_return_t
1092vfs_context_get_special_port(vfs_context_t ctx, int which, ipc_port_t *portp)
1093{
1094	task_t			task = NULL;
1095
1096	if (ctx != NULL && ctx->vc_thread != NULL)
1097		task = get_threadtask(ctx->vc_thread);
1098
1099	return task_get_special_port(task, which, portp);
1100}
1101
1102/*
1103 * vfs_context_set_special_port
1104 *
1105 * Description: Set the requested special port in the task associated
1106 * 		with the given context.
1107 *
1108 * Parameters:	vfs_context_t			The context to use
1109 * 		int				Index of special port
1110 * 		ipc_port_t			New special port
1111 *
1112 * Returns:	kern_return_t			see task_set_special_port()
1113 */
1114kern_return_t
1115vfs_context_set_special_port(vfs_context_t ctx, int which, ipc_port_t port)
1116{
1117	task_t			task = NULL;
1118
1119	if (ctx != NULL && ctx->vc_thread != NULL)
1120		task = get_threadtask(ctx->vc_thread);
1121
1122	return task_set_special_port(task, which, port);
1123}
1124
1125/*
1126 * vfs_context_thread
1127 *
1128 * Description:	Return the Mach thread associated with a vfs_context_t
1129 *
1130 * Parameters:	vfs_context_t			The context to use
1131 *
1132 * Returns:	thread_t			The thread for this context, or
1133 *						NULL, if there is not one.
1134 *
1135 * Notes:	NULL thread_t's are legal, but discouraged.  They occur only
1136 *		as a result of a static vfs_context_t declaration in a function
1137 *		and will result in this function returning NULL.
1138 *
1139 *		This is intentional; this function should NOT return the
1140 *		current_thread() in this case.
1141 */
1142thread_t
1143vfs_context_thread(vfs_context_t ctx)
1144{
1145	return(ctx->vc_thread);
1146}
1147
1148
1149/*
1150 * vfs_context_cwd
1151 *
1152 * Description:	Returns a reference on the vnode for the current working
1153 *		directory for the supplied context
1154 *
1155 * Parameters:	vfs_context_t			The context to use
1156 *
1157 * Returns:	vnode_t				The current working directory
1158 *						for this context
1159 *
1160 * Notes:	The function first attempts to obtain the current directory
1161 *		from the thread, and if it is not present there, falls back
1162 *		to obtaining it from the process instead.  If it can't be
1163 *		obtained from either place, we return NULLVP.
1164 */
1165vnode_t
1166vfs_context_cwd(vfs_context_t ctx)
1167{
1168	vnode_t cwd = NULLVP;
1169
1170	if(ctx != NULL && ctx->vc_thread != NULL) {
1171		uthread_t uth = get_bsdthread_info(ctx->vc_thread);
1172		proc_t proc;
1173
1174		/*
1175		 * Get the cwd from the thread; if there isn't one, get it
1176		 * from the process, instead.
1177		 */
1178		if ((cwd = uth->uu_cdir) == NULLVP &&
1179		    (proc = (proc_t)get_bsdthreadtask_info(ctx->vc_thread)) != NULL &&
1180		    proc->p_fd != NULL)
1181			cwd = proc->p_fd->fd_cdir;
1182	}
1183
1184	return(cwd);
1185}
1186
1187/*
1188 * vfs_context_create
1189 *
1190 * Description: Allocate and initialize a new context.
1191 *
1192 * Parameters:  vfs_context_t: 			Context to copy, or NULL for new
1193 *
1194 * Returns:     Pointer to new context
1195 *
1196 * Notes:       Copy cred and thread from argument, if available; else
1197 * 		initialize with current thread and new cred.  Returns
1198 * 		with a reference held on the credential.
1199 */
1200vfs_context_t
1201vfs_context_create(vfs_context_t ctx)
1202{
1203	vfs_context_t newcontext;
1204
1205	newcontext = (vfs_context_t)kalloc(sizeof(struct vfs_context));
1206
1207	if (newcontext) {
1208		kauth_cred_t safecred;
1209		if (ctx) {
1210			newcontext->vc_thread = ctx->vc_thread;
1211			safecred = ctx->vc_ucred;
1212		} else {
1213			newcontext->vc_thread = current_thread();
1214			safecred = kauth_cred_get();
1215		}
1216		if (IS_VALID_CRED(safecred))
1217			kauth_cred_ref(safecred);
1218		newcontext->vc_ucred = safecred;
1219		return(newcontext);
1220	}
1221	return(NULL);
1222}
1223
1224
1225vfs_context_t
1226vfs_context_current(void)
1227{
1228	vfs_context_t ctx = NULL;
1229	volatile uthread_t ut = (uthread_t)get_bsdthread_info(current_thread());
1230
1231	if (ut != NULL ) {
1232		if (ut->uu_context.vc_ucred != NULL) {
1233			ctx = &ut->uu_context;
1234		}
1235	}
1236
1237	return(ctx == NULL ? vfs_context_kernel() : ctx);
1238}
1239
1240
1241/*
1242 * XXX Do not ask
1243 *
1244 * Dangerous hack - adopt the first kernel thread as the current thread, to
1245 * get to the vfs_context_t in the uthread associated with a kernel thread.
1246 * This is used by UDF to make the call into IOCDMediaBSDClient,
1247 * IOBDMediaBSDClient, and IODVDMediaBSDClient to determine whether the
1248 * ioctl() is being called from kernel or user space (and all this because
1249 * we do not pass threads into our ioctl()'s, instead of processes).
1250 *
1251 * This is also used by imageboot_setup(), called early from bsd_init() after
1252 * kernproc has been given a credential.
1253 *
1254 * Note: The use of proc_thread() here is a convenience to avoid inclusion
1255 * of many Mach headers to do the reference directly rather than indirectly;
1256 * we will need to forego this convenience when we reture proc_thread().
1257 */
1258static struct vfs_context kerncontext;
1259vfs_context_t
1260vfs_context_kernel(void)
1261{
1262	if (kerncontext.vc_ucred == NOCRED)
1263		kerncontext.vc_ucred = kernproc->p_ucred;
1264	if (kerncontext.vc_thread == NULL)
1265		kerncontext.vc_thread = proc_thread(kernproc);
1266
1267	return(&kerncontext);
1268}
1269
1270
1271int
1272vfs_context_rele(vfs_context_t ctx)
1273{
1274	if (ctx) {
1275		if (IS_VALID_CRED(ctx->vc_ucred))
1276			kauth_cred_unref(&ctx->vc_ucred);
1277		kfree(ctx, sizeof(struct vfs_context));
1278	}
1279	return(0);
1280}
1281
1282
1283kauth_cred_t
1284vfs_context_ucred(vfs_context_t ctx)
1285{
1286	return (ctx->vc_ucred);
1287}
1288
1289/*
1290 * Return true if the context is owned by the superuser.
1291 */
1292int
1293vfs_context_issuser(vfs_context_t ctx)
1294{
1295	return(kauth_cred_issuser(vfs_context_ucred(ctx)));
1296}
1297
1298/*
1299 * Given a context, for all fields of vfs_context_t which
1300 * are not held with a reference, set those fields to the
1301 * values for the current execution context.  Currently, this
1302 * just means the vc_thread.
1303 *
1304 * Returns: 0 for success, nonzero for failure
1305 *
1306 * The intended use is:
1307 * 1. vfs_context_create()	gets the caller a context
1308 * 2. vfs_context_bind() 	sets the unrefcounted data
1309 * 3. vfs_context_rele() 	releases the context
1310 *
1311 */
1312int
1313vfs_context_bind(vfs_context_t ctx)
1314{
1315	ctx->vc_thread = current_thread();
1316	return 0;
1317}
1318
1319/* XXXXXXXXXXXXXX VNODE KAPIS XXXXXXXXXXXXXXXXXXXXXXXXX */
1320
1321
1322/*
1323 * Convert between vnode types and inode formats (since POSIX.1
1324 * defines mode word of stat structure in terms of inode formats).
1325 */
1326enum vtype
1327vnode_iftovt(int mode)
1328{
1329	return(iftovt_tab[((mode) & S_IFMT) >> 12]);
1330}
1331
1332int
1333vnode_vttoif(enum vtype indx)
1334{
1335	return(vttoif_tab[(int)(indx)]);
1336}
1337
1338int
1339vnode_makeimode(int indx, int mode)
1340{
1341	return (int)(VTTOIF(indx) | (mode));
1342}
1343
1344
1345/*
1346 * vnode manipulation functions.
1347 */
1348
1349/* returns system root vnode iocount; It should be released using vnode_put() */
1350vnode_t
1351vfs_rootvnode(void)
1352{
1353	int error;
1354
1355	error = vnode_get(rootvnode);
1356	if (error)
1357		return ((vnode_t)0);
1358	else
1359		return rootvnode;
1360}
1361
1362
1363uint32_t
1364vnode_vid(vnode_t vp)
1365{
1366	return ((uint32_t)(vp->v_id));
1367}
1368
1369mount_t
1370vnode_mount(vnode_t vp)
1371{
1372	return (vp->v_mount);
1373}
1374
1375#if CONFIG_IOSCHED
1376vnode_t
1377vnode_mountdevvp(vnode_t vp)
1378{
1379	if (vp->v_mount)
1380		return (vp->v_mount->mnt_devvp);
1381	else
1382		return ((vnode_t)0);
1383}
1384#endif
1385
1386mount_t
1387vnode_mountedhere(vnode_t vp)
1388{
1389	mount_t mp;
1390
1391	if ((vp->v_type == VDIR) && ((mp = vp->v_mountedhere) != NULL) &&
1392	    (mp->mnt_vnodecovered == vp))
1393		return (mp);
1394	else
1395		return (mount_t)NULL;
1396}
1397
1398/* returns vnode type of vnode_t */
1399enum vtype
1400vnode_vtype(vnode_t vp)
1401{
1402	return (vp->v_type);
1403}
1404
1405/* returns FS specific node saved in vnode */
1406void *
1407vnode_fsnode(vnode_t vp)
1408{
1409	return (vp->v_data);
1410}
1411
1412void
1413vnode_clearfsnode(vnode_t vp)
1414{
1415	vp->v_data = NULL;
1416}
1417
1418dev_t
1419vnode_specrdev(vnode_t vp)
1420{
1421	return(vp->v_rdev);
1422}
1423
1424
1425/* Accessor functions */
1426/* is vnode_t a root vnode */
1427int
1428vnode_isvroot(vnode_t vp)
1429{
1430	return ((vp->v_flag & VROOT)? 1 : 0);
1431}
1432
1433/* is vnode_t a system vnode */
1434int
1435vnode_issystem(vnode_t vp)
1436{
1437	return ((vp->v_flag & VSYSTEM)? 1 : 0);
1438}
1439
1440/* is vnode_t a swap file vnode */
1441int
1442vnode_isswap(vnode_t vp)
1443{
1444	return ((vp->v_flag & VSWAP)? 1 : 0);
1445}
1446
1447/* is vnode_t a tty */
1448int
1449vnode_istty(vnode_t vp)
1450{
1451	return ((vp->v_flag & VISTTY) ? 1 : 0);
1452}
1453
1454/* if vnode_t mount operation in progress */
1455int
1456vnode_ismount(vnode_t vp)
1457{
1458	return ((vp->v_flag & VMOUNT)? 1 : 0);
1459}
1460
1461/* is this vnode under recyle now */
1462int
1463vnode_isrecycled(vnode_t vp)
1464{
1465	int ret;
1466
1467	vnode_lock_spin(vp);
1468	ret =  (vp->v_lflag & (VL_TERMINATE|VL_DEAD))? 1 : 0;
1469	vnode_unlock(vp);
1470	return(ret);
1471}
1472
1473/* vnode was created by background task requesting rapid aging
1474   and has not since been referenced by a normal task */
1475int
1476vnode_israge(vnode_t vp)
1477{
1478        return ((vp->v_flag & VRAGE)? 1 : 0);
1479}
1480
1481int
1482vnode_needssnapshots(vnode_t vp)
1483{
1484	return ((vp->v_flag & VNEEDSSNAPSHOT)? 1 : 0);
1485}
1486
1487
1488/* Check the process/thread to see if we should skip atime updates */
1489int
1490vfs_ctx_skipatime (vfs_context_t ctx) {
1491	struct uthread *ut;
1492	proc_t proc;
1493	thread_t thr;
1494
1495	proc = vfs_context_proc(ctx);
1496	thr = vfs_context_thread (ctx);
1497
1498	/* Validate pointers in case we were invoked via a kernel context */
1499	if (thr && proc) {
1500		ut = get_bsdthread_info (thr);
1501
1502		if (proc->p_lflag & P_LRAGE_VNODES) {
1503			return 1;
1504		}
1505
1506		if (ut) {
1507			if  (ut->uu_flag & UT_RAGE_VNODES) {
1508				return 1;
1509			}
1510		}
1511	}
1512	return 0;
1513}
1514
1515/* is vnode_t marked to not keep data cached once it's been consumed */
1516int
1517vnode_isnocache(vnode_t vp)
1518{
1519	return ((vp->v_flag & VNOCACHE_DATA)? 1 : 0);
1520}
1521
1522/*
1523 * has sequential readahead been disabled on this vnode
1524 */
1525int
1526vnode_isnoreadahead(vnode_t vp)
1527{
1528	return ((vp->v_flag & VRAOFF)? 1 : 0);
1529}
1530
1531int
1532vnode_is_openevt(vnode_t vp)
1533{
1534	return ((vp->v_flag & VOPENEVT)? 1 : 0);
1535}
1536
1537/* is vnode_t a standard one? */
1538int
1539vnode_isstandard(vnode_t vp)
1540{
1541	return ((vp->v_flag & VSTANDARD)? 1 : 0);
1542}
1543
1544/* don't vflush() if SKIPSYSTEM */
1545int
1546vnode_isnoflush(vnode_t vp)
1547{
1548	return ((vp->v_flag & VNOFLUSH)? 1 : 0);
1549}
1550
1551/* is vnode_t a regular file */
1552int
1553vnode_isreg(vnode_t vp)
1554{
1555	return ((vp->v_type == VREG)? 1 : 0);
1556}
1557
1558/* is vnode_t a directory? */
1559int
1560vnode_isdir(vnode_t vp)
1561{
1562	return ((vp->v_type == VDIR)? 1 : 0);
1563}
1564
1565/* is vnode_t a symbolic link ? */
1566int
1567vnode_islnk(vnode_t vp)
1568{
1569	return ((vp->v_type == VLNK)? 1 : 0);
1570}
1571
1572int
1573vnode_lookup_continue_needed(vnode_t vp, struct componentname *cnp)
1574{
1575	struct nameidata *ndp = cnp->cn_ndp;
1576
1577	if (ndp == NULL) {
1578		panic("vnode_lookup_continue_needed(): cnp->cn_ndp is NULL\n");
1579	}
1580
1581	if (vnode_isdir(vp)) {
1582		if (vp->v_mountedhere != NULL) {
1583			goto yes;
1584		}
1585
1586#if CONFIG_TRIGGERS
1587		if (vp->v_resolve) {
1588			goto yes;
1589		}
1590#endif /* CONFIG_TRIGGERS */
1591
1592	}
1593
1594
1595	if (vnode_islnk(vp)) {
1596		/* From lookup():  || *ndp->ni_next == '/') No need for this, we know we're NULL-terminated here */
1597		if (cnp->cn_flags & FOLLOW) {
1598			goto yes;
1599		}
1600		if (ndp->ni_flag & NAMEI_TRAILINGSLASH) {
1601			goto yes;
1602		}
1603	}
1604
1605	return 0;
1606
1607yes:
1608	ndp->ni_flag |= NAMEI_CONTLOOKUP;
1609	return EKEEPLOOKING;
1610}
1611
1612/* is vnode_t a fifo ? */
1613int
1614vnode_isfifo(vnode_t vp)
1615{
1616	return ((vp->v_type == VFIFO)? 1 : 0);
1617}
1618
1619/* is vnode_t a block device? */
1620int
1621vnode_isblk(vnode_t vp)
1622{
1623	return ((vp->v_type == VBLK)? 1 : 0);
1624}
1625
1626int
1627vnode_isspec(vnode_t vp)
1628{
1629	return (((vp->v_type == VCHR) || (vp->v_type == VBLK)) ? 1 : 0);
1630}
1631
1632/* is vnode_t a char device? */
1633int
1634vnode_ischr(vnode_t vp)
1635{
1636	return ((vp->v_type == VCHR)? 1 : 0);
1637}
1638
1639/* is vnode_t a socket? */
1640int
1641vnode_issock(vnode_t vp)
1642{
1643	return ((vp->v_type == VSOCK)? 1 : 0);
1644}
1645
1646/* is vnode_t a device with multiple active vnodes referring to it? */
1647int
1648vnode_isaliased(vnode_t vp)
1649{
1650	enum vtype vt = vp->v_type;
1651	if (!((vt == VCHR) || (vt == VBLK))) {
1652		return 0;
1653	} else {
1654		return (vp->v_specflags & SI_ALIASED);
1655	}
1656}
1657
1658/* is vnode_t a named stream? */
1659int
1660vnode_isnamedstream(
1661#if NAMEDSTREAMS
1662		vnode_t vp
1663#else
1664		__unused vnode_t vp
1665#endif
1666		)
1667{
1668#if NAMEDSTREAMS
1669	return ((vp->v_flag & VISNAMEDSTREAM) ? 1 : 0);
1670#else
1671	return (0);
1672#endif
1673}
1674
1675int
1676vnode_isshadow(
1677#if NAMEDSTREAMS
1678		vnode_t vp
1679#else
1680		__unused vnode_t vp
1681#endif
1682		)
1683{
1684#if NAMEDSTREAMS
1685	return ((vp->v_flag & VISSHADOW) ? 1 : 0);
1686#else
1687	return (0);
1688#endif
1689}
1690
1691/* does vnode have associated named stream vnodes ? */
1692int
1693vnode_hasnamedstreams(
1694#if NAMEDSTREAMS
1695		vnode_t vp
1696#else
1697		__unused vnode_t vp
1698#endif
1699		)
1700{
1701#if NAMEDSTREAMS
1702	return ((vp->v_lflag & VL_HASSTREAMS) ? 1 : 0);
1703#else
1704	return (0);
1705#endif
1706}
1707/* TBD:  set vnode_t to not cache data after it is consumed once; used for quota */
1708void
1709vnode_setnocache(vnode_t vp)
1710{
1711	vnode_lock_spin(vp);
1712	vp->v_flag |= VNOCACHE_DATA;
1713	vnode_unlock(vp);
1714}
1715
1716void
1717vnode_clearnocache(vnode_t vp)
1718{
1719	vnode_lock_spin(vp);
1720	vp->v_flag &= ~VNOCACHE_DATA;
1721	vnode_unlock(vp);
1722}
1723
1724void
1725vnode_set_openevt(vnode_t vp)
1726{
1727	vnode_lock_spin(vp);
1728	vp->v_flag |= VOPENEVT;
1729	vnode_unlock(vp);
1730}
1731
1732void
1733vnode_clear_openevt(vnode_t vp)
1734{
1735	vnode_lock_spin(vp);
1736	vp->v_flag &= ~VOPENEVT;
1737	vnode_unlock(vp);
1738}
1739
1740
1741void
1742vnode_setnoreadahead(vnode_t vp)
1743{
1744	vnode_lock_spin(vp);
1745	vp->v_flag |= VRAOFF;
1746	vnode_unlock(vp);
1747}
1748
1749void
1750vnode_clearnoreadahead(vnode_t vp)
1751{
1752	vnode_lock_spin(vp);
1753	vp->v_flag &= ~VRAOFF;
1754	vnode_unlock(vp);
1755}
1756
1757
1758/* mark vnode_t to skip vflush() is SKIPSYSTEM */
1759void
1760vnode_setnoflush(vnode_t vp)
1761{
1762	vnode_lock_spin(vp);
1763	vp->v_flag |= VNOFLUSH;
1764	vnode_unlock(vp);
1765}
1766
1767void
1768vnode_clearnoflush(vnode_t vp)
1769{
1770	vnode_lock_spin(vp);
1771	vp->v_flag &= ~VNOFLUSH;
1772	vnode_unlock(vp);
1773}
1774
1775
1776/* is vnode_t a blkdevice and has a FS mounted on it */
1777int
1778vnode_ismountedon(vnode_t vp)
1779{
1780	return ((vp->v_specflags & SI_MOUNTEDON)? 1 : 0);
1781}
1782
1783void
1784vnode_setmountedon(vnode_t vp)
1785{
1786	vnode_lock_spin(vp);
1787	vp->v_specflags |= SI_MOUNTEDON;
1788	vnode_unlock(vp);
1789}
1790
1791void
1792vnode_clearmountedon(vnode_t vp)
1793{
1794	vnode_lock_spin(vp);
1795	vp->v_specflags &= ~SI_MOUNTEDON;
1796	vnode_unlock(vp);
1797}
1798
1799
1800void
1801vnode_settag(vnode_t vp, int tag)
1802{
1803	vp->v_tag = tag;
1804
1805}
1806
1807int
1808vnode_tag(vnode_t vp)
1809{
1810	return(vp->v_tag);
1811}
1812
1813vnode_t
1814vnode_parent(vnode_t vp)
1815{
1816
1817	return(vp->v_parent);
1818}
1819
1820void
1821vnode_setparent(vnode_t vp, vnode_t dvp)
1822{
1823	vp->v_parent = dvp;
1824}
1825
1826void
1827vnode_setname(vnode_t vp, char * name)
1828{
1829	vp->v_name = name;
1830}
1831
1832/* return the registered  FS name when adding the FS to kernel */
1833void
1834vnode_vfsname(vnode_t vp, char * buf)
1835{
1836        strncpy(buf, vp->v_mount->mnt_vtable->vfc_name, MFSNAMELEN);
1837}
1838
1839/* return the FS type number */
1840int
1841vnode_vfstypenum(vnode_t vp)
1842{
1843	return(vp->v_mount->mnt_vtable->vfc_typenum);
1844}
1845
1846int
1847vnode_vfs64bitready(vnode_t vp)
1848{
1849
1850	/*
1851	 * Checking for dead_mountp is a bit of a hack for SnowLeopard: <rdar://problem/6269051>
1852	 */
1853	if ((vp->v_mount != dead_mountp) && (vp->v_mount->mnt_vtable->vfc_vfsflags & VFC_VFS64BITREADY))
1854		return(1);
1855	else
1856		return(0);
1857}
1858
1859
1860
1861/* return the visible flags on associated mount point of vnode_t */
1862uint32_t
1863vnode_vfsvisflags(vnode_t vp)
1864{
1865	return(vp->v_mount->mnt_flag & MNT_VISFLAGMASK);
1866}
1867
1868/* return the command modifier flags on associated mount point of vnode_t */
1869uint32_t
1870vnode_vfscmdflags(vnode_t vp)
1871{
1872	return(vp->v_mount->mnt_flag & MNT_CMDFLAGS);
1873}
1874
1875/* return the max symlink of short links  of vnode_t */
1876uint32_t
1877vnode_vfsmaxsymlen(vnode_t vp)
1878{
1879	return(vp->v_mount->mnt_maxsymlinklen);
1880}
1881
1882/* return a pointer to the RO vfs_statfs associated with vnode_t's mount point */
1883struct vfsstatfs *
1884vnode_vfsstatfs(vnode_t vp)
1885{
1886        return(&vp->v_mount->mnt_vfsstat);
1887}
1888
1889/* return a handle to the FSs specific private handle associated with vnode_t's mount point */
1890void *
1891vnode_vfsfsprivate(vnode_t vp)
1892{
1893	return(vp->v_mount->mnt_data);
1894}
1895
1896/* is vnode_t in a rdonly mounted  FS */
1897int
1898vnode_vfsisrdonly(vnode_t vp)
1899{
1900	return ((vp->v_mount->mnt_flag & MNT_RDONLY)? 1 : 0);
1901}
1902
1903int
1904vnode_compound_rename_available(vnode_t vp)
1905{
1906	return vnode_compound_op_available(vp, COMPOUND_VNOP_RENAME);
1907}
1908int
1909vnode_compound_rmdir_available(vnode_t vp)
1910{
1911	return vnode_compound_op_available(vp, COMPOUND_VNOP_RMDIR);
1912}
1913int
1914vnode_compound_mkdir_available(vnode_t vp)
1915{
1916	return vnode_compound_op_available(vp, COMPOUND_VNOP_MKDIR);
1917}
1918int
1919vnode_compound_remove_available(vnode_t vp)
1920{
1921	return vnode_compound_op_available(vp, COMPOUND_VNOP_REMOVE);
1922}
1923int
1924vnode_compound_open_available(vnode_t vp)
1925{
1926	return vnode_compound_op_available(vp, COMPOUND_VNOP_OPEN);
1927}
1928
1929int
1930vnode_compound_op_available(vnode_t vp, compound_vnop_id_t opid)
1931{
1932	return ((vp->v_mount->mnt_compound_ops & opid) != 0);
1933}
1934
1935/*
1936 * Returns vnode ref to current working directory; if a per-thread current
1937 * working directory is in effect, return that instead of the per process one.
1938 *
1939 * XXX Published, but not used.
1940 */
1941vnode_t
1942current_workingdir(void)
1943{
1944	return vfs_context_cwd(vfs_context_current());
1945}
1946
1947/* returns vnode ref to current root(chroot) directory */
1948vnode_t
1949current_rootdir(void)
1950{
1951	proc_t proc = current_proc();
1952	struct vnode * vp ;
1953
1954	if ( (vp = proc->p_fd->fd_rdir) ) {
1955	        if ( (vnode_getwithref(vp)) )
1956		        return (NULL);
1957	}
1958	return vp;
1959}
1960
1961/*
1962 * Get a filesec and optional acl contents from an extended attribute.
1963 * Function will attempt to retrive ACL, UUID, and GUID information using a
1964 * read of a named extended attribute (KAUTH_FILESEC_XATTR).
1965 *
1966 * Parameters:	vp			The vnode on which to operate.
1967 *		fsecp			The filesec (and ACL, if any) being
1968 *					retrieved.
1969 *		ctx			The vnode context in which the
1970 *					operation is to be attempted.
1971 *
1972 * Returns:	0			Success
1973 *		!0			errno value
1974 *
1975 * Notes:	The kauth_filesec_t in '*fsecp', if retrieved, will be in
1976 *		host byte order, as will be the ACL contents, if any.
1977 *		Internally, we will cannonize these values from network (PPC)
1978 *		byte order after we retrieve them so that the on-disk contents
1979 *		of the extended attribute are identical for both PPC and Intel
1980 *		(if we were not being required to provide this service via
1981 *		fallback, this would be the job of the filesystem
1982 *		'VNOP_GETATTR' call).
1983 *
1984 *		We use ntohl() because it has a transitive property on Intel
1985 *		machines and no effect on PPC mancines.  This guarantees us
1986 *
1987 * XXX:		Deleting rather than ignoreing a corrupt security structure is
1988 *		probably the only way to reset it without assistance from an
1989 *		file system integrity checking tool.  Right now we ignore it.
1990 *
1991 * XXX:		We should enummerate the possible errno values here, and where
1992 *		in the code they originated.
1993 */
1994static int
1995vnode_get_filesec(vnode_t vp, kauth_filesec_t *fsecp, vfs_context_t ctx)
1996{
1997	kauth_filesec_t fsec;
1998	uio_t	fsec_uio;
1999	size_t	fsec_size;
2000	size_t	xsize, rsize;
2001	int	error;
2002	uint32_t	host_fsec_magic;
2003	uint32_t	host_acl_entrycount;
2004
2005	fsec = NULL;
2006	fsec_uio = NULL;
2007	error = 0;
2008
2009	/* find out how big the EA is */
2010	if (vn_getxattr(vp, KAUTH_FILESEC_XATTR, NULL, &xsize, XATTR_NOSECURITY, ctx) != 0) {
2011		/* no EA, no filesec */
2012		if ((error == ENOATTR) || (error == ENOENT) || (error == EJUSTRETURN))
2013			error = 0;
2014		/* either way, we are done */
2015		goto out;
2016	}
2017
2018	/*
2019	 * To be valid, a kauth_filesec_t must be large enough to hold a zero
2020	 * ACE entrly ACL, and if it's larger than that, it must have the right
2021	 * number of bytes such that it contains an atomic number of ACEs,
2022	 * rather than partial entries.  Otherwise, we ignore it.
2023	 */
2024	if (!KAUTH_FILESEC_VALID(xsize)) {
2025		KAUTH_DEBUG("    ERROR - Bogus kauth_fiilesec_t: %ld bytes", xsize);
2026		error = 0;
2027		goto out;
2028	}
2029
2030	/* how many entries would fit? */
2031	fsec_size = KAUTH_FILESEC_COUNT(xsize);
2032
2033	/* get buffer and uio */
2034	if (((fsec = kauth_filesec_alloc(fsec_size)) == NULL) ||
2035	    ((fsec_uio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ)) == NULL) ||
2036	    uio_addiov(fsec_uio, CAST_USER_ADDR_T(fsec), xsize)) {
2037		KAUTH_DEBUG("    ERROR - could not allocate iov to read ACL");
2038		error = ENOMEM;
2039		goto out;
2040	}
2041
2042	/* read security attribute */
2043	rsize = xsize;
2044	if ((error = vn_getxattr(vp,
2045		 KAUTH_FILESEC_XATTR,
2046		 fsec_uio,
2047		 &rsize,
2048		 XATTR_NOSECURITY,
2049		 ctx)) != 0) {
2050
2051		/* no attribute - no security data */
2052		if ((error == ENOATTR) || (error == ENOENT) || (error == EJUSTRETURN))
2053			error = 0;
2054		/* either way, we are done */
2055		goto out;
2056	}
2057
2058	/*
2059	 * Validate security structure; the validation must take place in host
2060	 * byte order.  If it's corrupt, we will just ignore it.
2061	 */
2062
2063	/* Validate the size before trying to convert it */
2064	if (rsize < KAUTH_FILESEC_SIZE(0)) {
2065		KAUTH_DEBUG("ACL - DATA TOO SMALL (%d)", rsize);
2066		goto out;
2067	}
2068
2069	/* Validate the magic number before trying to convert it */
2070	host_fsec_magic = ntohl(KAUTH_FILESEC_MAGIC);
2071	if (fsec->fsec_magic != host_fsec_magic) {
2072		KAUTH_DEBUG("ACL - BAD MAGIC %x", host_fsec_magic);
2073		goto out;
2074	}
2075
2076	/* Validate the entry count before trying to convert it. */
2077	host_acl_entrycount = ntohl(fsec->fsec_acl.acl_entrycount);
2078	if (host_acl_entrycount != KAUTH_FILESEC_NOACL) {
2079		if (host_acl_entrycount > KAUTH_ACL_MAX_ENTRIES) {
2080			KAUTH_DEBUG("ACL - BAD ENTRYCOUNT %x", host_acl_entrycount);
2081			goto out;
2082		}
2083	    	if (KAUTH_FILESEC_SIZE(host_acl_entrycount) > rsize) {
2084			KAUTH_DEBUG("ACL - BUFFER OVERFLOW (%d entries too big for %d)", host_acl_entrycount, rsize);
2085			goto out;
2086		}
2087	}
2088
2089	kauth_filesec_acl_setendian(KAUTH_ENDIAN_HOST, fsec, NULL);
2090
2091	*fsecp = fsec;
2092	fsec = NULL;
2093	error = 0;
2094out:
2095	if (fsec != NULL)
2096		kauth_filesec_free(fsec);
2097	if (fsec_uio != NULL)
2098		uio_free(fsec_uio);
2099	if (error)
2100		*fsecp = NULL;
2101	return(error);
2102}
2103
2104/*
2105 * Set a filesec and optional acl contents into an extended attribute.
2106 * function will attempt to store ACL, UUID, and GUID information using a
2107 * write to a named extended attribute (KAUTH_FILESEC_XATTR).  The 'acl'
2108 * may or may not point to the `fsec->fsec_acl`, depending on whether the
2109 * original caller supplied an acl.
2110 *
2111 * Parameters:	vp			The vnode on which to operate.
2112 *		fsec			The filesec being set.
2113 *		acl			The acl to be associated with 'fsec'.
2114 *		ctx			The vnode context in which the
2115 *					operation is to be attempted.
2116 *
2117 * Returns:	0			Success
2118 *		!0			errno value
2119 *
2120 * Notes:	Both the fsec and the acl are always valid.
2121 *
2122 *		The kauth_filesec_t in 'fsec', if any, is in host byte order,
2123 *		as are the acl contents, if they are used.  Internally, we will
2124 *		cannonize these values into network (PPC) byte order before we
2125 *		attempt to write them so that the on-disk contents of the
2126 *		extended attribute are identical for both PPC and Intel (if we
2127 *		were not being required to provide this service via fallback,
2128 *		this would be the job of the filesystem 'VNOP_SETATTR' call).
2129 *		We reverse this process on the way out, so we leave with the
2130 *		same byte order we started with.
2131 *
2132 * XXX:		We should enummerate the possible errno values here, and where
2133 *		in the code they originated.
2134 */
2135static int
2136vnode_set_filesec(vnode_t vp, kauth_filesec_t fsec, kauth_acl_t acl, vfs_context_t ctx)
2137{
2138	uio_t		fsec_uio;
2139	int		error;
2140	uint32_t	saved_acl_copysize;
2141
2142	fsec_uio = NULL;
2143
2144	if ((fsec_uio = uio_create(2, 0, UIO_SYSSPACE, UIO_WRITE)) == NULL) {
2145		KAUTH_DEBUG("    ERROR - could not allocate iov to write ACL");
2146		error = ENOMEM;
2147		goto out;
2148	}
2149	/*
2150	 * Save the pre-converted ACL copysize, because it gets swapped too
2151	 * if we are running with the wrong endianness.
2152	 */
2153	saved_acl_copysize = KAUTH_ACL_COPYSIZE(acl);
2154
2155	kauth_filesec_acl_setendian(KAUTH_ENDIAN_DISK, fsec, acl);
2156
2157	uio_addiov(fsec_uio, CAST_USER_ADDR_T(fsec), KAUTH_FILESEC_SIZE(0) - KAUTH_ACL_SIZE(KAUTH_FILESEC_NOACL));
2158	uio_addiov(fsec_uio, CAST_USER_ADDR_T(acl), saved_acl_copysize);
2159	error = vn_setxattr(vp,
2160	    KAUTH_FILESEC_XATTR,
2161	    fsec_uio,
2162	    XATTR_NOSECURITY, 		/* we have auth'ed already */
2163	    ctx);
2164	VFS_DEBUG(ctx, vp, "SETATTR - set ACL returning %d", error);
2165
2166	kauth_filesec_acl_setendian(KAUTH_ENDIAN_HOST, fsec, acl);
2167
2168out:
2169	if (fsec_uio != NULL)
2170		uio_free(fsec_uio);
2171	return(error);
2172}
2173
2174
2175/*
2176 * Returns:	0			Success
2177 *		ENOMEM			Not enough space [only if has filesec]
2178 *		VNOP_GETATTR:		???
2179 *		vnode_get_filesec:	???
2180 *		kauth_cred_guid2uid:	???
2181 *		kauth_cred_guid2gid:	???
2182 *		vfs_update_vfsstat:	???
2183 */
2184int
2185vnode_getattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
2186{
2187	kauth_filesec_t fsec;
2188	kauth_acl_t facl;
2189	int	error;
2190	uid_t	nuid;
2191	gid_t	ngid;
2192
2193	/* don't ask for extended security data if the filesystem doesn't support it */
2194	if (!vfs_extendedsecurity(vnode_mount(vp))) {
2195		VATTR_CLEAR_ACTIVE(vap, va_acl);
2196		VATTR_CLEAR_ACTIVE(vap, va_uuuid);
2197		VATTR_CLEAR_ACTIVE(vap, va_guuid);
2198	}
2199
2200	/*
2201	 * If the caller wants size values we might have to synthesise, give the
2202	 * filesystem the opportunity to supply better intermediate results.
2203	 */
2204	if (VATTR_IS_ACTIVE(vap, va_data_alloc) ||
2205	    VATTR_IS_ACTIVE(vap, va_total_size) ||
2206	    VATTR_IS_ACTIVE(vap, va_total_alloc)) {
2207		VATTR_SET_ACTIVE(vap, va_data_size);
2208		VATTR_SET_ACTIVE(vap, va_data_alloc);
2209		VATTR_SET_ACTIVE(vap, va_total_size);
2210		VATTR_SET_ACTIVE(vap, va_total_alloc);
2211	}
2212
2213	error = VNOP_GETATTR(vp, vap, ctx);
2214	if (error) {
2215		KAUTH_DEBUG("ERROR - returning %d", error);
2216		goto out;
2217	}
2218
2219	/*
2220	 * If extended security data was requested but not returned, try the fallback
2221	 * path.
2222	 */
2223	if (VATTR_NOT_RETURNED(vap, va_acl) || VATTR_NOT_RETURNED(vap, va_uuuid) || VATTR_NOT_RETURNED(vap, va_guuid)) {
2224		fsec = NULL;
2225
2226		if (XATTR_VNODE_SUPPORTED(vp)) {
2227			/* try to get the filesec */
2228			if ((error = vnode_get_filesec(vp, &fsec, ctx)) != 0)
2229				goto out;
2230		}
2231		/* if no filesec, no attributes */
2232		if (fsec == NULL) {
2233			VATTR_RETURN(vap, va_acl, NULL);
2234			VATTR_RETURN(vap, va_uuuid, kauth_null_guid);
2235			VATTR_RETURN(vap, va_guuid, kauth_null_guid);
2236		} else {
2237
2238			/* looks good, try to return what we were asked for */
2239			VATTR_RETURN(vap, va_uuuid, fsec->fsec_owner);
2240			VATTR_RETURN(vap, va_guuid, fsec->fsec_group);
2241
2242			/* only return the ACL if we were actually asked for it */
2243			if (VATTR_IS_ACTIVE(vap, va_acl)) {
2244				if (fsec->fsec_acl.acl_entrycount == KAUTH_FILESEC_NOACL) {
2245					VATTR_RETURN(vap, va_acl, NULL);
2246				} else {
2247					facl = kauth_acl_alloc(fsec->fsec_acl.acl_entrycount);
2248					if (facl == NULL) {
2249						kauth_filesec_free(fsec);
2250						error = ENOMEM;
2251						goto out;
2252					}
2253					bcopy(&fsec->fsec_acl, facl, KAUTH_ACL_COPYSIZE(&fsec->fsec_acl));
2254					VATTR_RETURN(vap, va_acl, facl);
2255				}
2256			}
2257			kauth_filesec_free(fsec);
2258		}
2259	}
2260	/*
2261	 * If someone gave us an unsolicited filesec, toss it.  We promise that
2262	 * we're OK with a filesystem giving us anything back, but our callers
2263	 * only expect what they asked for.
2264	 */
2265	if (VATTR_IS_SUPPORTED(vap, va_acl) && !VATTR_IS_ACTIVE(vap, va_acl)) {
2266		if (vap->va_acl != NULL)
2267			kauth_acl_free(vap->va_acl);
2268		VATTR_CLEAR_SUPPORTED(vap, va_acl);
2269	}
2270
2271#if 0	/* enable when we have a filesystem only supporting UUIDs */
2272	/*
2273	 * Handle the case where we need a UID/GID, but only have extended
2274	 * security information.
2275	 */
2276	if (VATTR_NOT_RETURNED(vap, va_uid) &&
2277	    VATTR_IS_SUPPORTED(vap, va_uuuid) &&
2278	    !kauth_guid_equal(&vap->va_uuuid, &kauth_null_guid)) {
2279		if ((error = kauth_cred_guid2uid(&vap->va_uuuid, &nuid)) == 0)
2280			VATTR_RETURN(vap, va_uid, nuid);
2281	}
2282	if (VATTR_NOT_RETURNED(vap, va_gid) &&
2283	    VATTR_IS_SUPPORTED(vap, va_guuid) &&
2284	    !kauth_guid_equal(&vap->va_guuid, &kauth_null_guid)) {
2285		if ((error = kauth_cred_guid2gid(&vap->va_guuid, &ngid)) == 0)
2286			VATTR_RETURN(vap, va_gid, ngid);
2287	}
2288#endif
2289
2290	/*
2291	 * Handle uid/gid == 99 and MNT_IGNORE_OWNERSHIP here.
2292	 */
2293	if (VATTR_IS_ACTIVE(vap, va_uid)) {
2294		if (vfs_context_issuser(ctx) && VATTR_IS_SUPPORTED(vap, va_uid)) {
2295			nuid = vap->va_uid;
2296		} else if (vp->v_mount->mnt_flag & MNT_IGNORE_OWNERSHIP) {
2297			nuid = vp->v_mount->mnt_fsowner;
2298			if (nuid == KAUTH_UID_NONE)
2299				nuid = 99;
2300		} else if (VATTR_IS_SUPPORTED(vap, va_uid)) {
2301			nuid = vap->va_uid;
2302		} else {
2303			/* this will always be something sensible */
2304			nuid = vp->v_mount->mnt_fsowner;
2305		}
2306		if ((nuid == 99) && !vfs_context_issuser(ctx))
2307			nuid = kauth_cred_getuid(vfs_context_ucred(ctx));
2308		VATTR_RETURN(vap, va_uid, nuid);
2309	}
2310	if (VATTR_IS_ACTIVE(vap, va_gid)) {
2311		if (vfs_context_issuser(ctx) && VATTR_IS_SUPPORTED(vap, va_gid)) {
2312			ngid = vap->va_gid;
2313		} else if (vp->v_mount->mnt_flag & MNT_IGNORE_OWNERSHIP) {
2314			ngid = vp->v_mount->mnt_fsgroup;
2315			if (ngid == KAUTH_GID_NONE)
2316				ngid = 99;
2317		} else if (VATTR_IS_SUPPORTED(vap, va_gid)) {
2318			ngid = vap->va_gid;
2319		} else {
2320			/* this will always be something sensible */
2321			ngid = vp->v_mount->mnt_fsgroup;
2322		}
2323		if ((ngid == 99) && !vfs_context_issuser(ctx))
2324			ngid = kauth_cred_getgid(vfs_context_ucred(ctx));
2325		VATTR_RETURN(vap, va_gid, ngid);
2326	}
2327
2328	/*
2329	 * Synthesise some values that can be reasonably guessed.
2330	 */
2331	if (!VATTR_IS_SUPPORTED(vap, va_iosize))
2332		VATTR_RETURN(vap, va_iosize, vp->v_mount->mnt_vfsstat.f_iosize);
2333
2334	if (!VATTR_IS_SUPPORTED(vap, va_flags))
2335		VATTR_RETURN(vap, va_flags, 0);
2336
2337	if (!VATTR_IS_SUPPORTED(vap, va_filerev))
2338		VATTR_RETURN(vap, va_filerev, 0);
2339
2340	if (!VATTR_IS_SUPPORTED(vap, va_gen))
2341		VATTR_RETURN(vap, va_gen, 0);
2342
2343	/*
2344	 * Default sizes.  Ordering here is important, as later defaults build on earlier ones.
2345	 */
2346	if (!VATTR_IS_SUPPORTED(vap, va_data_size))
2347		VATTR_RETURN(vap, va_data_size, 0);
2348
2349	/* do we want any of the possibly-computed values? */
2350	if (VATTR_IS_ACTIVE(vap, va_data_alloc) ||
2351	    VATTR_IS_ACTIVE(vap, va_total_size) ||
2352	    VATTR_IS_ACTIVE(vap, va_total_alloc)) {
2353                /* make sure f_bsize is valid */
2354                if (vp->v_mount->mnt_vfsstat.f_bsize == 0) {
2355                    if ((error = vfs_update_vfsstat(vp->v_mount, ctx, VFS_KERNEL_EVENT)) != 0)
2356                        goto out;
2357                }
2358
2359		/* default va_data_alloc from va_data_size */
2360		if (!VATTR_IS_SUPPORTED(vap, va_data_alloc))
2361			VATTR_RETURN(vap, va_data_alloc, roundup(vap->va_data_size, vp->v_mount->mnt_vfsstat.f_bsize));
2362
2363		/* default va_total_size from va_data_size */
2364		if (!VATTR_IS_SUPPORTED(vap, va_total_size))
2365			VATTR_RETURN(vap, va_total_size, vap->va_data_size);
2366
2367		/* default va_total_alloc from va_total_size which is guaranteed at this point */
2368		if (!VATTR_IS_SUPPORTED(vap, va_total_alloc))
2369			VATTR_RETURN(vap, va_total_alloc, roundup(vap->va_total_size, vp->v_mount->mnt_vfsstat.f_bsize));
2370	}
2371
2372	/*
2373	 * If we don't have a change time, pull it from the modtime.
2374	 */
2375	if (!VATTR_IS_SUPPORTED(vap, va_change_time) && VATTR_IS_SUPPORTED(vap, va_modify_time))
2376		VATTR_RETURN(vap, va_change_time, vap->va_modify_time);
2377
2378	/*
2379	 * This is really only supported for the creation VNOPs, but since the field is there
2380	 * we should populate it correctly.
2381	 */
2382	VATTR_RETURN(vap, va_type, vp->v_type);
2383
2384	/*
2385	 * The fsid can be obtained from the mountpoint directly.
2386	 */
2387	VATTR_RETURN(vap, va_fsid, vp->v_mount->mnt_vfsstat.f_fsid.val[0]);
2388
2389out:
2390
2391	return(error);
2392}
2393
2394/*
2395 * Set the attributes on a vnode in a vnode context.
2396 *
2397 * Parameters:	vp			The vnode whose attributes to set.
2398 *		vap			A pointer to the attributes to set.
2399 *		ctx			The vnode context in which the
2400 *					operation is to be attempted.
2401 *
2402 * Returns:	0			Success
2403 *		!0			errno value
2404 *
2405 * Notes:	The kauth_filesec_t in 'vap', if any, is in host byte order.
2406 *
2407 *		The contents of the data area pointed to by 'vap' may be
2408 *		modified if the vnode is on a filesystem which has been
2409 *		mounted with ingore ownership flags, or by the underlyng
2410 *		VFS itself, or by the fallback code, if the underlying VFS
2411 *		does not support ACL, UUID, or GUUID attributes directly.
2412 *
2413 * XXX:		We should enummerate the possible errno values here, and where
2414 *		in the code they originated.
2415 */
2416int
2417vnode_setattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
2418{
2419	int	error, is_perm_change=0;
2420
2421	/*
2422	 * Make sure the filesystem is mounted R/W.
2423	 * If not, return an error.
2424	 */
2425	if (vfs_isrdonly(vp->v_mount)) {
2426		error = EROFS;
2427		goto out;
2428	}
2429#if NAMEDSTREAMS
2430	/* For streams, va_data_size is the only setable attribute. */
2431	if ((vp->v_flag & VISNAMEDSTREAM) && (vap->va_active != VNODE_ATTR_va_data_size)) {
2432		error = EPERM;
2433		goto out;
2434	}
2435#endif
2436
2437	/*
2438	 * If ownership is being ignored on this volume, we silently discard
2439	 * ownership changes.
2440	 */
2441	if (vp->v_mount->mnt_flag & MNT_IGNORE_OWNERSHIP) {
2442		VATTR_CLEAR_ACTIVE(vap, va_uid);
2443		VATTR_CLEAR_ACTIVE(vap, va_gid);
2444	}
2445
2446	if (   VATTR_IS_ACTIVE(vap, va_uid)  || VATTR_IS_ACTIVE(vap, va_gid)
2447	    || VATTR_IS_ACTIVE(vap, va_mode) || VATTR_IS_ACTIVE(vap, va_acl)) {
2448	    is_perm_change = 1;
2449	}
2450
2451	/*
2452	 * Make sure that extended security is enabled if we're going to try
2453	 * to set any.
2454	 */
2455	if (!vfs_extendedsecurity(vnode_mount(vp)) &&
2456	    (VATTR_IS_ACTIVE(vap, va_acl) || VATTR_IS_ACTIVE(vap, va_uuuid) || VATTR_IS_ACTIVE(vap, va_guuid))) {
2457		KAUTH_DEBUG("SETATTR - returning ENOTSUP to request to set extended security");
2458		error = ENOTSUP;
2459		goto out;
2460	}
2461
2462	error = VNOP_SETATTR(vp, vap, ctx);
2463
2464	if ((error == 0) && !VATTR_ALL_SUPPORTED(vap))
2465		error = vnode_setattr_fallback(vp, vap, ctx);
2466
2467#if CONFIG_FSE
2468	// only send a stat_changed event if this is more than
2469	// just an access or backup time update
2470	if (error == 0 && (vap->va_active != VNODE_ATTR_BIT(va_access_time)) && (vap->va_active != VNODE_ATTR_BIT(va_backup_time))) {
2471	    if (is_perm_change) {
2472		if (need_fsevent(FSE_CHOWN, vp)) {
2473		    add_fsevent(FSE_CHOWN, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE);
2474		}
2475	    } else if(need_fsevent(FSE_STAT_CHANGED, vp)) {
2476		add_fsevent(FSE_STAT_CHANGED, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE);
2477	    }
2478	}
2479#endif
2480
2481out:
2482	return(error);
2483}
2484
2485/*
2486 * Fallback for setting the attributes on a vnode in a vnode context.  This
2487 * Function will attempt to store ACL, UUID, and GUID information utilizing
2488 * a read/modify/write operation against an EA used as a backing store for
2489 * the object.
2490 *
2491 * Parameters:	vp			The vnode whose attributes to set.
2492 *		vap			A pointer to the attributes to set.
2493 *		ctx			The vnode context in which the
2494 *					operation is to be attempted.
2495 *
2496 * Returns:	0			Success
2497 *		!0			errno value
2498 *
2499 * Notes:	The kauth_filesec_t in 'vap', if any, is in host byte order,
2500 *		as are the fsec and lfsec, if they are used.
2501 *
2502 *		The contents of the data area pointed to by 'vap' may be
2503 *		modified to indicate that the attribute is supported for
2504 *		any given requested attribute.
2505 *
2506 * XXX:		We should enummerate the possible errno values here, and where
2507 *		in the code they originated.
2508 */
2509int
2510vnode_setattr_fallback(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
2511{
2512	kauth_filesec_t fsec;
2513	kauth_acl_t facl;
2514	struct kauth_filesec lfsec;
2515	int	error;
2516
2517	error = 0;
2518
2519	/*
2520	 * Extended security fallback via extended attributes.
2521	 *
2522	 * Note that we do not free the filesec; the caller is expected to
2523	 * do this.
2524	 */
2525	if (VATTR_NOT_RETURNED(vap, va_acl) ||
2526	    VATTR_NOT_RETURNED(vap, va_uuuid) ||
2527	    VATTR_NOT_RETURNED(vap, va_guuid)) {
2528		VFS_DEBUG(ctx, vp, "SETATTR - doing filesec fallback");
2529
2530		/*
2531		 * Fail for file types that we don't permit extended security
2532		 * to be set on.
2533		 */
2534		if (!XATTR_VNODE_SUPPORTED(vp)) {
2535			VFS_DEBUG(ctx, vp, "SETATTR - Can't write ACL to file type %d", vnode_vtype(vp));
2536			error = EINVAL;
2537			goto out;
2538		}
2539
2540		/*
2541		 * If we don't have all the extended security items, we need
2542		 * to fetch the existing data to perform a read-modify-write
2543		 * operation.
2544		 */
2545		fsec = NULL;
2546		if (!VATTR_IS_ACTIVE(vap, va_acl) ||
2547		    !VATTR_IS_ACTIVE(vap, va_uuuid) ||
2548		    !VATTR_IS_ACTIVE(vap, va_guuid)) {
2549			if ((error = vnode_get_filesec(vp, &fsec, ctx)) != 0) {
2550				KAUTH_DEBUG("SETATTR - ERROR %d fetching filesec for update", error);
2551				goto out;
2552			}
2553		}
2554		/* if we didn't get a filesec, use our local one */
2555		if (fsec == NULL) {
2556			KAUTH_DEBUG("SETATTR - using local filesec for new/full update");
2557			fsec = &lfsec;
2558		} else {
2559			KAUTH_DEBUG("SETATTR - updating existing filesec");
2560		}
2561		/* find the ACL */
2562		facl = &fsec->fsec_acl;
2563
2564		/* if we're using the local filesec, we need to initialise it */
2565		if (fsec == &lfsec) {
2566			fsec->fsec_magic = KAUTH_FILESEC_MAGIC;
2567			fsec->fsec_owner = kauth_null_guid;
2568			fsec->fsec_group = kauth_null_guid;
2569			facl->acl_entrycount = KAUTH_FILESEC_NOACL;
2570			facl->acl_flags = 0;
2571		}
2572
2573		/*
2574		 * Update with the supplied attributes.
2575		 */
2576		if (VATTR_IS_ACTIVE(vap, va_uuuid)) {
2577			KAUTH_DEBUG("SETATTR - updating owner UUID");
2578			fsec->fsec_owner = vap->va_uuuid;
2579			VATTR_SET_SUPPORTED(vap, va_uuuid);
2580		}
2581		if (VATTR_IS_ACTIVE(vap, va_guuid)) {
2582			KAUTH_DEBUG("SETATTR - updating group UUID");
2583			fsec->fsec_group = vap->va_guuid;
2584			VATTR_SET_SUPPORTED(vap, va_guuid);
2585		}
2586		if (VATTR_IS_ACTIVE(vap, va_acl)) {
2587			if (vap->va_acl == NULL) {
2588				KAUTH_DEBUG("SETATTR - removing ACL");
2589				facl->acl_entrycount = KAUTH_FILESEC_NOACL;
2590			} else {
2591				KAUTH_DEBUG("SETATTR - setting ACL with %d entries", vap->va_acl->acl_entrycount);
2592				facl = vap->va_acl;
2593			}
2594			VATTR_SET_SUPPORTED(vap, va_acl);
2595		}
2596
2597		/*
2598		 * If the filesec data is all invalid, we can just remove
2599		 * the EA completely.
2600		 */
2601		if ((facl->acl_entrycount == KAUTH_FILESEC_NOACL) &&
2602		    kauth_guid_equal(&fsec->fsec_owner, &kauth_null_guid) &&
2603		    kauth_guid_equal(&fsec->fsec_group, &kauth_null_guid)) {
2604			error = vn_removexattr(vp, KAUTH_FILESEC_XATTR, XATTR_NOSECURITY, ctx);
2605			/* no attribute is ok, nothing to delete */
2606			if (error == ENOATTR)
2607				error = 0;
2608			VFS_DEBUG(ctx, vp, "SETATTR - remove filesec returning %d", error);
2609		} else {
2610			/* write the EA */
2611			error = vnode_set_filesec(vp, fsec, facl, ctx);
2612			VFS_DEBUG(ctx, vp, "SETATTR - update filesec returning %d", error);
2613		}
2614
2615		/* if we fetched a filesec, dispose of the buffer */
2616		if (fsec != &lfsec)
2617			kauth_filesec_free(fsec);
2618	}
2619out:
2620
2621	return(error);
2622}
2623
2624/*
2625 * Upcall for a filesystem to tell VFS about an EVFILT_VNODE-type
2626 * event on a vnode.
2627 */
2628int
2629vnode_notify(vnode_t vp, uint32_t events, struct vnode_attr *vap)
2630{
2631	/* These are the same as the corresponding knotes, at least for now.  Cheating a little. */
2632	uint32_t knote_mask = (VNODE_EVENT_WRITE | VNODE_EVENT_DELETE | VNODE_EVENT_RENAME
2633		| VNODE_EVENT_LINK | VNODE_EVENT_EXTEND | VNODE_EVENT_ATTRIB);
2634	uint32_t dir_contents_mask = (VNODE_EVENT_DIR_CREATED | VNODE_EVENT_FILE_CREATED
2635			| VNODE_EVENT_DIR_REMOVED | VNODE_EVENT_FILE_REMOVED);
2636	uint32_t knote_events = (events & knote_mask);
2637
2638	/* Permissions are not explicitly part of the kqueue model */
2639	if (events & VNODE_EVENT_PERMS) {
2640		knote_events |= NOTE_ATTRIB;
2641	}
2642
2643	/* Directory contents information just becomes NOTE_WRITE */
2644	if ((vnode_isdir(vp)) && (events & dir_contents_mask)) {
2645		knote_events |= NOTE_WRITE;
2646	}
2647
2648	if (knote_events) {
2649		lock_vnode_and_post(vp, knote_events);
2650#if CONFIG_FSE
2651		if (vap != NULL) {
2652			create_fsevent_from_kevent(vp, events, vap);
2653		}
2654#else
2655		(void)vap;
2656#endif
2657	}
2658
2659	return 0;
2660}
2661
2662
2663
2664int
2665vnode_isdyldsharedcache(vnode_t vp)
2666{
2667	return ((vp->v_flag & VSHARED_DYLD) ? 1 : 0);
2668}
2669
2670
2671/*
2672 * For a filesystem that isn't tracking its own vnode watchers:
2673 * check whether a vnode is being monitored.
2674 */
2675int
2676vnode_ismonitored(vnode_t vp) {
2677	return (vp->v_knotes.slh_first != NULL);
2678}
2679
2680/*
2681 * Initialize a struct vnode_attr and activate the attributes required
2682 * by the vnode_notify() call.
2683 */
2684int
2685vfs_get_notify_attributes(struct vnode_attr *vap)
2686{
2687	VATTR_INIT(vap);
2688	vap->va_active = VNODE_NOTIFY_ATTRS;
2689	return 0;
2690}
2691
2692#if CONFIG_TRIGGERS
2693int
2694vfs_settriggercallback(fsid_t *fsid, vfs_trigger_callback_t vtc, void *data, uint32_t flags __unused, vfs_context_t ctx)
2695{
2696	int error;
2697	mount_t mp;
2698
2699	mp = mount_list_lookupby_fsid(fsid, 0 /* locked */, 1 /* withref */);
2700	if (mp == NULL) {
2701		return ENOENT;
2702	}
2703
2704	error = vfs_busy(mp, LK_NOWAIT);
2705	mount_iterdrop(mp);
2706
2707	if (error != 0) {
2708		return ENOENT;
2709	}
2710
2711	mount_lock(mp);
2712	if (mp->mnt_triggercallback != NULL) {
2713		error = EBUSY;
2714		mount_unlock(mp);
2715		goto out;
2716	}
2717
2718	mp->mnt_triggercallback = vtc;
2719	mp->mnt_triggerdata = data;
2720	mount_unlock(mp);
2721
2722	mp->mnt_triggercallback(mp, VTC_REPLACE, data, ctx);
2723
2724out:
2725	vfs_unbusy(mp);
2726	return 0;
2727}
2728#endif /* CONFIG_TRIGGERS */
2729
2730/*
2731 *  Definition of vnode operations.
2732 */
2733
2734#if 0
2735/*
2736 *#
2737 *#% lookup       dvp     L ? ?
2738 *#% lookup       vpp     - L -
2739 */
2740struct vnop_lookup_args {
2741	struct vnodeop_desc *a_desc;
2742	vnode_t a_dvp;
2743	vnode_t *a_vpp;
2744	struct componentname *a_cnp;
2745	vfs_context_t a_context;
2746};
2747#endif /* 0*/
2748
2749/*
2750 * Returns:	0			Success
2751 *	lock_fsnode:ENOENT		No such file or directory [only for VFS
2752 *					 that is not thread safe & vnode is
2753 *					 currently being/has been terminated]
2754 *	<vfs_lookup>:ENAMETOOLONG
2755 *	<vfs_lookup>:ENOENT
2756 *	<vfs_lookup>:EJUSTRETURN
2757 *	<vfs_lookup>:EPERM
2758 *	<vfs_lookup>:EISDIR
2759 *	<vfs_lookup>:ENOTDIR
2760 *	<vfs_lookup>:???
2761 *
2762 * Note:	The return codes from the underlying VFS's lookup routine can't
2763 *		be fully enumerated here, since third party VFS authors may not
2764 *		limit their error returns to the ones documented here, even
2765 *		though this may result in some programs functioning incorrectly.
2766 *
2767 *		The return codes documented above are those which may currently
2768 *		be returned by HFS from hfs_lookup, not including additional
2769 *		error code which may be propagated from underlying routines.
2770 */
2771errno_t
2772VNOP_LOOKUP(vnode_t dvp, vnode_t *vpp, struct componentname *cnp, vfs_context_t ctx)
2773{
2774	int _err;
2775	struct vnop_lookup_args a;
2776
2777	a.a_desc = &vnop_lookup_desc;
2778	a.a_dvp = dvp;
2779	a.a_vpp = vpp;
2780	a.a_cnp = cnp;
2781	a.a_context = ctx;
2782
2783	_err = (*dvp->v_op[vnop_lookup_desc.vdesc_offset])(&a);
2784	if (_err == 0 && *vpp) {
2785		DTRACE_FSINFO(lookup, vnode_t, *vpp);
2786	}
2787
2788	return (_err);
2789}
2790
2791#if 0
2792struct vnop_compound_open_args {
2793	struct vnodeop_desc *a_desc;
2794	vnode_t a_dvp;
2795	vnode_t *a_vpp;
2796	struct componentname *a_cnp;
2797	int32_t a_flags;
2798	int32_t a_fmode;
2799	struct vnode_attr *a_vap;
2800	vfs_context_t a_context;
2801	void *a_reserved;
2802};
2803#endif /* 0 */
2804
2805int
2806VNOP_COMPOUND_OPEN(vnode_t dvp, vnode_t *vpp, struct nameidata *ndp, int32_t flags, int32_t fmode, uint32_t *statusp, struct vnode_attr *vap, vfs_context_t ctx)
2807{
2808	int _err;
2809	struct vnop_compound_open_args a;
2810	int did_create = 0;
2811	int want_create;
2812	uint32_t tmp_status = 0;
2813	struct componentname *cnp = &ndp->ni_cnd;
2814
2815	want_create = (flags & O_CREAT);
2816
2817	a.a_desc = &vnop_compound_open_desc;
2818	a.a_dvp = dvp;
2819	a.a_vpp = vpp; /* Could be NULL */
2820	a.a_cnp = cnp;
2821	a.a_flags = flags;
2822	a.a_fmode = fmode;
2823	a.a_status = (statusp != NULL) ? statusp : &tmp_status;
2824	a.a_vap = vap;
2825	a.a_context = ctx;
2826	a.a_open_create_authorizer = vn_authorize_create;
2827	a.a_open_existing_authorizer = vn_authorize_open_existing;
2828	a.a_reserved = NULL;
2829
2830	if (dvp == NULLVP) {
2831		panic("No dvp?");
2832	}
2833	if (want_create && !vap) {
2834		panic("Want create, but no vap?");
2835	}
2836	if (!want_create && vap) {
2837		panic("Don't want create, but have a vap?");
2838	}
2839
2840	_err = (*dvp->v_op[vnop_compound_open_desc.vdesc_offset])(&a);
2841	if (want_create) {
2842	       	if (_err == 0 && *vpp) {
2843			DTRACE_FSINFO(compound_open, vnode_t, *vpp);
2844		} else {
2845			DTRACE_FSINFO(compound_open, vnode_t, dvp);
2846		}
2847	} else {
2848		DTRACE_FSINFO(compound_open, vnode_t, *vpp);
2849	}
2850
2851	did_create = (*a.a_status & COMPOUND_OPEN_STATUS_DID_CREATE);
2852
2853	if (did_create && !want_create) {
2854		panic("Filesystem did a create, even though none was requested?");
2855	}
2856
2857	if (did_create) {
2858#if CONFIG_APPLEDOUBLE
2859		if (!NATIVE_XATTR(dvp)) {
2860			/*
2861			 * Remove stale Apple Double file (if any).
2862			 */
2863			xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 0);
2864		}
2865#endif /* CONFIG_APPLEDOUBLE */
2866		/* On create, provide kqueue notification */
2867		post_event_if_success(dvp, _err, NOTE_WRITE);
2868	}
2869
2870	lookup_compound_vnop_post_hook(_err, dvp, *vpp, ndp, did_create);
2871#if 0 /* FSEvents... */
2872	if (*vpp && _err && _err != EKEEPLOOKING) {
2873		vnode_put(*vpp);
2874		*vpp = NULLVP;
2875	}
2876#endif /* 0 */
2877
2878	return (_err);
2879
2880}
2881
2882#if 0
2883struct vnop_create_args {
2884	struct vnodeop_desc *a_desc;
2885	vnode_t a_dvp;
2886	vnode_t *a_vpp;
2887	struct componentname *a_cnp;
2888	struct vnode_attr *a_vap;
2889	vfs_context_t a_context;
2890};
2891#endif /* 0*/
2892errno_t
2893VNOP_CREATE(vnode_t dvp, vnode_t * vpp, struct componentname * cnp, struct vnode_attr * vap, vfs_context_t ctx)
2894{
2895	int _err;
2896	struct vnop_create_args a;
2897
2898	a.a_desc = &vnop_create_desc;
2899	a.a_dvp = dvp;
2900	a.a_vpp = vpp;
2901	a.a_cnp = cnp;
2902	a.a_vap = vap;
2903	a.a_context = ctx;
2904
2905	_err = (*dvp->v_op[vnop_create_desc.vdesc_offset])(&a);
2906	if (_err == 0 && *vpp) {
2907		DTRACE_FSINFO(create, vnode_t, *vpp);
2908	}
2909
2910#if CONFIG_APPLEDOUBLE
2911	if (_err == 0 && !NATIVE_XATTR(dvp)) {
2912		/*
2913		 * Remove stale Apple Double file (if any).
2914		 */
2915		xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 0);
2916	}
2917#endif /* CONFIG_APPLEDOUBLE */
2918
2919	post_event_if_success(dvp, _err, NOTE_WRITE);
2920
2921	return (_err);
2922}
2923
2924#if 0
2925/*
2926 *#
2927 *#% whiteout     dvp     L L L
2928 *#% whiteout     cnp     - - -
2929 *#% whiteout     flag    - - -
2930 *#
2931 */
2932struct vnop_whiteout_args {
2933	struct vnodeop_desc *a_desc;
2934	vnode_t a_dvp;
2935	struct componentname *a_cnp;
2936	int a_flags;
2937	vfs_context_t a_context;
2938};
2939#endif /* 0*/
2940errno_t
2941VNOP_WHITEOUT(__unused vnode_t dvp, __unused struct componentname *cnp,
2942	__unused int flags, __unused vfs_context_t ctx)
2943{
2944	return (ENOTSUP);	// XXX OBSOLETE
2945}
2946
2947#if 0
2948/*
2949 *#
2950 *#% mknod        dvp     L U U
2951 *#% mknod        vpp     - X -
2952 *#
2953 */
2954struct vnop_mknod_args {
2955       struct vnodeop_desc *a_desc;
2956       vnode_t a_dvp;
2957       vnode_t *a_vpp;
2958       struct componentname *a_cnp;
2959       struct vnode_attr *a_vap;
2960       vfs_context_t a_context;
2961};
2962#endif /* 0*/
2963errno_t
2964VNOP_MKNOD(vnode_t dvp, vnode_t * vpp, struct componentname * cnp, struct vnode_attr * vap, vfs_context_t ctx)
2965{
2966
2967       int _err;
2968       struct vnop_mknod_args a;
2969
2970       a.a_desc = &vnop_mknod_desc;
2971       a.a_dvp = dvp;
2972       a.a_vpp = vpp;
2973       a.a_cnp = cnp;
2974       a.a_vap = vap;
2975       a.a_context = ctx;
2976
2977       _err = (*dvp->v_op[vnop_mknod_desc.vdesc_offset])(&a);
2978       if (_err == 0 && *vpp) {
2979		DTRACE_FSINFO(mknod, vnode_t, *vpp);
2980       }
2981
2982       post_event_if_success(dvp, _err, NOTE_WRITE);
2983
2984       return (_err);
2985}
2986
2987#if 0
2988/*
2989 *#
2990 *#% open         vp      L L L
2991 *#
2992 */
2993struct vnop_open_args {
2994	struct vnodeop_desc *a_desc;
2995	vnode_t a_vp;
2996	int a_mode;
2997	vfs_context_t a_context;
2998};
2999#endif /* 0*/
3000errno_t
3001VNOP_OPEN(vnode_t vp, int mode, vfs_context_t ctx)
3002{
3003	int _err;
3004	struct vnop_open_args a;
3005
3006	if (ctx == NULL) {
3007		ctx = vfs_context_current();
3008	}
3009	a.a_desc = &vnop_open_desc;
3010	a.a_vp = vp;
3011	a.a_mode = mode;
3012	a.a_context = ctx;
3013
3014	_err = (*vp->v_op[vnop_open_desc.vdesc_offset])(&a);
3015	DTRACE_FSINFO(open, vnode_t, vp);
3016
3017	return (_err);
3018}
3019
3020#if 0
3021/*
3022 *#
3023 *#% close        vp      U U U
3024 *#
3025 */
3026struct vnop_close_args {
3027	struct vnodeop_desc *a_desc;
3028	vnode_t a_vp;
3029	int a_fflag;
3030	vfs_context_t a_context;
3031};
3032#endif /* 0*/
3033errno_t
3034VNOP_CLOSE(vnode_t vp, int fflag, vfs_context_t ctx)
3035{
3036	int _err;
3037	struct vnop_close_args a;
3038
3039	if (ctx == NULL) {
3040		ctx = vfs_context_current();
3041	}
3042	a.a_desc = &vnop_close_desc;
3043	a.a_vp = vp;
3044	a.a_fflag = fflag;
3045	a.a_context = ctx;
3046
3047	_err = (*vp->v_op[vnop_close_desc.vdesc_offset])(&a);
3048	DTRACE_FSINFO(close, vnode_t, vp);
3049
3050	return (_err);
3051}
3052
3053#if 0
3054/*
3055 *#
3056 *#% access       vp      L L L
3057 *#
3058 */
3059struct vnop_access_args {
3060	struct vnodeop_desc *a_desc;
3061	vnode_t a_vp;
3062	int a_action;
3063	vfs_context_t a_context;
3064};
3065#endif /* 0*/
3066errno_t
3067VNOP_ACCESS(vnode_t vp, int action, vfs_context_t ctx)
3068{
3069	int _err;
3070	struct vnop_access_args a;
3071
3072	if (ctx == NULL) {
3073		ctx = vfs_context_current();
3074	}
3075	a.a_desc = &vnop_access_desc;
3076	a.a_vp = vp;
3077	a.a_action = action;
3078	a.a_context = ctx;
3079
3080	_err = (*vp->v_op[vnop_access_desc.vdesc_offset])(&a);
3081	DTRACE_FSINFO(access, vnode_t, vp);
3082
3083	return (_err);
3084}
3085
3086#if 0
3087/*
3088 *#
3089 *#% getattr      vp      = = =
3090 *#
3091 */
3092struct vnop_getattr_args {
3093	struct vnodeop_desc *a_desc;
3094	vnode_t a_vp;
3095	struct vnode_attr *a_vap;
3096	vfs_context_t a_context;
3097};
3098#endif /* 0*/
3099errno_t
3100VNOP_GETATTR(vnode_t vp, struct vnode_attr * vap, vfs_context_t ctx)
3101{
3102	int _err;
3103	struct vnop_getattr_args a;
3104
3105	a.a_desc = &vnop_getattr_desc;
3106	a.a_vp = vp;
3107	a.a_vap = vap;
3108	a.a_context = ctx;
3109
3110	_err = (*vp->v_op[vnop_getattr_desc.vdesc_offset])(&a);
3111	DTRACE_FSINFO(getattr, vnode_t, vp);
3112
3113	return (_err);
3114}
3115
3116#if 0
3117/*
3118 *#
3119 *#% setattr      vp      L L L
3120 *#
3121 */
3122struct vnop_setattr_args {
3123	struct vnodeop_desc *a_desc;
3124	vnode_t a_vp;
3125	struct vnode_attr *a_vap;
3126	vfs_context_t a_context;
3127};
3128#endif /* 0*/
3129errno_t
3130VNOP_SETATTR(vnode_t vp, struct vnode_attr * vap, vfs_context_t ctx)
3131{
3132	int _err;
3133	struct vnop_setattr_args a;
3134
3135	a.a_desc = &vnop_setattr_desc;
3136	a.a_vp = vp;
3137	a.a_vap = vap;
3138	a.a_context = ctx;
3139
3140	_err = (*vp->v_op[vnop_setattr_desc.vdesc_offset])(&a);
3141	DTRACE_FSINFO(setattr, vnode_t, vp);
3142
3143#if CONFIG_APPLEDOUBLE
3144	/*
3145	 * Shadow uid/gid/mod change to extended attribute file.
3146	 */
3147	if (_err == 0 && !NATIVE_XATTR(vp)) {
3148		struct vnode_attr va;
3149		int change = 0;
3150
3151		VATTR_INIT(&va);
3152		if (VATTR_IS_ACTIVE(vap, va_uid)) {
3153			VATTR_SET(&va, va_uid, vap->va_uid);
3154			change = 1;
3155		}
3156		if (VATTR_IS_ACTIVE(vap, va_gid)) {
3157			VATTR_SET(&va, va_gid, vap->va_gid);
3158			change = 1;
3159		}
3160		if (VATTR_IS_ACTIVE(vap, va_mode)) {
3161			VATTR_SET(&va, va_mode, vap->va_mode);
3162			change = 1;
3163		}
3164		if (change) {
3165		        vnode_t dvp;
3166			const char   *vname;
3167
3168			dvp = vnode_getparent(vp);
3169			vname = vnode_getname(vp);
3170
3171			xattrfile_setattr(dvp, vname, &va, ctx);
3172			if (dvp != NULLVP)
3173			        vnode_put(dvp);
3174			if (vname != NULL)
3175			        vnode_putname(vname);
3176		}
3177	}
3178#endif /* CONFIG_APPLEDOUBLE */
3179
3180	/*
3181	 * If we have changed any of the things about the file that are likely
3182	 * to result in changes to authorization results, blow the vnode auth
3183	 * cache
3184	 */
3185	if (_err == 0 && (
3186			  VATTR_IS_SUPPORTED(vap, va_mode) ||
3187			  VATTR_IS_SUPPORTED(vap, va_uid) ||
3188			  VATTR_IS_SUPPORTED(vap, va_gid) ||
3189			  VATTR_IS_SUPPORTED(vap, va_flags) ||
3190			  VATTR_IS_SUPPORTED(vap, va_acl) ||
3191			  VATTR_IS_SUPPORTED(vap, va_uuuid) ||
3192			  VATTR_IS_SUPPORTED(vap, va_guuid))) {
3193	        vnode_uncache_authorized_action(vp, KAUTH_INVALIDATE_CACHED_RIGHTS);
3194
3195#if NAMEDSTREAMS
3196		if (vfs_authopaque(vp->v_mount) && vnode_hasnamedstreams(vp)) {
3197			vnode_t svp;
3198			if (vnode_getnamedstream(vp, &svp, XATTR_RESOURCEFORK_NAME, NS_OPEN, 0, ctx) == 0) {
3199				vnode_uncache_authorized_action(svp, KAUTH_INVALIDATE_CACHED_RIGHTS);
3200				vnode_put(svp);
3201		 	}
3202		}
3203#endif /* NAMEDSTREAMS */
3204	}
3205
3206
3207	post_event_if_success(vp, _err, NOTE_ATTRIB);
3208
3209	return (_err);
3210}
3211
3212
3213#if 0
3214/*
3215 *#
3216 *#% read         vp      L L L
3217 *#
3218 */
3219struct vnop_read_args {
3220	struct vnodeop_desc *a_desc;
3221	vnode_t a_vp;
3222	struct uio *a_uio;
3223	int a_ioflag;
3224	vfs_context_t a_context;
3225};
3226#endif /* 0*/
3227errno_t
3228VNOP_READ(vnode_t vp, struct uio * uio, int ioflag, vfs_context_t ctx)
3229{
3230	int _err;
3231	struct vnop_read_args a;
3232#if CONFIG_DTRACE
3233	user_ssize_t resid = uio_resid(uio);
3234#endif
3235
3236	if (ctx == NULL) {
3237		return EINVAL;
3238	}
3239
3240	a.a_desc = &vnop_read_desc;
3241	a.a_vp = vp;
3242	a.a_uio = uio;
3243	a.a_ioflag = ioflag;
3244	a.a_context = ctx;
3245
3246	_err = (*vp->v_op[vnop_read_desc.vdesc_offset])(&a);
3247	DTRACE_FSINFO_IO(read,
3248	    vnode_t, vp, user_ssize_t, (resid - uio_resid(uio)));
3249
3250	return (_err);
3251}
3252
3253
3254#if 0
3255/*
3256 *#
3257 *#% write        vp      L L L
3258 *#
3259 */
3260struct vnop_write_args {
3261	struct vnodeop_desc *a_desc;
3262	vnode_t a_vp;
3263	struct uio *a_uio;
3264	int a_ioflag;
3265	vfs_context_t a_context;
3266};
3267#endif /* 0*/
3268errno_t
3269VNOP_WRITE(vnode_t vp, struct uio * uio, int ioflag, vfs_context_t ctx)
3270{
3271	struct vnop_write_args a;
3272	int _err;
3273#if CONFIG_DTRACE
3274	user_ssize_t resid = uio_resid(uio);
3275#endif
3276
3277	if (ctx == NULL) {
3278		return EINVAL;
3279	}
3280
3281	a.a_desc = &vnop_write_desc;
3282	a.a_vp = vp;
3283	a.a_uio = uio;
3284	a.a_ioflag = ioflag;
3285	a.a_context = ctx;
3286
3287	_err = (*vp->v_op[vnop_write_desc.vdesc_offset])(&a);
3288	DTRACE_FSINFO_IO(write,
3289	    vnode_t, vp, user_ssize_t, (resid - uio_resid(uio)));
3290
3291	post_event_if_success(vp, _err, NOTE_WRITE);
3292
3293	return (_err);
3294}
3295
3296
3297#if 0
3298/*
3299 *#
3300 *#% ioctl        vp      U U U
3301 *#
3302 */
3303struct vnop_ioctl_args {
3304	struct vnodeop_desc *a_desc;
3305	vnode_t a_vp;
3306	u_long a_command;
3307	caddr_t a_data;
3308	int a_fflag;
3309	vfs_context_t a_context;
3310};
3311#endif /* 0*/
3312errno_t
3313VNOP_IOCTL(vnode_t vp, u_long command, caddr_t data, int fflag, vfs_context_t ctx)
3314{
3315	int _err;
3316	struct vnop_ioctl_args a;
3317
3318	if (ctx == NULL) {
3319		ctx = vfs_context_current();
3320	}
3321
3322	/*
3323	 * This check should probably have been put in the TTY code instead...
3324	 *
3325	 * We have to be careful about what we assume during startup and shutdown.
3326	 * We have to be able to use the root filesystem's device vnode even when
3327	 * devfs isn't mounted (yet/anymore), so we can't go looking at its mount
3328	 * structure.  If there is no data pointer, it doesn't matter whether
3329	 * the device is 64-bit ready.  Any command (like DKIOCSYNCHRONIZECACHE)
3330	 * which passes NULL for its data pointer can therefore be used during
3331	 * mount or unmount of the root filesystem.
3332	 *
3333	 * Depending on what root filesystems need to do during mount/unmount, we
3334	 * may need to loosen this check again in the future.
3335	 */
3336	if (vfs_context_is64bit(ctx) && !(vnode_ischr(vp) || vnode_isblk(vp))) {
3337		if (data != NULL && !vnode_vfs64bitready(vp)) {
3338			return(ENOTTY);
3339		}
3340	}
3341
3342	a.a_desc = &vnop_ioctl_desc;
3343	a.a_vp = vp;
3344	a.a_command = command;
3345	a.a_data = data;
3346	a.a_fflag = fflag;
3347	a.a_context= ctx;
3348
3349	_err = (*vp->v_op[vnop_ioctl_desc.vdesc_offset])(&a);
3350	DTRACE_FSINFO(ioctl, vnode_t, vp);
3351
3352	return (_err);
3353}
3354
3355
3356#if 0
3357/*
3358 *#
3359 *#% select       vp      U U U
3360 *#
3361 */
3362struct vnop_select_args {
3363	struct vnodeop_desc *a_desc;
3364	vnode_t a_vp;
3365	int a_which;
3366	int a_fflags;
3367	void *a_wql;
3368	vfs_context_t a_context;
3369};
3370#endif /* 0*/
3371errno_t
3372VNOP_SELECT(vnode_t vp, int which , int fflags, void * wql, vfs_context_t ctx)
3373{
3374	int _err;
3375	struct vnop_select_args a;
3376
3377	if (ctx == NULL) {
3378		ctx = vfs_context_current();
3379	}
3380	a.a_desc = &vnop_select_desc;
3381	a.a_vp = vp;
3382	a.a_which = which;
3383	a.a_fflags = fflags;
3384	a.a_context = ctx;
3385	a.a_wql = wql;
3386
3387	_err = (*vp->v_op[vnop_select_desc.vdesc_offset])(&a);
3388	DTRACE_FSINFO(select, vnode_t, vp);
3389
3390	return (_err);
3391}
3392
3393
3394#if 0
3395/*
3396 *#
3397 *#% exchange fvp         L L L
3398 *#% exchange tvp         L L L
3399 *#
3400 */
3401struct vnop_exchange_args {
3402	struct vnodeop_desc *a_desc;
3403	vnode_t a_fvp;
3404        vnode_t a_tvp;
3405        int a_options;
3406	vfs_context_t a_context;
3407};
3408#endif /* 0*/
3409errno_t
3410VNOP_EXCHANGE(vnode_t fvp, vnode_t tvp, int options, vfs_context_t ctx)
3411{
3412	int _err;
3413	struct vnop_exchange_args a;
3414
3415	a.a_desc = &vnop_exchange_desc;
3416	a.a_fvp = fvp;
3417	a.a_tvp = tvp;
3418	a.a_options = options;
3419	a.a_context = ctx;
3420
3421	_err = (*fvp->v_op[vnop_exchange_desc.vdesc_offset])(&a);
3422	DTRACE_FSINFO(exchange, vnode_t, fvp);
3423
3424	/* Don't post NOTE_WRITE because file descriptors follow the data ... */
3425	post_event_if_success(fvp, _err, NOTE_ATTRIB);
3426	post_event_if_success(tvp, _err, NOTE_ATTRIB);
3427
3428	return (_err);
3429}
3430
3431
3432#if 0
3433/*
3434 *#
3435 *#% revoke       vp      U U U
3436 *#
3437 */
3438struct vnop_revoke_args {
3439	struct vnodeop_desc *a_desc;
3440	vnode_t a_vp;
3441	int a_flags;
3442	vfs_context_t a_context;
3443};
3444#endif /* 0*/
3445errno_t
3446VNOP_REVOKE(vnode_t vp, int flags, vfs_context_t ctx)
3447{
3448	struct vnop_revoke_args a;
3449	int _err;
3450
3451	a.a_desc = &vnop_revoke_desc;
3452	a.a_vp = vp;
3453	a.a_flags = flags;
3454	a.a_context = ctx;
3455
3456	_err = (*vp->v_op[vnop_revoke_desc.vdesc_offset])(&a);
3457	DTRACE_FSINFO(revoke, vnode_t, vp);
3458
3459	return (_err);
3460}
3461
3462
3463#if 0
3464/*
3465 *#
3466 *# mmap - vp U U U
3467 *#
3468 */
3469struct vnop_mmap_args {
3470	struct vnodeop_desc *a_desc;
3471	vnode_t a_vp;
3472	int a_fflags;
3473	vfs_context_t a_context;
3474};
3475#endif /* 0*/
3476errno_t
3477VNOP_MMAP(vnode_t vp, int fflags, vfs_context_t ctx)
3478{
3479	int _err;
3480	struct vnop_mmap_args a;
3481
3482	a.a_desc = &vnop_mmap_desc;
3483	a.a_vp = vp;
3484	a.a_fflags = fflags;
3485	a.a_context = ctx;
3486
3487	_err = (*vp->v_op[vnop_mmap_desc.vdesc_offset])(&a);
3488	DTRACE_FSINFO(mmap, vnode_t, vp);
3489
3490	return (_err);
3491}
3492
3493
3494#if 0
3495/*
3496 *#
3497 *# mnomap - vp U U U
3498 *#
3499 */
3500struct vnop_mnomap_args {
3501	struct vnodeop_desc *a_desc;
3502	vnode_t a_vp;
3503	vfs_context_t a_context;
3504};
3505#endif /* 0*/
3506errno_t
3507VNOP_MNOMAP(vnode_t vp, vfs_context_t ctx)
3508{
3509	int _err;
3510	struct vnop_mnomap_args a;
3511
3512	a.a_desc = &vnop_mnomap_desc;
3513	a.a_vp = vp;
3514	a.a_context = ctx;
3515
3516	_err = (*vp->v_op[vnop_mnomap_desc.vdesc_offset])(&a);
3517	DTRACE_FSINFO(mnomap, vnode_t, vp);
3518
3519	return (_err);
3520}
3521
3522
3523#if 0
3524/*
3525 *#
3526 *#% fsync        vp      L L L
3527 *#
3528 */
3529struct vnop_fsync_args {
3530	struct vnodeop_desc *a_desc;
3531	vnode_t a_vp;
3532	int a_waitfor;
3533	vfs_context_t a_context;
3534};
3535#endif /* 0*/
3536errno_t
3537VNOP_FSYNC(vnode_t vp, int waitfor, vfs_context_t ctx)
3538{
3539	struct vnop_fsync_args a;
3540	int _err;
3541
3542	a.a_desc = &vnop_fsync_desc;
3543	a.a_vp = vp;
3544	a.a_waitfor = waitfor;
3545	a.a_context = ctx;
3546
3547	_err = (*vp->v_op[vnop_fsync_desc.vdesc_offset])(&a);
3548	DTRACE_FSINFO(fsync, vnode_t, vp);
3549
3550	return (_err);
3551}
3552
3553
3554#if 0
3555/*
3556 *#
3557 *#% remove       dvp     L U U
3558 *#% remove       vp      L U U
3559 *#
3560 */
3561struct vnop_remove_args {
3562	struct vnodeop_desc *a_desc;
3563	vnode_t a_dvp;
3564	vnode_t a_vp;
3565	struct componentname *a_cnp;
3566	int a_flags;
3567	vfs_context_t a_context;
3568};
3569#endif /* 0*/
3570errno_t
3571VNOP_REMOVE(vnode_t dvp, vnode_t vp, struct componentname * cnp, int flags, vfs_context_t ctx)
3572{
3573	int _err;
3574	struct vnop_remove_args a;
3575
3576	a.a_desc = &vnop_remove_desc;
3577	a.a_dvp = dvp;
3578	a.a_vp = vp;
3579	a.a_cnp = cnp;
3580	a.a_flags = flags;
3581	a.a_context = ctx;
3582
3583	_err = (*dvp->v_op[vnop_remove_desc.vdesc_offset])(&a);
3584	DTRACE_FSINFO(remove, vnode_t, vp);
3585
3586	if (_err == 0) {
3587	        vnode_setneedinactive(vp);
3588#if CONFIG_APPLEDOUBLE
3589		if ( !(NATIVE_XATTR(dvp)) ) {
3590		        /*
3591			 * Remove any associated extended attribute file (._ AppleDouble file).
3592			 */
3593		        xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 1);
3594		}
3595#endif /* CONFIG_APPLEDOUBLE */
3596	}
3597
3598	post_event_if_success(vp, _err, NOTE_DELETE | NOTE_LINK);
3599	post_event_if_success(dvp, _err, NOTE_WRITE);
3600
3601	return (_err);
3602}
3603
3604int
3605VNOP_COMPOUND_REMOVE(vnode_t dvp, vnode_t *vpp, struct nameidata *ndp, int32_t flags, struct vnode_attr *vap, vfs_context_t ctx)
3606{
3607	int _err;
3608	struct vnop_compound_remove_args a;
3609	int no_vp = (*vpp == NULLVP);
3610
3611	a.a_desc = &vnop_compound_remove_desc;
3612	a.a_dvp = dvp;
3613	a.a_vpp = vpp;
3614	a.a_cnp = &ndp->ni_cnd;
3615	a.a_flags = flags;
3616	a.a_vap = vap;
3617	a.a_context = ctx;
3618	a.a_remove_authorizer = vn_authorize_unlink;
3619
3620	_err = (*dvp->v_op[vnop_compound_remove_desc.vdesc_offset])(&a);
3621	if (_err == 0 && *vpp) {
3622		DTRACE_FSINFO(compound_remove, vnode_t, *vpp);
3623	} else {
3624		DTRACE_FSINFO(compound_remove, vnode_t, dvp);
3625	}
3626	if (_err == 0) {
3627	        vnode_setneedinactive(*vpp);
3628#if CONFIG_APPLEDOUBLE
3629		if ( !(NATIVE_XATTR(dvp)) ) {
3630		        /*
3631			 * Remove any associated extended attribute file (._ AppleDouble file).
3632			 */
3633		        xattrfile_remove(dvp, ndp->ni_cnd.cn_nameptr, ctx, 1);
3634		}
3635#endif /* CONFIG_APPLEDOUBLE */
3636	}
3637
3638	post_event_if_success(*vpp, _err, NOTE_DELETE | NOTE_LINK);
3639	post_event_if_success(dvp, _err, NOTE_WRITE);
3640
3641	if (no_vp) {
3642		lookup_compound_vnop_post_hook(_err, dvp, *vpp, ndp, 0);
3643		if (*vpp && _err && _err != EKEEPLOOKING) {
3644			vnode_put(*vpp);
3645			*vpp = NULLVP;
3646		}
3647	}
3648
3649	//printf("VNOP_COMPOUND_REMOVE() returning %d\n", _err);
3650
3651	return (_err);
3652}
3653
3654#if 0
3655/*
3656 *#
3657 *#% link         vp      U U U
3658 *#% link         tdvp    L U U
3659 *#
3660 */
3661struct vnop_link_args {
3662	struct vnodeop_desc *a_desc;
3663	vnode_t a_vp;
3664	vnode_t a_tdvp;
3665	struct componentname *a_cnp;
3666	vfs_context_t a_context;
3667};
3668#endif /* 0*/
3669errno_t
3670VNOP_LINK(vnode_t vp, vnode_t tdvp, struct componentname * cnp, vfs_context_t ctx)
3671{
3672	int _err;
3673	struct vnop_link_args a;
3674
3675#if CONFIG_APPLEDOUBLE
3676	/*
3677	 * For file systems with non-native extended attributes,
3678	 * disallow linking to an existing "._" Apple Double file.
3679	 */
3680	if ( !NATIVE_XATTR(tdvp) && (vp->v_type == VREG)) {
3681		const char   *vname;
3682
3683		vname = vnode_getname(vp);
3684		if (vname != NULL) {
3685			_err = 0;
3686			if (vname[0] == '.' && vname[1] == '_' && vname[2] != '\0') {
3687				_err = EPERM;
3688			}
3689			vnode_putname(vname);
3690			if (_err)
3691				return (_err);
3692		}
3693	}
3694#endif /* CONFIG_APPLEDOUBLE */
3695
3696	a.a_desc = &vnop_link_desc;
3697	a.a_vp = vp;
3698	a.a_tdvp = tdvp;
3699	a.a_cnp = cnp;
3700	a.a_context = ctx;
3701
3702	_err = (*tdvp->v_op[vnop_link_desc.vdesc_offset])(&a);
3703	DTRACE_FSINFO(link, vnode_t, vp);
3704
3705	post_event_if_success(vp, _err, NOTE_LINK);
3706	post_event_if_success(tdvp, _err, NOTE_WRITE);
3707
3708	return (_err);
3709}
3710
3711errno_t
3712vn_rename(struct vnode *fdvp, struct vnode **fvpp, struct componentname *fcnp, struct vnode_attr *fvap,
3713            struct vnode *tdvp, struct vnode **tvpp, struct componentname *tcnp, struct vnode_attr *tvap,
3714            uint32_t flags, vfs_context_t ctx)
3715{
3716	int _err;
3717	struct nameidata *fromnd = NULL;
3718	struct nameidata *tond = NULL;
3719#if CONFIG_APPLEDOUBLE
3720	vnode_t src_attr_vp = NULLVP;
3721	vnode_t dst_attr_vp = NULLVP;
3722	char smallname1[48];
3723	char smallname2[48];
3724	char *xfromname = NULL;
3725	char *xtoname = NULL;
3726#endif /* CONFIG_APPLEDOUBLE */
3727	int batched;
3728	uint32_t tdfflags;	// Target directory file flags
3729
3730	batched = vnode_compound_rename_available(fdvp);
3731
3732	if (!batched) {
3733		if (*fvpp == NULLVP)
3734			panic("Not batched, and no fvp?");
3735	}
3736
3737#if CONFIG_SECLUDED_RENAME
3738	if ((fcnp->cn_flags & CN_SECLUDE_RENAME) &&
3739	    (((*fvpp)->v_mount->mnt_vtable->vfc_vfsflags & VFC_VFSVNOP_SECLUDE_RENAME) == 0)) {
3740	    return ENOTSUP;
3741	}
3742#endif
3743
3744#if CONFIG_APPLEDOUBLE
3745	/*
3746	 * We need to preflight any potential AppleDouble file for the source file
3747	 * before doing the rename operation, since we could potentially be doing
3748	 * this operation on a network filesystem, and would end up duplicating
3749	 * the work.  Also, save the source and destination names.  Skip it if the
3750	 * source has a "._" prefix.
3751	 */
3752
3753	if (!NATIVE_XATTR(fdvp) &&
3754	    !(fcnp->cn_nameptr[0] == '.' && fcnp->cn_nameptr[1] == '_')) {
3755		size_t len;
3756		int error;
3757
3758		/* Get source attribute file name. */
3759		len = fcnp->cn_namelen + 3;
3760		if (len > sizeof(smallname1)) {
3761			MALLOC(xfromname, char *, len, M_TEMP, M_WAITOK);
3762		} else {
3763			xfromname = &smallname1[0];
3764		}
3765		strlcpy(xfromname, "._", min(sizeof smallname1, len));
3766		strncat(xfromname, fcnp->cn_nameptr, fcnp->cn_namelen);
3767		xfromname[len-1] = '\0';
3768
3769		/* Get destination attribute file name. */
3770		len = tcnp->cn_namelen + 3;
3771		if (len > sizeof(smallname2)) {
3772			MALLOC(xtoname, char *, len, M_TEMP, M_WAITOK);
3773		} else {
3774			xtoname = &smallname2[0];
3775		}
3776		strlcpy(xtoname, "._", min(sizeof smallname2, len));
3777		strncat(xtoname, tcnp->cn_nameptr, tcnp->cn_namelen);
3778		xtoname[len-1] = '\0';
3779
3780		/*
3781		 * Look up source attribute file, keep reference on it if exists.
3782		 * Note that we do the namei with the nameiop of RENAME, which is different than
3783		 * in the rename syscall. It's OK if the source file does not exist, since this
3784		 * is only for AppleDouble files.
3785		 */
3786		if (xfromname != NULL) {
3787			MALLOC(fromnd, struct nameidata *, sizeof (struct nameidata), M_TEMP, M_WAITOK);
3788			NDINIT(fromnd, RENAME, OP_RENAME, NOFOLLOW | USEDVP | CN_NBMOUNTLOOK,
3789			       UIO_SYSSPACE, CAST_USER_ADDR_T(xfromname), ctx);
3790			fromnd->ni_dvp = fdvp;
3791			error = namei(fromnd);
3792
3793			/*
3794			 * If there was an error looking up source attribute file,
3795			 * we'll behave as if it didn't exist.
3796			 */
3797
3798			if (error == 0) {
3799				if (fromnd->ni_vp) {
3800					/* src_attr_vp indicates need to call vnode_put / nameidone later */
3801					src_attr_vp = fromnd->ni_vp;
3802
3803					if (fromnd->ni_vp->v_type != VREG) {
3804						src_attr_vp = NULLVP;
3805						vnode_put(fromnd->ni_vp);
3806					}
3807				}
3808				/*
3809				 * Either we got an invalid vnode type (not a regular file) or the namei lookup
3810				 * suppressed ENOENT as a valid error since we're renaming. Either way, we don't
3811				 * have a vnode here, so we drop our namei buffer for the source attribute file
3812				 */
3813				if (src_attr_vp == NULLVP) {
3814					nameidone(fromnd);
3815				}
3816			}
3817		}
3818	}
3819#endif /* CONFIG_APPLEDOUBLE */
3820
3821	if (batched) {
3822		_err = VNOP_COMPOUND_RENAME(fdvp, fvpp, fcnp, fvap, tdvp, tvpp, tcnp, tvap, flags, ctx);
3823		if (_err != 0) {
3824			printf("VNOP_COMPOUND_RENAME() returned %d\n", _err);
3825		}
3826	} else {
3827		_err = VNOP_RENAME(fdvp, *fvpp, fcnp, tdvp, *tvpp, tcnp, ctx);
3828	}
3829#if CONFIG_MACF
3830	if (_err == 0) {
3831		mac_vnode_notify_rename(ctx, *fvpp, tdvp, tcnp);
3832	}
3833#endif
3834
3835	/*
3836	 * If moved to a new directory that is restricted,
3837	 * set the restricted flag on the item moved.
3838	 */
3839	if (_err == 0) {
3840		_err = vnode_flags(tdvp, &tdfflags, ctx);
3841		if (_err == 0 && (tdfflags & SF_RESTRICTED)) {
3842			uint32_t fflags;
3843			_err = vnode_flags(*fvpp, &fflags, ctx);
3844			if (_err == 0 && !(fflags & SF_RESTRICTED)) {
3845				struct vnode_attr va;
3846				VATTR_INIT(&va);
3847				VATTR_SET(&va, va_flags, fflags | SF_RESTRICTED);
3848				_err = vnode_setattr(*fvpp, &va, ctx);
3849			}
3850		}
3851	}
3852
3853#if CONFIG_APPLEDOUBLE
3854	/*
3855	 * Rename any associated extended attribute file (._ AppleDouble file).
3856	 */
3857	if (_err == 0 && !NATIVE_XATTR(fdvp) && xfromname != NULL) {
3858		int error = 0;
3859
3860		/*
3861		 * Get destination attribute file vnode.
3862		 * Note that tdvp already has an iocount reference. Make sure to check that we
3863		 * get a valid vnode from namei.
3864		 */
3865		MALLOC(tond, struct nameidata *, sizeof(struct nameidata), M_TEMP, M_WAITOK);
3866		NDINIT(tond, RENAME, OP_RENAME,
3867		       NOCACHE | NOFOLLOW | USEDVP | CN_NBMOUNTLOOK, UIO_SYSSPACE,
3868		       CAST_USER_ADDR_T(xtoname), ctx);
3869		tond->ni_dvp = tdvp;
3870		error = namei(tond);
3871
3872		if (error)
3873			goto ad_error;
3874
3875		if (tond->ni_vp) {
3876			dst_attr_vp = tond->ni_vp;
3877		}
3878
3879		if (src_attr_vp) {
3880			const char *old_name = src_attr_vp->v_name;
3881			vnode_t old_parent = src_attr_vp->v_parent;
3882
3883			if (batched) {
3884				error = VNOP_COMPOUND_RENAME(fdvp, &src_attr_vp, &fromnd->ni_cnd, NULL,
3885						tdvp, &dst_attr_vp, &tond->ni_cnd, NULL,
3886						0, ctx);
3887			} else {
3888				error = VNOP_RENAME(fdvp, src_attr_vp, &fromnd->ni_cnd,
3889						tdvp, dst_attr_vp, &tond->ni_cnd, ctx);
3890			}
3891
3892			if (error == 0 && old_name == src_attr_vp->v_name &&
3893					old_parent == src_attr_vp->v_parent) {
3894				int update_flags = VNODE_UPDATE_NAME;
3895
3896				if (fdvp != tdvp)
3897					update_flags |= VNODE_UPDATE_PARENT;
3898
3899				if ((src_attr_vp->v_mount->mnt_vtable->vfc_vfsflags & VFC_VFSVNOP_NOUPDATEID_RENAME) == 0) {
3900					vnode_update_identity(src_attr_vp, tdvp,
3901						tond->ni_cnd.cn_nameptr,
3902						tond->ni_cnd.cn_namelen,
3903						tond->ni_cnd.cn_hash,
3904						update_flags);
3905				}
3906			}
3907
3908			/* kevent notifications for moving resource files
3909			 * _err is zero if we're here, so no need to notify directories, code
3910			 * below will do that.  only need to post the rename on the source and
3911			 * possibly a delete on the dest
3912			 */
3913			post_event_if_success(src_attr_vp, error, NOTE_RENAME);
3914			if (dst_attr_vp) {
3915				post_event_if_success(dst_attr_vp, error, NOTE_DELETE);
3916			}
3917
3918		} else if (dst_attr_vp) {
3919			/*
3920			 * Just delete destination attribute file vnode if it exists, since
3921			 * we didn't have a source attribute file.
3922			 * Note that tdvp already has an iocount reference.
3923			 */
3924
3925			struct vnop_remove_args args;
3926
3927			args.a_desc    = &vnop_remove_desc;
3928			args.a_dvp     = tdvp;
3929			args.a_vp      = dst_attr_vp;
3930			args.a_cnp     = &tond->ni_cnd;
3931			args.a_context = ctx;
3932
3933			if (error == 0) {
3934				error = (*tdvp->v_op[vnop_remove_desc.vdesc_offset])(&args);
3935
3936				if (error == 0)
3937					vnode_setneedinactive(dst_attr_vp);
3938			}
3939
3940			/* kevent notification for deleting the destination's attribute file
3941			 * if it existed.  Only need to post the delete on the destination, since
3942			 * the code below will handle the directories.
3943			 */
3944			post_event_if_success(dst_attr_vp, error, NOTE_DELETE);
3945		}
3946	}
3947ad_error:
3948	if (src_attr_vp) {
3949		vnode_put(src_attr_vp);
3950		nameidone(fromnd);
3951	}
3952	if (dst_attr_vp) {
3953		vnode_put(dst_attr_vp);
3954		nameidone(tond);
3955	}
3956	if (xfromname && xfromname != &smallname1[0]) {
3957		FREE(xfromname, M_TEMP);
3958	}
3959	if (xtoname && xtoname != &smallname2[0]) {
3960		FREE(xtoname, M_TEMP);
3961	}
3962#endif /* CONFIG_APPLEDOUBLE */
3963	if (fromnd) {
3964		FREE(fromnd, M_TEMP);
3965	}
3966	if (tond) {
3967		FREE(tond, M_TEMP);
3968	}
3969	return _err;
3970}
3971
3972
3973#if 0
3974/*
3975 *#
3976 *#% rename       fdvp    U U U
3977 *#% rename       fvp     U U U
3978 *#% rename       tdvp    L U U
3979 *#% rename       tvp     X U U
3980 *#
3981 */
3982struct vnop_rename_args {
3983	struct vnodeop_desc *a_desc;
3984	vnode_t a_fdvp;
3985	vnode_t a_fvp;
3986	struct componentname *a_fcnp;
3987	vnode_t a_tdvp;
3988	vnode_t a_tvp;
3989	struct componentname *a_tcnp;
3990	vfs_context_t a_context;
3991};
3992#endif /* 0*/
3993errno_t
3994VNOP_RENAME(struct vnode *fdvp, struct vnode *fvp, struct componentname *fcnp,
3995            struct vnode *tdvp, struct vnode *tvp, struct componentname *tcnp,
3996            vfs_context_t ctx)
3997{
3998	int _err = 0;
3999	int events;
4000	struct vnop_rename_args a;
4001
4002	a.a_desc = &vnop_rename_desc;
4003	a.a_fdvp = fdvp;
4004	a.a_fvp = fvp;
4005	a.a_fcnp = fcnp;
4006	a.a_tdvp = tdvp;
4007	a.a_tvp = tvp;
4008	a.a_tcnp = tcnp;
4009	a.a_context = ctx;
4010
4011	/* do the rename of the main file. */
4012	_err = (*fdvp->v_op[vnop_rename_desc.vdesc_offset])(&a);
4013	DTRACE_FSINFO(rename, vnode_t, fdvp);
4014
4015	if (_err == 0) {
4016		if (tvp && tvp != fvp)
4017		        vnode_setneedinactive(tvp);
4018	}
4019
4020	/* Wrote at least one directory.  If transplanted a dir, also changed link counts */
4021	if (_err == 0) {
4022		events = NOTE_WRITE;
4023		if (vnode_isdir(fvp)) {
4024			/* Link count on dir changed only if we are moving a dir and...
4025			 * 	--Moved to new dir, not overwriting there
4026			 * 	--Kept in same dir and DID overwrite
4027			 */
4028			if (((fdvp != tdvp) && (!tvp)) || ((fdvp == tdvp) && (tvp))) {
4029				events |= NOTE_LINK;
4030			}
4031		}
4032
4033		lock_vnode_and_post(fdvp, events);
4034		if (fdvp != tdvp) {
4035			lock_vnode_and_post(tdvp,  events);
4036		}
4037
4038		/* If you're replacing the target, post a deletion for it */
4039		if (tvp)
4040		{
4041			lock_vnode_and_post(tvp, NOTE_DELETE);
4042		}
4043
4044		lock_vnode_and_post(fvp, NOTE_RENAME);
4045	}
4046
4047	return (_err);
4048}
4049
4050int
4051VNOP_COMPOUND_RENAME(
4052		struct vnode *fdvp,  struct vnode **fvpp,  struct componentname *fcnp, struct vnode_attr *fvap,
4053             	struct vnode *tdvp,  struct vnode **tvpp,  struct componentname *tcnp, struct vnode_attr *tvap,
4054	     	uint32_t flags, vfs_context_t ctx)
4055{
4056	int _err = 0;
4057	int events;
4058	struct vnop_compound_rename_args a;
4059	int no_fvp, no_tvp;
4060
4061	no_fvp = (*fvpp) == NULLVP;
4062	no_tvp = (*tvpp) == NULLVP;
4063
4064	a.a_desc = &vnop_compound_rename_desc;
4065
4066	a.a_fdvp = fdvp;
4067	a.a_fvpp = fvpp;
4068	a.a_fcnp = fcnp;
4069	a.a_fvap = fvap;
4070
4071	a.a_tdvp = tdvp;
4072	a.a_tvpp = tvpp;
4073	a.a_tcnp = tcnp;
4074	a.a_tvap = tvap;
4075
4076	a.a_flags = flags;
4077	a.a_context = ctx;
4078	a.a_rename_authorizer = vn_authorize_rename;
4079	a.a_reserved = NULL;
4080
4081	/* do the rename of the main file. */
4082	_err = (*fdvp->v_op[vnop_compound_rename_desc.vdesc_offset])(&a);
4083	DTRACE_FSINFO(compound_rename, vnode_t, fdvp);
4084
4085	if (_err == 0) {
4086		if (*tvpp && *tvpp != *fvpp)
4087		        vnode_setneedinactive(*tvpp);
4088	}
4089
4090	/* Wrote at least one directory.  If transplanted a dir, also changed link counts */
4091	if (_err == 0 && *fvpp != *tvpp) {
4092		if (!*fvpp) {
4093			panic("No fvpp after compound rename?");
4094		}
4095
4096		events = NOTE_WRITE;
4097		if (vnode_isdir(*fvpp)) {
4098			/* Link count on dir changed only if we are moving a dir and...
4099			 * 	--Moved to new dir, not overwriting there
4100			 * 	--Kept in same dir and DID overwrite
4101			 */
4102			if (((fdvp != tdvp) && (!*tvpp)) || ((fdvp == tdvp) && (*tvpp))) {
4103				events |= NOTE_LINK;
4104			}
4105		}
4106
4107		lock_vnode_and_post(fdvp, events);
4108		if (fdvp != tdvp) {
4109			lock_vnode_and_post(tdvp,  events);
4110		}
4111
4112		/* If you're replacing the target, post a deletion for it */
4113		if (*tvpp)
4114		{
4115			lock_vnode_and_post(*tvpp, NOTE_DELETE);
4116		}
4117
4118		lock_vnode_and_post(*fvpp, NOTE_RENAME);
4119	}
4120
4121	if (no_fvp) {
4122		lookup_compound_vnop_post_hook(_err, fdvp, *fvpp, fcnp->cn_ndp, 0);
4123	}
4124	if (no_tvp && *tvpp != NULLVP) {
4125		lookup_compound_vnop_post_hook(_err, tdvp, *tvpp, tcnp->cn_ndp, 0);
4126	}
4127
4128	if (_err && _err != EKEEPLOOKING) {
4129		if (*fvpp) {
4130			vnode_put(*fvpp);
4131			*fvpp = NULLVP;
4132		}
4133		if (*tvpp) {
4134			vnode_put(*tvpp);
4135			*tvpp = NULLVP;
4136		}
4137	}
4138
4139	return (_err);
4140}
4141
4142int
4143vn_mkdir(struct vnode *dvp, struct vnode **vpp, struct nameidata *ndp,
4144           struct vnode_attr *vap, vfs_context_t ctx)
4145{
4146	if (ndp->ni_cnd.cn_nameiop != CREATE) {
4147		panic("Non-CREATE nameiop in vn_mkdir()?");
4148	}
4149
4150	if (vnode_compound_mkdir_available(dvp)) {
4151		return VNOP_COMPOUND_MKDIR(dvp, vpp, ndp, vap, ctx);
4152	} else {
4153		return VNOP_MKDIR(dvp, vpp, &ndp->ni_cnd, vap, ctx);
4154	}
4155}
4156
4157#if 0
4158/*
4159 *#
4160 *#% mkdir        dvp     L U U
4161 *#% mkdir        vpp     - L -
4162 *#
4163 */
4164struct vnop_mkdir_args {
4165       struct vnodeop_desc *a_desc;
4166       vnode_t a_dvp;
4167       vnode_t *a_vpp;
4168       struct componentname *a_cnp;
4169       struct vnode_attr *a_vap;
4170       vfs_context_t a_context;
4171};
4172#endif /* 0*/
4173errno_t
4174VNOP_MKDIR(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp,
4175           struct vnode_attr *vap, vfs_context_t ctx)
4176{
4177       int _err;
4178       struct vnop_mkdir_args a;
4179
4180       a.a_desc = &vnop_mkdir_desc;
4181       a.a_dvp = dvp;
4182       a.a_vpp = vpp;
4183       a.a_cnp = cnp;
4184       a.a_vap = vap;
4185       a.a_context = ctx;
4186
4187       _err = (*dvp->v_op[vnop_mkdir_desc.vdesc_offset])(&a);
4188	if (_err == 0 && *vpp) {
4189		DTRACE_FSINFO(mkdir, vnode_t, *vpp);
4190	}
4191#if CONFIG_APPLEDOUBLE
4192	if (_err == 0 && !NATIVE_XATTR(dvp)) {
4193		/*
4194		 * Remove stale Apple Double file (if any).
4195		 */
4196		xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 0);
4197	}
4198#endif /* CONFIG_APPLEDOUBLE */
4199
4200       post_event_if_success(dvp, _err, NOTE_LINK | NOTE_WRITE);
4201
4202       return (_err);
4203}
4204
4205int
4206VNOP_COMPOUND_MKDIR(struct vnode *dvp, struct vnode **vpp, struct nameidata *ndp,
4207           struct vnode_attr *vap, vfs_context_t ctx)
4208{
4209       int _err;
4210       struct vnop_compound_mkdir_args a;
4211
4212       a.a_desc = &vnop_compound_mkdir_desc;
4213       a.a_dvp = dvp;
4214       a.a_vpp = vpp;
4215       a.a_cnp = &ndp->ni_cnd;
4216       a.a_vap = vap;
4217       a.a_flags = 0;
4218       a.a_context = ctx;
4219#if 0
4220       a.a_mkdir_authorizer = vn_authorize_mkdir;
4221#endif /* 0 */
4222       a.a_reserved = NULL;
4223
4224       _err = (*dvp->v_op[vnop_compound_mkdir_desc.vdesc_offset])(&a);
4225	if (_err == 0 && *vpp) {
4226		DTRACE_FSINFO(compound_mkdir, vnode_t, *vpp);
4227	}
4228#if CONFIG_APPLEDOUBLE
4229	if (_err == 0 && !NATIVE_XATTR(dvp)) {
4230		/*
4231		 * Remove stale Apple Double file (if any).
4232		 */
4233		xattrfile_remove(dvp, ndp->ni_cnd.cn_nameptr, ctx, 0);
4234	}
4235#endif /* CONFIG_APPLEDOUBLE */
4236
4237	post_event_if_success(dvp, _err, NOTE_LINK | NOTE_WRITE);
4238
4239	lookup_compound_vnop_post_hook(_err, dvp, *vpp, ndp, (_err == 0));
4240	if (*vpp && _err && _err != EKEEPLOOKING) {
4241		vnode_put(*vpp);
4242		*vpp = NULLVP;
4243	}
4244
4245	return (_err);
4246}
4247
4248int
4249vn_rmdir(vnode_t dvp, vnode_t *vpp, struct nameidata *ndp, struct vnode_attr *vap, vfs_context_t ctx)
4250{
4251	if (vnode_compound_rmdir_available(dvp)) {
4252		return VNOP_COMPOUND_RMDIR(dvp, vpp, ndp, vap, ctx);
4253	} else {
4254		if (*vpp == NULLVP) {
4255			panic("NULL vp, but not a compound VNOP?");
4256		}
4257		if (vap != NULL) {
4258			panic("Non-NULL vap, but not a compound VNOP?");
4259		}
4260		return VNOP_RMDIR(dvp, *vpp, &ndp->ni_cnd, ctx);
4261	}
4262}
4263
4264#if 0
4265/*
4266 *#
4267 *#% rmdir        dvp     L U U
4268 *#% rmdir        vp      L U U
4269 *#
4270 */
4271struct vnop_rmdir_args {
4272	struct vnodeop_desc *a_desc;
4273	vnode_t a_dvp;
4274	vnode_t a_vp;
4275	struct componentname *a_cnp;
4276	vfs_context_t a_context;
4277};
4278
4279#endif /* 0*/
4280errno_t
4281VNOP_RMDIR(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, vfs_context_t ctx)
4282{
4283	int _err;
4284	struct vnop_rmdir_args a;
4285
4286	a.a_desc = &vnop_rmdir_desc;
4287	a.a_dvp = dvp;
4288	a.a_vp = vp;
4289	a.a_cnp = cnp;
4290	a.a_context = ctx;
4291
4292	_err = (*vp->v_op[vnop_rmdir_desc.vdesc_offset])(&a);
4293	DTRACE_FSINFO(rmdir, vnode_t, vp);
4294
4295	if (_err == 0) {
4296	        vnode_setneedinactive(vp);
4297#if CONFIG_APPLEDOUBLE
4298		if ( !(NATIVE_XATTR(dvp)) ) {
4299		        /*
4300			 * Remove any associated extended attribute file (._ AppleDouble file).
4301			 */
4302		        xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 1);
4303		}
4304#endif
4305	}
4306
4307	/* If you delete a dir, it loses its "." reference --> NOTE_LINK */
4308	post_event_if_success(vp, _err, NOTE_DELETE | NOTE_LINK);
4309	post_event_if_success(dvp, _err, NOTE_LINK | NOTE_WRITE);
4310
4311	return (_err);
4312}
4313
4314int
4315VNOP_COMPOUND_RMDIR(struct vnode *dvp, struct vnode **vpp, struct nameidata *ndp,
4316           struct vnode_attr *vap, vfs_context_t ctx)
4317{
4318       int _err;
4319       struct vnop_compound_rmdir_args a;
4320       int no_vp;
4321
4322       a.a_desc = &vnop_mkdir_desc;
4323       a.a_dvp = dvp;
4324       a.a_vpp = vpp;
4325       a.a_cnp = &ndp->ni_cnd;
4326       a.a_vap = vap;
4327       a.a_flags = 0;
4328       a.a_context = ctx;
4329       a.a_rmdir_authorizer = vn_authorize_rmdir;
4330       a.a_reserved = NULL;
4331
4332       no_vp = (*vpp == NULLVP);
4333
4334       _err = (*dvp->v_op[vnop_compound_rmdir_desc.vdesc_offset])(&a);
4335	if (_err == 0 && *vpp) {
4336		DTRACE_FSINFO(compound_rmdir, vnode_t, *vpp);
4337	}
4338#if CONFIG_APPLEDOUBLE
4339	if (_err == 0 && !NATIVE_XATTR(dvp)) {
4340		/*
4341		 * Remove stale Apple Double file (if any).
4342		 */
4343		xattrfile_remove(dvp, ndp->ni_cnd.cn_nameptr, ctx, 0);
4344	}
4345#endif
4346
4347	if (*vpp) {
4348		post_event_if_success(*vpp, _err, NOTE_DELETE | NOTE_LINK);
4349	}
4350	post_event_if_success(dvp, _err, NOTE_LINK | NOTE_WRITE);
4351
4352       if (no_vp) {
4353	       lookup_compound_vnop_post_hook(_err, dvp, *vpp, ndp, 0);
4354
4355#if 0 /* Removing orphaned ._ files requires a vp.... */
4356	       if (*vpp && _err && _err != EKEEPLOOKING) {
4357		       vnode_put(*vpp);
4358		       *vpp = NULLVP;
4359	       }
4360#endif  /* 0 */
4361       }
4362
4363       return (_err);
4364}
4365
4366#if CONFIG_APPLEDOUBLE
4367/*
4368 * Remove a ._ AppleDouble file
4369 */
4370#define AD_STALE_SECS  (180)
4371static void
4372xattrfile_remove(vnode_t dvp, const char * basename, vfs_context_t ctx, int force)
4373{
4374	vnode_t xvp;
4375	struct nameidata nd;
4376	char smallname[64];
4377	char *filename = NULL;
4378	size_t len;
4379
4380	if ((basename == NULL) || (basename[0] == '\0') ||
4381	    (basename[0] == '.' && basename[1] == '_')) {
4382		return;
4383	}
4384	filename = &smallname[0];
4385	len = snprintf(filename, sizeof(smallname), "._%s", basename);
4386	if (len >= sizeof(smallname)) {
4387		len++;  /* snprintf result doesn't include '\0' */
4388		MALLOC(filename, char *, len, M_TEMP, M_WAITOK);
4389		len = snprintf(filename, len, "._%s", basename);
4390	}
4391	NDINIT(&nd, DELETE, OP_UNLINK, WANTPARENT | LOCKLEAF | NOFOLLOW | USEDVP, UIO_SYSSPACE,
4392	       CAST_USER_ADDR_T(filename), ctx);
4393	nd.ni_dvp = dvp;
4394	if (namei(&nd) != 0)
4395		goto out2;
4396
4397	xvp = nd.ni_vp;
4398	nameidone(&nd);
4399	if (xvp->v_type != VREG)
4400		goto out1;
4401
4402	/*
4403	 * When creating a new object and a "._" file already
4404	 * exists, check to see if its a stale "._" file.
4405	 *
4406	 */
4407	if (!force) {
4408		struct vnode_attr va;
4409
4410		VATTR_INIT(&va);
4411		VATTR_WANTED(&va, va_data_size);
4412		VATTR_WANTED(&va, va_modify_time);
4413		if (VNOP_GETATTR(xvp, &va, ctx) == 0  &&
4414		    VATTR_IS_SUPPORTED(&va, va_data_size)  &&
4415		    VATTR_IS_SUPPORTED(&va, va_modify_time)  &&
4416		    va.va_data_size != 0) {
4417			struct timeval tv;
4418
4419			microtime(&tv);
4420			if ((tv.tv_sec > va.va_modify_time.tv_sec) &&
4421			    (tv.tv_sec - va.va_modify_time.tv_sec) > AD_STALE_SECS) {
4422				force = 1;  /* must be stale */
4423			}
4424		}
4425	}
4426	if (force) {
4427		int  error;
4428
4429		error = VNOP_REMOVE(dvp, xvp, &nd.ni_cnd, 0, ctx);
4430		if (error == 0)
4431			vnode_setneedinactive(xvp);
4432
4433		post_event_if_success(xvp, error, NOTE_DELETE);
4434		post_event_if_success(dvp, error, NOTE_WRITE);
4435	}
4436
4437out1:
4438	vnode_put(dvp);
4439	vnode_put(xvp);
4440out2:
4441	if (filename && filename != &smallname[0]) {
4442		FREE(filename, M_TEMP);
4443	}
4444}
4445
4446/*
4447 * Shadow uid/gid/mod to a ._ AppleDouble file
4448 */
4449static void
4450xattrfile_setattr(vnode_t dvp, const char * basename, struct vnode_attr * vap,
4451                  vfs_context_t ctx)
4452{
4453	vnode_t xvp;
4454	struct nameidata nd;
4455	char smallname[64];
4456	char *filename = NULL;
4457	size_t len;
4458
4459	if ((dvp == NULLVP) ||
4460	    (basename == NULL) || (basename[0] == '\0') ||
4461	    (basename[0] == '.' && basename[1] == '_')) {
4462		return;
4463	}
4464	filename = &smallname[0];
4465	len = snprintf(filename, sizeof(smallname), "._%s", basename);
4466	if (len >= sizeof(smallname)) {
4467		len++;  /* snprintf result doesn't include '\0' */
4468		MALLOC(filename, char *, len, M_TEMP, M_WAITOK);
4469		len = snprintf(filename, len, "._%s", basename);
4470	}
4471	NDINIT(&nd, LOOKUP, OP_SETATTR, NOFOLLOW | USEDVP, UIO_SYSSPACE,
4472	       CAST_USER_ADDR_T(filename), ctx);
4473	nd.ni_dvp = dvp;
4474	if (namei(&nd) != 0)
4475		goto out2;
4476
4477	xvp = nd.ni_vp;
4478	nameidone(&nd);
4479
4480	if (xvp->v_type == VREG) {
4481		struct vnop_setattr_args a;
4482
4483		a.a_desc = &vnop_setattr_desc;
4484		a.a_vp = xvp;
4485		a.a_vap = vap;
4486		a.a_context = ctx;
4487
4488		(void) (*xvp->v_op[vnop_setattr_desc.vdesc_offset])(&a);
4489	}
4490
4491	vnode_put(xvp);
4492out2:
4493	if (filename && filename != &smallname[0]) {
4494		FREE(filename, M_TEMP);
4495	}
4496}
4497#endif /* CONFIG_APPLEDOUBLE */
4498
4499 #if 0
4500/*
4501 *#
4502 *#% symlink      dvp     L U U
4503 *#% symlink      vpp     - U -
4504 *#
4505 */
4506struct vnop_symlink_args {
4507       struct vnodeop_desc *a_desc;
4508       vnode_t a_dvp;
4509       vnode_t *a_vpp;
4510       struct componentname *a_cnp;
4511       struct vnode_attr *a_vap;
4512       char *a_target;
4513       vfs_context_t a_context;
4514};
4515
4516#endif /* 0*/
4517errno_t
4518VNOP_SYMLINK(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp,
4519             struct vnode_attr *vap, char *target, vfs_context_t ctx)
4520{
4521       int _err;
4522       struct vnop_symlink_args a;
4523
4524       a.a_desc = &vnop_symlink_desc;
4525       a.a_dvp = dvp;
4526       a.a_vpp = vpp;
4527       a.a_cnp = cnp;
4528       a.a_vap = vap;
4529       a.a_target = target;
4530       a.a_context = ctx;
4531
4532       _err = (*dvp->v_op[vnop_symlink_desc.vdesc_offset])(&a);
4533	DTRACE_FSINFO(symlink, vnode_t, dvp);
4534#if CONFIG_APPLEDOUBLE
4535	if (_err == 0 && !NATIVE_XATTR(dvp)) {
4536		/*
4537		 * Remove stale Apple Double file (if any).  Posts its own knotes
4538		 */
4539		xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 0);
4540	}
4541#endif /* CONFIG_APPLEDOUBLE */
4542
4543	post_event_if_success(dvp, _err, NOTE_WRITE);
4544
4545	return (_err);
4546}
4547
4548#if 0
4549/*
4550 *#
4551 *#% readdir      vp      L L L
4552 *#
4553 */
4554struct vnop_readdir_args {
4555	struct vnodeop_desc *a_desc;
4556	vnode_t a_vp;
4557	struct uio *a_uio;
4558	int a_flags;
4559	int *a_eofflag;
4560	int *a_numdirent;
4561	vfs_context_t a_context;
4562};
4563
4564#endif /* 0*/
4565errno_t
4566VNOP_READDIR(struct vnode *vp, struct uio *uio, int flags, int *eofflag,
4567             int *numdirent, vfs_context_t ctx)
4568{
4569	int _err;
4570	struct vnop_readdir_args a;
4571#if CONFIG_DTRACE
4572	user_ssize_t resid = uio_resid(uio);
4573#endif
4574
4575	a.a_desc = &vnop_readdir_desc;
4576	a.a_vp = vp;
4577	a.a_uio = uio;
4578	a.a_flags = flags;
4579	a.a_eofflag = eofflag;
4580	a.a_numdirent = numdirent;
4581	a.a_context = ctx;
4582
4583	_err = (*vp->v_op[vnop_readdir_desc.vdesc_offset])(&a);
4584	DTRACE_FSINFO_IO(readdir,
4585	    vnode_t, vp, user_ssize_t, (resid - uio_resid(uio)));
4586
4587	return (_err);
4588}
4589
4590#if 0
4591/*
4592 *#
4593 *#% readdirattr  vp      L L L
4594 *#
4595 */
4596struct vnop_readdirattr_args {
4597	struct vnodeop_desc *a_desc;
4598	vnode_t a_vp;
4599	struct attrlist *a_alist;
4600	struct uio *a_uio;
4601	uint32_t a_maxcount;
4602	uint32_t a_options;
4603	uint32_t *a_newstate;
4604	int *a_eofflag;
4605	uint32_t *a_actualcount;
4606	vfs_context_t a_context;
4607};
4608
4609#endif /* 0*/
4610errno_t
4611VNOP_READDIRATTR(struct vnode *vp, struct attrlist *alist, struct uio *uio, uint32_t maxcount,
4612                 uint32_t options, uint32_t *newstate, int *eofflag, uint32_t *actualcount, vfs_context_t ctx)
4613{
4614	int _err;
4615	struct vnop_readdirattr_args a;
4616#if CONFIG_DTRACE
4617	user_ssize_t resid = uio_resid(uio);
4618#endif
4619
4620	a.a_desc = &vnop_readdirattr_desc;
4621	a.a_vp = vp;
4622	a.a_alist = alist;
4623	a.a_uio = uio;
4624	a.a_maxcount = maxcount;
4625	a.a_options = options;
4626	a.a_newstate = newstate;
4627	a.a_eofflag = eofflag;
4628	a.a_actualcount = actualcount;
4629	a.a_context = ctx;
4630
4631	_err = (*vp->v_op[vnop_readdirattr_desc.vdesc_offset])(&a);
4632	DTRACE_FSINFO_IO(readdirattr,
4633	    vnode_t, vp, user_ssize_t, (resid - uio_resid(uio)));
4634
4635	return (_err);
4636}
4637
4638#if 0
4639struct vnop_getttrlistbulk_args {
4640	struct vnodeop_desc *a_desc;
4641	vnode_t a_vp;
4642	struct attrlist *a_alist;
4643	struct vnode_attr *a_vap;
4644	struct uio *a_uio;
4645	void *a_private
4646	uint64_t a_options;
4647	int *a_eofflag;
4648	uint32_t *a_actualcount;
4649	vfs_context_t a_context;
4650};
4651#endif /* 0*/
4652errno_t
4653VNOP_GETATTRLISTBULK(struct vnode *vp, struct attrlist *alist,
4654    struct vnode_attr *vap, struct uio *uio, void *private, uint64_t options,
4655    int32_t *eofflag, int32_t *actualcount, vfs_context_t ctx)
4656{
4657	int _err;
4658	struct vnop_getattrlistbulk_args a;
4659#if CONFIG_DTRACE
4660	user_ssize_t resid = uio_resid(uio);
4661#endif
4662
4663	a.a_desc = &vnop_getattrlistbulk_desc;
4664	a.a_vp = vp;
4665	a.a_alist = alist;
4666	a.a_vap = vap;
4667	a.a_uio = uio;
4668	a.a_private = private;
4669	a.a_options = options;
4670	a.a_eofflag = eofflag;
4671	a.a_actualcount = actualcount;
4672	a.a_context = ctx;
4673
4674	_err = (*vp->v_op[vnop_getattrlistbulk_desc.vdesc_offset])(&a);
4675	DTRACE_FSINFO_IO(getattrlistbulk,
4676	    vnode_t, vp, user_ssize_t, (resid - uio_resid(uio)));
4677
4678	return (_err);
4679}
4680
4681#if 0
4682/*
4683 *#
4684 *#% readlink     vp      L L L
4685 *#
4686 */
4687struct vnop_readlink_args {
4688	struct vnodeop_desc *a_desc;
4689	vnode_t a_vp;
4690	struct uio *a_uio;
4691	vfs_context_t a_context;
4692};
4693#endif /* 0 */
4694
4695/*
4696 * Returns:	0			Success
4697 *		lock_fsnode:ENOENT	No such file or directory [only for VFS
4698 *					 that is not thread safe & vnode is
4699 *					 currently being/has been terminated]
4700 *		<vfs_readlink>:EINVAL
4701 *		<vfs_readlink>:???
4702 *
4703 * Note:	The return codes from the underlying VFS's readlink routine
4704 *		can't be fully enumerated here, since third party VFS authors
4705 *		may not limit their error returns to the ones documented here,
4706 *		even though this may result in some programs functioning
4707 *		incorrectly.
4708 *
4709 *		The return codes documented above are those which may currently
4710 *		be returned by HFS from hfs_vnop_readlink, not including
4711 *		additional error code which may be propagated from underlying
4712 *		routines.
4713 */
4714errno_t
4715VNOP_READLINK(struct vnode *vp, struct uio *uio, vfs_context_t ctx)
4716{
4717	int _err;
4718	struct vnop_readlink_args a;
4719#if CONFIG_DTRACE
4720	user_ssize_t resid = uio_resid(uio);
4721#endif
4722	a.a_desc = &vnop_readlink_desc;
4723	a.a_vp = vp;
4724	a.a_uio = uio;
4725	a.a_context = ctx;
4726
4727	_err = (*vp->v_op[vnop_readlink_desc.vdesc_offset])(&a);
4728	DTRACE_FSINFO_IO(readlink,
4729	    vnode_t, vp, user_ssize_t, (resid - uio_resid(uio)));
4730
4731	return (_err);
4732}
4733
4734#if 0
4735/*
4736 *#
4737 *#% inactive     vp      L U U
4738 *#
4739 */
4740struct vnop_inactive_args {
4741	struct vnodeop_desc *a_desc;
4742	vnode_t a_vp;
4743	vfs_context_t a_context;
4744};
4745#endif /* 0*/
4746errno_t
4747VNOP_INACTIVE(struct vnode *vp, vfs_context_t ctx)
4748{
4749	int _err;
4750	struct vnop_inactive_args a;
4751
4752	a.a_desc = &vnop_inactive_desc;
4753	a.a_vp = vp;
4754	a.a_context = ctx;
4755
4756	_err = (*vp->v_op[vnop_inactive_desc.vdesc_offset])(&a);
4757	DTRACE_FSINFO(inactive, vnode_t, vp);
4758
4759#if NAMEDSTREAMS
4760	/* For file systems that do not support namedstream natively, mark
4761	 * the shadow stream file vnode to be recycled as soon as the last
4762	 * reference goes away.  To avoid re-entering reclaim code, do not
4763	 * call recycle on terminating namedstream vnodes.
4764	 */
4765	if (vnode_isnamedstream(vp) &&
4766	    (vp->v_parent != NULLVP) &&
4767	    vnode_isshadow(vp) &&
4768	    ((vp->v_lflag & VL_TERMINATE) == 0)) {
4769		vnode_recycle(vp);
4770	}
4771#endif
4772
4773	return (_err);
4774}
4775
4776
4777#if 0
4778/*
4779 *#
4780 *#% reclaim      vp      U U U
4781 *#
4782 */
4783struct vnop_reclaim_args {
4784	struct vnodeop_desc *a_desc;
4785	vnode_t a_vp;
4786	vfs_context_t a_context;
4787};
4788#endif /* 0*/
4789errno_t
4790VNOP_RECLAIM(struct vnode *vp, vfs_context_t ctx)
4791{
4792	int _err;
4793	struct vnop_reclaim_args a;
4794
4795	a.a_desc = &vnop_reclaim_desc;
4796	a.a_vp = vp;
4797	a.a_context = ctx;
4798
4799	_err = (*vp->v_op[vnop_reclaim_desc.vdesc_offset])(&a);
4800	DTRACE_FSINFO(reclaim, vnode_t, vp);
4801
4802	return (_err);
4803}
4804
4805
4806/*
4807 * Returns:	0			Success
4808 *	lock_fsnode:ENOENT		No such file or directory [only for VFS
4809 *					 that is not thread safe & vnode is
4810 *					 currently being/has been terminated]
4811 *	<vnop_pathconf_desc>:???	[per FS implementation specific]
4812 */
4813#if 0
4814/*
4815 *#
4816 *#% pathconf     vp      L L L
4817 *#
4818 */
4819struct vnop_pathconf_args {
4820	struct vnodeop_desc *a_desc;
4821	vnode_t a_vp;
4822	int a_name;
4823	int32_t *a_retval;
4824	vfs_context_t a_context;
4825};
4826#endif /* 0*/
4827errno_t
4828VNOP_PATHCONF(struct vnode *vp, int name, int32_t *retval, vfs_context_t ctx)
4829{
4830	int _err;
4831	struct vnop_pathconf_args a;
4832
4833	a.a_desc = &vnop_pathconf_desc;
4834	a.a_vp = vp;
4835	a.a_name = name;
4836	a.a_retval = retval;
4837	a.a_context = ctx;
4838
4839	_err = (*vp->v_op[vnop_pathconf_desc.vdesc_offset])(&a);
4840	DTRACE_FSINFO(pathconf, vnode_t, vp);
4841
4842	return (_err);
4843}
4844
4845/*
4846 * Returns:	0			Success
4847 *	err_advlock:ENOTSUP
4848 *	lf_advlock:???
4849 *	<vnop_advlock_desc>:???
4850 *
4851 * Notes:	VFS implementations of advisory locking using calls through
4852 *		<vnop_advlock_desc> because lock enforcement does not occur
4853 *		locally should try to limit themselves to the return codes
4854 *		documented above for lf_advlock and err_advlock.
4855 */
4856#if 0
4857/*
4858 *#
4859 *#% advlock      vp      U U U
4860 *#
4861 */
4862struct vnop_advlock_args {
4863	struct vnodeop_desc *a_desc;
4864	vnode_t a_vp;
4865	caddr_t a_id;
4866	int a_op;
4867	struct flock *a_fl;
4868	int a_flags;
4869	vfs_context_t a_context;
4870};
4871#endif /* 0*/
4872errno_t
4873VNOP_ADVLOCK(struct vnode *vp, caddr_t id, int op, struct flock *fl, int flags, vfs_context_t ctx, struct timespec *timeout)
4874{
4875	int _err;
4876	struct vnop_advlock_args a;
4877
4878	a.a_desc = &vnop_advlock_desc;
4879	a.a_vp = vp;
4880	a.a_id = id;
4881	a.a_op = op;
4882	a.a_fl = fl;
4883	a.a_flags = flags;
4884	a.a_context = ctx;
4885	a.a_timeout = timeout;
4886
4887	/* Disallow advisory locking on non-seekable vnodes */
4888	if (vnode_isfifo(vp)) {
4889		_err = err_advlock(&a);
4890	} else {
4891		if ((vp->v_flag & VLOCKLOCAL)) {
4892			/* Advisory locking done at this layer */
4893			_err = lf_advlock(&a);
4894		} else {
4895			/* Advisory locking done by underlying filesystem */
4896			_err = (*vp->v_op[vnop_advlock_desc.vdesc_offset])(&a);
4897		}
4898		DTRACE_FSINFO(advlock, vnode_t, vp);
4899	}
4900
4901	return (_err);
4902}
4903
4904
4905
4906#if 0
4907/*
4908 *#
4909 *#% allocate     vp      L L L
4910 *#
4911 */
4912struct vnop_allocate_args {
4913	struct vnodeop_desc *a_desc;
4914	vnode_t a_vp;
4915	off_t a_length;
4916	u_int32_t a_flags;
4917	off_t *a_bytesallocated;
4918	off_t a_offset;
4919	vfs_context_t a_context;
4920};
4921
4922#endif /* 0*/
4923errno_t
4924VNOP_ALLOCATE(struct vnode *vp, off_t length, u_int32_t flags, off_t *bytesallocated, off_t offset, vfs_context_t ctx)
4925{
4926	int _err;
4927	struct vnop_allocate_args a;
4928
4929	a.a_desc = &vnop_allocate_desc;
4930	a.a_vp = vp;
4931	a.a_length = length;
4932	a.a_flags = flags;
4933	a.a_bytesallocated = bytesallocated;
4934	a.a_offset = offset;
4935	a.a_context = ctx;
4936
4937	_err = (*vp->v_op[vnop_allocate_desc.vdesc_offset])(&a);
4938	DTRACE_FSINFO(allocate, vnode_t, vp);
4939#if CONFIG_FSE
4940	if (_err == 0) {
4941		add_fsevent(FSE_STAT_CHANGED, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE);
4942	}
4943#endif
4944
4945	return (_err);
4946}
4947
4948#if 0
4949/*
4950 *#
4951 *#% pagein       vp      = = =
4952 *#
4953 */
4954struct vnop_pagein_args {
4955	struct vnodeop_desc *a_desc;
4956	vnode_t a_vp;
4957	upl_t a_pl;
4958	upl_offset_t a_pl_offset;
4959	off_t a_f_offset;
4960	size_t a_size;
4961	int a_flags;
4962	vfs_context_t a_context;
4963};
4964#endif /* 0*/
4965errno_t
4966VNOP_PAGEIN(struct vnode *vp, upl_t pl, upl_offset_t pl_offset, off_t f_offset, size_t size, int flags, vfs_context_t ctx)
4967{
4968	int _err;
4969	struct vnop_pagein_args a;
4970
4971	a.a_desc = &vnop_pagein_desc;
4972	a.a_vp = vp;
4973	a.a_pl = pl;
4974	a.a_pl_offset = pl_offset;
4975	a.a_f_offset = f_offset;
4976	a.a_size = size;
4977	a.a_flags = flags;
4978	a.a_context = ctx;
4979
4980	_err = (*vp->v_op[vnop_pagein_desc.vdesc_offset])(&a);
4981	DTRACE_FSINFO(pagein, vnode_t, vp);
4982
4983	return (_err);
4984}
4985
4986#if 0
4987/*
4988 *#
4989 *#% pageout      vp      = = =
4990 *#
4991 */
4992struct vnop_pageout_args {
4993	struct vnodeop_desc *a_desc;
4994	vnode_t a_vp;
4995	upl_t a_pl;
4996	upl_offset_t a_pl_offset;
4997	off_t a_f_offset;
4998	size_t a_size;
4999	int a_flags;
5000	vfs_context_t a_context;
5001};
5002
5003#endif /* 0*/
5004errno_t
5005VNOP_PAGEOUT(struct vnode *vp, upl_t pl, upl_offset_t pl_offset, off_t f_offset, size_t size, int flags, vfs_context_t ctx)
5006{
5007	int _err;
5008	struct vnop_pageout_args a;
5009
5010	a.a_desc = &vnop_pageout_desc;
5011	a.a_vp = vp;
5012	a.a_pl = pl;
5013	a.a_pl_offset = pl_offset;
5014	a.a_f_offset = f_offset;
5015	a.a_size = size;
5016	a.a_flags = flags;
5017	a.a_context = ctx;
5018
5019	_err = (*vp->v_op[vnop_pageout_desc.vdesc_offset])(&a);
5020	DTRACE_FSINFO(pageout, vnode_t, vp);
5021
5022	post_event_if_success(vp, _err, NOTE_WRITE);
5023
5024	return (_err);
5025}
5026
5027int
5028vn_remove(vnode_t dvp, vnode_t *vpp, struct nameidata *ndp, int32_t flags, struct vnode_attr *vap, vfs_context_t ctx)
5029{
5030	if (vnode_compound_remove_available(dvp)) {
5031		return VNOP_COMPOUND_REMOVE(dvp, vpp, ndp, flags, vap, ctx);
5032	} else {
5033		return VNOP_REMOVE(dvp, *vpp, &ndp->ni_cnd, flags, ctx);
5034	}
5035}
5036
5037#if CONFIG_SEARCHFS
5038
5039#if 0
5040/*
5041 *#
5042 *#% searchfs     vp      L L L
5043 *#
5044 */
5045struct vnop_searchfs_args {
5046	struct vnodeop_desc *a_desc;
5047	vnode_t a_vp;
5048	void *a_searchparams1;
5049	void *a_searchparams2;
5050	struct attrlist *a_searchattrs;
5051	uint32_t a_maxmatches;
5052	struct timeval *a_timelimit;
5053	struct attrlist *a_returnattrs;
5054	uint32_t *a_nummatches;
5055	uint32_t a_scriptcode;
5056	uint32_t a_options;
5057	struct uio *a_uio;
5058	struct searchstate *a_searchstate;
5059	vfs_context_t a_context;
5060};
5061
5062#endif /* 0*/
5063errno_t
5064VNOP_SEARCHFS(struct vnode *vp, void *searchparams1, void *searchparams2, struct attrlist *searchattrs, uint32_t maxmatches, struct timeval *timelimit, struct attrlist *returnattrs, uint32_t *nummatches, uint32_t scriptcode, uint32_t options, struct uio *uio, struct searchstate *searchstate, vfs_context_t ctx)
5065{
5066	int _err;
5067	struct vnop_searchfs_args a;
5068
5069	a.a_desc = &vnop_searchfs_desc;
5070	a.a_vp = vp;
5071	a.a_searchparams1 = searchparams1;
5072	a.a_searchparams2 = searchparams2;
5073	a.a_searchattrs = searchattrs;
5074	a.a_maxmatches = maxmatches;
5075	a.a_timelimit = timelimit;
5076	a.a_returnattrs = returnattrs;
5077	a.a_nummatches = nummatches;
5078	a.a_scriptcode = scriptcode;
5079	a.a_options = options;
5080	a.a_uio = uio;
5081	a.a_searchstate = searchstate;
5082	a.a_context = ctx;
5083
5084	_err = (*vp->v_op[vnop_searchfs_desc.vdesc_offset])(&a);
5085	DTRACE_FSINFO(searchfs, vnode_t, vp);
5086
5087	return (_err);
5088}
5089#endif /* CONFIG_SEARCHFS */
5090
5091#if 0
5092/*
5093 *#
5094 *#% copyfile fvp U U U
5095 *#% copyfile tdvp L U U
5096 *#% copyfile tvp X U U
5097 *#
5098 */
5099struct vnop_copyfile_args {
5100	struct vnodeop_desc *a_desc;
5101	vnode_t a_fvp;
5102	vnode_t a_tdvp;
5103	vnode_t a_tvp;
5104	struct componentname *a_tcnp;
5105	int a_mode;
5106	int a_flags;
5107	vfs_context_t a_context;
5108};
5109#endif /* 0*/
5110errno_t
5111VNOP_COPYFILE(struct vnode *fvp, struct vnode *tdvp, struct vnode *tvp, struct componentname *tcnp,
5112              int mode, int flags, vfs_context_t ctx)
5113{
5114	int _err;
5115	struct vnop_copyfile_args a;
5116	a.a_desc = &vnop_copyfile_desc;
5117	a.a_fvp = fvp;
5118	a.a_tdvp = tdvp;
5119	a.a_tvp = tvp;
5120	a.a_tcnp = tcnp;
5121	a.a_mode = mode;
5122	a.a_flags = flags;
5123	a.a_context = ctx;
5124	_err = (*fvp->v_op[vnop_copyfile_desc.vdesc_offset])(&a);
5125	DTRACE_FSINFO(copyfile, vnode_t, fvp);
5126	return (_err);
5127}
5128
5129errno_t
5130VNOP_GETXATTR(vnode_t vp, const char *name, uio_t uio, size_t *size, int options, vfs_context_t ctx)
5131{
5132	struct vnop_getxattr_args a;
5133	int error;
5134
5135	a.a_desc = &vnop_getxattr_desc;
5136	a.a_vp = vp;
5137	a.a_name = name;
5138	a.a_uio = uio;
5139	a.a_size = size;
5140	a.a_options = options;
5141	a.a_context = ctx;
5142
5143	error = (*vp->v_op[vnop_getxattr_desc.vdesc_offset])(&a);
5144	DTRACE_FSINFO(getxattr, vnode_t, vp);
5145
5146	return (error);
5147}
5148
5149errno_t
5150VNOP_SETXATTR(vnode_t vp, const char *name, uio_t uio, int options, vfs_context_t ctx)
5151{
5152	struct vnop_setxattr_args a;
5153	int error;
5154
5155	a.a_desc = &vnop_setxattr_desc;
5156	a.a_vp = vp;
5157	a.a_name = name;
5158	a.a_uio = uio;
5159	a.a_options = options;
5160	a.a_context = ctx;
5161
5162	error = (*vp->v_op[vnop_setxattr_desc.vdesc_offset])(&a);
5163	DTRACE_FSINFO(setxattr, vnode_t, vp);
5164
5165	if (error == 0)
5166	        vnode_uncache_authorized_action(vp, KAUTH_INVALIDATE_CACHED_RIGHTS);
5167
5168	post_event_if_success(vp, error, NOTE_ATTRIB);
5169
5170	return (error);
5171}
5172
5173errno_t
5174VNOP_REMOVEXATTR(vnode_t vp, const char *name, int options, vfs_context_t ctx)
5175{
5176	struct vnop_removexattr_args a;
5177	int error;
5178
5179	a.a_desc = &vnop_removexattr_desc;
5180	a.a_vp = vp;
5181	a.a_name = name;
5182	a.a_options = options;
5183	a.a_context = ctx;
5184
5185	error = (*vp->v_op[vnop_removexattr_desc.vdesc_offset])(&a);
5186	DTRACE_FSINFO(removexattr, vnode_t, vp);
5187
5188	post_event_if_success(vp, error, NOTE_ATTRIB);
5189
5190	return (error);
5191}
5192
5193errno_t
5194VNOP_LISTXATTR(vnode_t vp, uio_t uio, size_t *size, int options, vfs_context_t ctx)
5195{
5196	struct vnop_listxattr_args a;
5197	int error;
5198
5199	a.a_desc = &vnop_listxattr_desc;
5200	a.a_vp = vp;
5201	a.a_uio = uio;
5202	a.a_size = size;
5203	a.a_options = options;
5204	a.a_context = ctx;
5205
5206	error = (*vp->v_op[vnop_listxattr_desc.vdesc_offset])(&a);
5207	DTRACE_FSINFO(listxattr, vnode_t, vp);
5208
5209	return (error);
5210}
5211
5212
5213#if 0
5214/*
5215 *#
5216 *#% blktooff vp = = =
5217 *#
5218 */
5219struct vnop_blktooff_args {
5220	struct vnodeop_desc *a_desc;
5221	vnode_t a_vp;
5222	daddr64_t a_lblkno;
5223	off_t *a_offset;
5224};
5225#endif /* 0*/
5226errno_t
5227VNOP_BLKTOOFF(struct vnode *vp, daddr64_t lblkno, off_t *offset)
5228{
5229	int _err;
5230	struct vnop_blktooff_args a;
5231
5232	a.a_desc = &vnop_blktooff_desc;
5233	a.a_vp = vp;
5234	a.a_lblkno = lblkno;
5235	a.a_offset = offset;
5236
5237	_err = (*vp->v_op[vnop_blktooff_desc.vdesc_offset])(&a);
5238	DTRACE_FSINFO(blktooff, vnode_t, vp);
5239
5240	return (_err);
5241}
5242
5243#if 0
5244/*
5245 *#
5246 *#% offtoblk vp = = =
5247 *#
5248 */
5249struct vnop_offtoblk_args {
5250	struct vnodeop_desc *a_desc;
5251	vnode_t a_vp;
5252	off_t a_offset;
5253	daddr64_t *a_lblkno;
5254};
5255#endif /* 0*/
5256errno_t
5257VNOP_OFFTOBLK(struct vnode *vp, off_t offset, daddr64_t *lblkno)
5258{
5259	int _err;
5260	struct vnop_offtoblk_args a;
5261
5262	a.a_desc = &vnop_offtoblk_desc;
5263	a.a_vp = vp;
5264	a.a_offset = offset;
5265	a.a_lblkno = lblkno;
5266
5267	_err = (*vp->v_op[vnop_offtoblk_desc.vdesc_offset])(&a);
5268	DTRACE_FSINFO(offtoblk, vnode_t, vp);
5269
5270	return (_err);
5271}
5272
5273#if 0
5274/*
5275 *#
5276 *#% blockmap vp L L L
5277 *#
5278 */
5279struct vnop_blockmap_args {
5280	struct vnodeop_desc *a_desc;
5281	vnode_t a_vp;
5282	off_t a_foffset;
5283	size_t a_size;
5284	daddr64_t *a_bpn;
5285	size_t *a_run;
5286	void *a_poff;
5287	int a_flags;
5288	vfs_context_t a_context;
5289};
5290#endif /* 0*/
5291errno_t
5292VNOP_BLOCKMAP(struct vnode *vp, off_t foffset, size_t size, daddr64_t *bpn, size_t *run, void *poff, int flags, vfs_context_t ctx)
5293{
5294	int _err;
5295	struct vnop_blockmap_args a;
5296	size_t localrun = 0;
5297
5298	if (ctx == NULL) {
5299		ctx = vfs_context_current();
5300	}
5301	a.a_desc = &vnop_blockmap_desc;
5302	a.a_vp = vp;
5303	a.a_foffset = foffset;
5304	a.a_size = size;
5305	a.a_bpn = bpn;
5306	a.a_run = &localrun;
5307	a.a_poff = poff;
5308	a.a_flags = flags;
5309	a.a_context = ctx;
5310
5311	_err = (*vp->v_op[vnop_blockmap_desc.vdesc_offset])(&a);
5312	DTRACE_FSINFO(blockmap, vnode_t, vp);
5313
5314	/*
5315	 * We used a local variable to request information from the underlying
5316	 * filesystem about the length of the I/O run in question.  If
5317	 * we get malformed output from the filesystem, we cap it to the length
5318	 * requested, at most.  Update 'run' on the way out.
5319	 */
5320	if (_err == 0) {
5321		if (localrun > size) {
5322			localrun = size;
5323		}
5324
5325		if (run) {
5326			*run = localrun;
5327		}
5328	}
5329
5330	return (_err);
5331}
5332
5333#if 0
5334struct vnop_strategy_args {
5335	struct vnodeop_desc *a_desc;
5336	struct buf *a_bp;
5337};
5338
5339#endif /* 0*/
5340errno_t
5341VNOP_STRATEGY(struct buf *bp)
5342{
5343	int _err;
5344	struct vnop_strategy_args a;
5345	vnode_t vp = buf_vnode(bp);
5346	a.a_desc = &vnop_strategy_desc;
5347	a.a_bp = bp;
5348	_err = (*vp->v_op[vnop_strategy_desc.vdesc_offset])(&a);
5349	DTRACE_FSINFO(strategy, vnode_t, vp);
5350	return (_err);
5351}
5352
5353#if 0
5354struct vnop_bwrite_args {
5355	struct vnodeop_desc *a_desc;
5356	buf_t a_bp;
5357};
5358#endif /* 0*/
5359errno_t
5360VNOP_BWRITE(struct buf *bp)
5361{
5362	int _err;
5363	struct vnop_bwrite_args a;
5364	vnode_t vp = buf_vnode(bp);
5365	a.a_desc = &vnop_bwrite_desc;
5366	a.a_bp = bp;
5367	_err = (*vp->v_op[vnop_bwrite_desc.vdesc_offset])(&a);
5368	DTRACE_FSINFO(bwrite, vnode_t, vp);
5369	return (_err);
5370}
5371
5372#if 0
5373struct vnop_kqfilt_add_args {
5374	struct vnodeop_desc *a_desc;
5375	struct vnode *a_vp;
5376	struct knote *a_kn;
5377	vfs_context_t a_context;
5378};
5379#endif
5380errno_t
5381VNOP_KQFILT_ADD(struct vnode *vp, struct knote *kn, vfs_context_t ctx)
5382{
5383	int _err;
5384	struct vnop_kqfilt_add_args a;
5385
5386	a.a_desc = VDESC(vnop_kqfilt_add);
5387	a.a_vp = vp;
5388	a.a_kn = kn;
5389	a.a_context = ctx;
5390
5391	_err = (*vp->v_op[vnop_kqfilt_add_desc.vdesc_offset])(&a);
5392	DTRACE_FSINFO(kqfilt_add, vnode_t, vp);
5393
5394	return(_err);
5395}
5396
5397#if 0
5398struct vnop_kqfilt_remove_args {
5399	struct vnodeop_desc *a_desc;
5400	struct vnode *a_vp;
5401	uintptr_t a_ident;
5402	vfs_context_t a_context;
5403};
5404#endif
5405errno_t
5406VNOP_KQFILT_REMOVE(struct vnode *vp, uintptr_t ident, vfs_context_t ctx)
5407{
5408	int _err;
5409	struct vnop_kqfilt_remove_args a;
5410
5411	a.a_desc = VDESC(vnop_kqfilt_remove);
5412	a.a_vp = vp;
5413	a.a_ident = ident;
5414	a.a_context = ctx;
5415
5416	_err = (*vp->v_op[vnop_kqfilt_remove_desc.vdesc_offset])(&a);
5417	DTRACE_FSINFO(kqfilt_remove, vnode_t, vp);
5418
5419	return(_err);
5420}
5421
5422errno_t
5423VNOP_MONITOR(vnode_t vp, uint32_t events, uint32_t flags, void *handle, vfs_context_t ctx)
5424{
5425	int _err;
5426	struct vnop_monitor_args a;
5427
5428	a.a_desc = VDESC(vnop_monitor);
5429	a.a_vp = vp;
5430	a.a_events = events;
5431	a.a_flags = flags;
5432	a.a_handle = handle;
5433	a.a_context = ctx;
5434
5435	_err = (*vp->v_op[vnop_monitor_desc.vdesc_offset])(&a);
5436	DTRACE_FSINFO(monitor, vnode_t, vp);
5437
5438	return(_err);
5439}
5440
5441#if 0
5442struct vnop_setlabel_args {
5443	struct vnodeop_desc *a_desc;
5444	struct vnode *a_vp;
5445	struct label *a_vl;
5446	vfs_context_t a_context;
5447};
5448#endif
5449errno_t
5450VNOP_SETLABEL(struct vnode *vp, struct label *label, vfs_context_t ctx)
5451{
5452	int _err;
5453	struct vnop_setlabel_args a;
5454
5455	a.a_desc = VDESC(vnop_setlabel);
5456	a.a_vp = vp;
5457	a.a_vl = label;
5458	a.a_context = ctx;
5459
5460	_err = (*vp->v_op[vnop_setlabel_desc.vdesc_offset])(&a);
5461	DTRACE_FSINFO(setlabel, vnode_t, vp);
5462
5463	return(_err);
5464}
5465
5466
5467#if NAMEDSTREAMS
5468/*
5469 * Get a named streamed
5470 */
5471errno_t
5472VNOP_GETNAMEDSTREAM(vnode_t vp, vnode_t *svpp, const char *name, enum nsoperation operation, int flags, vfs_context_t ctx)
5473{
5474	int _err;
5475	struct vnop_getnamedstream_args a;
5476
5477	a.a_desc = &vnop_getnamedstream_desc;
5478	a.a_vp = vp;
5479	a.a_svpp = svpp;
5480	a.a_name = name;
5481	a.a_operation = operation;
5482	a.a_flags = flags;
5483	a.a_context = ctx;
5484
5485	_err = (*vp->v_op[vnop_getnamedstream_desc.vdesc_offset])(&a);
5486	DTRACE_FSINFO(getnamedstream, vnode_t, vp);
5487	return (_err);
5488}
5489
5490/*
5491 * Create a named streamed
5492 */
5493errno_t
5494VNOP_MAKENAMEDSTREAM(vnode_t vp, vnode_t *svpp, const char *name, int flags, vfs_context_t ctx)
5495{
5496	int _err;
5497	struct vnop_makenamedstream_args a;
5498
5499	a.a_desc = &vnop_makenamedstream_desc;
5500	a.a_vp = vp;
5501	a.a_svpp = svpp;
5502	a.a_name = name;
5503	a.a_flags = flags;
5504	a.a_context = ctx;
5505
5506	_err = (*vp->v_op[vnop_makenamedstream_desc.vdesc_offset])(&a);
5507	DTRACE_FSINFO(makenamedstream, vnode_t, vp);
5508	return (_err);
5509}
5510
5511
5512/*
5513 * Remove a named streamed
5514 */
5515errno_t
5516VNOP_REMOVENAMEDSTREAM(vnode_t vp, vnode_t svp, const char *name, int flags, vfs_context_t ctx)
5517{
5518	int _err;
5519	struct vnop_removenamedstream_args a;
5520
5521	a.a_desc = &vnop_removenamedstream_desc;
5522	a.a_vp = vp;
5523	a.a_svp = svp;
5524	a.a_name = name;
5525	a.a_flags = flags;
5526	a.a_context = ctx;
5527
5528	_err = (*vp->v_op[vnop_removenamedstream_desc.vdesc_offset])(&a);
5529	DTRACE_FSINFO(removenamedstream, vnode_t, vp);
5530	return (_err);
5531}
5532#endif
5533