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