2 * Copyright (c) 2000-2017 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. 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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
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.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
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.
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
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,
76 * External virtual filesystem routines
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>
87 #include <sys/vnode_internal.h>
89 #include <sys/namei.h>
90 #include <sys/ucred.h>
92 #include <sys/errno.h>
93 #include <sys/malloc.h>
94 #include <sys/domain.h>
96 #include <sys/syslog.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 #include <sys/kdebug.h>
108 #include <kern/assert.h>
109 #include <kern/kalloc.h>
110 #include <kern/task.h>
111 #include <kern/policy_internal.h>
113 #include <libkern/OSByteOrder.h>
115 #include <miscfs/specfs/specdev.h>
117 #include <mach/mach_types.h>
118 #include <mach/memory_object_types.h>
119 #include <mach/task.h>
122 #include <security/mac_framework.h>
126 #include <miscfs/nullfs/nullfs.h>
137 #define NATIVE_XATTR(VP) \
138 ((VP)->v_mount ? (VP)->v_mount->mnt_kern_flag & MNTK_EXTENDED_ATTRS : 0)
140 #if CONFIG_APPLEDOUBLE
141 static void xattrfile_remove(vnode_t dvp
, const char *basename
,
142 vfs_context_t ctx
, int force
);
143 static void xattrfile_setattr(vnode_t dvp
, const char * basename
,
144 struct vnode_attr
* vap
, vfs_context_t ctx
);
145 #endif /* CONFIG_APPLEDOUBLE */
147 static errno_t
post_rename(vnode_t fdvp
, vnode_t fvp
, vnode_t tdvp
, vnode_t tvp
);
150 * vnode_setneedinactive
152 * Description: Indicate that when the last iocount on this vnode goes away,
153 * and the usecount is also zero, we should inform the filesystem
156 * Parameters: vnode_t vnode to mark
160 * Notes: Notably used when we're deleting a file--we need not have a
161 * usecount, so VNOP_INACTIVE may not get called by anyone. We
162 * want it called when we drop our iocount.
165 vnode_setneedinactive(vnode_t vp
)
170 vp
->v_lflag
|= VL_NEEDINACTIVE
;
175 /* ====================================================================== */
176 /* ************ EXTERNAL KERNEL APIS ********************************** */
177 /* ====================================================================== */
180 * implementations of exported VFS operations
183 VFS_MOUNT(mount_t mp
, vnode_t devvp
, user_addr_t data
, vfs_context_t ctx
)
187 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_mount
== 0))
190 if (vfs_context_is64bit(ctx
)) {
191 if (vfs_64bitready(mp
)) {
192 error
= (*mp
->mnt_op
->vfs_mount
)(mp
, devvp
, data
, ctx
);
199 error
= (*mp
->mnt_op
->vfs_mount
)(mp
, devvp
, data
, ctx
);
206 VFS_START(mount_t mp
, int flags
, vfs_context_t ctx
)
210 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_start
== 0))
213 error
= (*mp
->mnt_op
->vfs_start
)(mp
, flags
, ctx
);
219 VFS_UNMOUNT(mount_t mp
, int flags
, vfs_context_t ctx
)
223 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_unmount
== 0))
226 error
= (*mp
->mnt_op
->vfs_unmount
)(mp
, flags
, ctx
);
233 * ENOTSUP Not supported
237 * Note: The return codes from the underlying VFS's root routine can't
238 * be fully enumerated here, since third party VFS authors may not
239 * limit their error returns to the ones documented here, even
240 * though this may result in some programs functioning incorrectly.
242 * The return codes documented above are those which may currently
243 * be returned by HFS from hfs_vfs_root, which is a simple wrapper
244 * for a call to hfs_vget on the volume mount point, not including
245 * additional error codes which may be propagated from underlying
246 * routines called by hfs_vget.
249 VFS_ROOT(mount_t mp
, struct vnode
** vpp
, vfs_context_t ctx
)
253 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_root
== 0))
257 ctx
= vfs_context_current();
260 error
= (*mp
->mnt_op
->vfs_root
)(mp
, vpp
, ctx
);
266 VFS_QUOTACTL(mount_t mp
, int cmd
, uid_t uid
, caddr_t datap
, vfs_context_t ctx
)
270 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_quotactl
== 0))
273 error
= (*mp
->mnt_op
->vfs_quotactl
)(mp
, cmd
, uid
, datap
, ctx
);
279 VFS_GETATTR(mount_t mp
, struct vfs_attr
*vfa
, vfs_context_t ctx
)
283 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_getattr
== 0))
287 ctx
= vfs_context_current();
290 error
= (*mp
->mnt_op
->vfs_getattr
)(mp
, vfa
, ctx
);
296 VFS_SETATTR(mount_t mp
, struct vfs_attr
*vfa
, vfs_context_t ctx
)
300 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_setattr
== 0))
304 ctx
= vfs_context_current();
307 error
= (*mp
->mnt_op
->vfs_setattr
)(mp
, vfa
, ctx
);
313 VFS_SYNC(mount_t mp
, int flags
, vfs_context_t ctx
)
317 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_sync
== 0))
321 ctx
= vfs_context_current();
324 error
= (*mp
->mnt_op
->vfs_sync
)(mp
, flags
, ctx
);
330 VFS_VGET(mount_t mp
, ino64_t ino
, struct vnode
**vpp
, vfs_context_t ctx
)
334 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_vget
== 0))
338 ctx
= vfs_context_current();
341 error
= (*mp
->mnt_op
->vfs_vget
)(mp
, ino
, vpp
, ctx
);
347 VFS_FHTOVP(mount_t mp
, int fhlen
, unsigned char *fhp
, vnode_t
*vpp
, vfs_context_t ctx
)
351 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_fhtovp
== 0))
355 ctx
= vfs_context_current();
358 error
= (*mp
->mnt_op
->vfs_fhtovp
)(mp
, fhlen
, fhp
, vpp
, ctx
);
364 VFS_VPTOFH(struct vnode
*vp
, int *fhlenp
, unsigned char *fhp
, vfs_context_t ctx
)
368 if ((vp
->v_mount
== dead_mountp
) || (vp
->v_mount
->mnt_op
->vfs_vptofh
== 0))
372 ctx
= vfs_context_current();
375 error
= (*vp
->v_mount
->mnt_op
->vfs_vptofh
)(vp
, fhlenp
, fhp
, ctx
);
380 int VFS_IOCTL(struct mount
*mp
, u_long command
, caddr_t data
,
381 int flags
, vfs_context_t context
)
383 if (mp
== dead_mountp
|| !mp
->mnt_op
->vfs_ioctl
)
386 return mp
->mnt_op
->vfs_ioctl(mp
, command
, data
, flags
,
387 context
?: vfs_context_current());
391 VFS_VGET_SNAPDIR(mount_t mp
, vnode_t
*vpp
, vfs_context_t ctx
)
395 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_vget_snapdir
== 0))
399 ctx
= vfs_context_current();
401 error
= (*mp
->mnt_op
->vfs_vget_snapdir
)(mp
, vpp
, ctx
);
406 /* returns the cached throttle mask for the mount_t */
408 vfs_throttle_mask(mount_t mp
)
410 return(mp
->mnt_throttle_mask
);
413 /* returns a copy of vfs type name for the mount_t */
415 vfs_name(mount_t mp
, char *buffer
)
417 strncpy(buffer
, mp
->mnt_vtable
->vfc_name
, MFSNAMELEN
);
420 /* returns vfs type number for the mount_t */
422 vfs_typenum(mount_t mp
)
424 return(mp
->mnt_vtable
->vfc_typenum
);
427 /* Safe to cast to "struct label*"; returns "void*" to limit dependence of mount.h on security headers. */
429 vfs_mntlabel(mount_t mp
)
431 return (void*)mp
->mnt_mntlabel
;
434 /* returns command modifier flags of mount_t ie. MNT_CMDFLAGS */
436 vfs_flags(mount_t mp
)
438 return((uint64_t)(mp
->mnt_flag
& (MNT_CMDFLAGS
| MNT_VISFLAGMASK
)));
441 /* set any of the command modifier flags(MNT_CMDFLAGS) in mount_t */
443 vfs_setflags(mount_t mp
, uint64_t flags
)
445 uint32_t lflags
= (uint32_t)(flags
& (MNT_CMDFLAGS
| MNT_VISFLAGMASK
));
448 mp
->mnt_flag
|= lflags
;
452 /* clear any of the command modifier flags(MNT_CMDFLAGS) in mount_t */
454 vfs_clearflags(mount_t mp
, uint64_t flags
)
456 uint32_t lflags
= (uint32_t)(flags
& (MNT_CMDFLAGS
| MNT_VISFLAGMASK
));
459 mp
->mnt_flag
&= ~lflags
;
463 /* Is the mount_t ronly and upgrade read/write requested? */
465 vfs_iswriteupgrade(mount_t mp
) /* ronly && MNTK_WANTRDWR */
467 return ((mp
->mnt_flag
& MNT_RDONLY
) && (mp
->mnt_kern_flag
& MNTK_WANTRDWR
));
471 /* Is the mount_t mounted ronly */
473 vfs_isrdonly(mount_t mp
)
475 return (mp
->mnt_flag
& MNT_RDONLY
);
478 /* Is the mount_t mounted for filesystem synchronous writes? */
480 vfs_issynchronous(mount_t mp
)
482 return (mp
->mnt_flag
& MNT_SYNCHRONOUS
);
485 /* Is the mount_t mounted read/write? */
487 vfs_isrdwr(mount_t mp
)
489 return ((mp
->mnt_flag
& MNT_RDONLY
) == 0);
493 /* Is mount_t marked for update (ie MNT_UPDATE) */
495 vfs_isupdate(mount_t mp
)
497 return (mp
->mnt_flag
& MNT_UPDATE
);
501 /* Is mount_t marked for reload (ie MNT_RELOAD) */
503 vfs_isreload(mount_t mp
)
505 return ((mp
->mnt_flag
& MNT_UPDATE
) && (mp
->mnt_flag
& MNT_RELOAD
));
508 /* Is mount_t marked for forced unmount (ie MNT_FORCE or MNTK_FRCUNMOUNT) */
510 vfs_isforce(mount_t mp
)
512 if (mp
->mnt_lflag
& MNT_LFORCE
)
519 vfs_isunmount(mount_t mp
)
521 if ((mp
->mnt_lflag
& MNT_LUNMOUNT
)) {
529 vfs_64bitready(mount_t mp
)
531 if ((mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFS64BITREADY
))
539 vfs_authcache_ttl(mount_t mp
)
541 if ( (mp
->mnt_kern_flag
& (MNTK_AUTH_OPAQUE
| MNTK_AUTH_CACHE_TTL
)) )
542 return (mp
->mnt_authcache_ttl
);
544 return (CACHED_RIGHT_INFINITE_TTL
);
548 vfs_setauthcache_ttl(mount_t mp
, int ttl
)
551 mp
->mnt_kern_flag
|= MNTK_AUTH_CACHE_TTL
;
552 mp
->mnt_authcache_ttl
= ttl
;
557 vfs_clearauthcache_ttl(mount_t mp
)
560 mp
->mnt_kern_flag
&= ~MNTK_AUTH_CACHE_TTL
;
562 * back to the default TTL value in case
563 * MNTK_AUTH_OPAQUE is set on this mount
565 mp
->mnt_authcache_ttl
= CACHED_LOOKUP_RIGHT_TTL
;
570 vfs_authopaque(mount_t mp
)
572 if ((mp
->mnt_kern_flag
& MNTK_AUTH_OPAQUE
))
579 vfs_authopaqueaccess(mount_t mp
)
581 if ((mp
->mnt_kern_flag
& MNTK_AUTH_OPAQUE_ACCESS
))
588 vfs_setauthopaque(mount_t mp
)
591 mp
->mnt_kern_flag
|= MNTK_AUTH_OPAQUE
;
596 vfs_setauthopaqueaccess(mount_t mp
)
599 mp
->mnt_kern_flag
|= MNTK_AUTH_OPAQUE_ACCESS
;
604 vfs_clearauthopaque(mount_t mp
)
607 mp
->mnt_kern_flag
&= ~MNTK_AUTH_OPAQUE
;
612 vfs_clearauthopaqueaccess(mount_t mp
)
615 mp
->mnt_kern_flag
&= ~MNTK_AUTH_OPAQUE_ACCESS
;
620 vfs_setextendedsecurity(mount_t mp
)
623 mp
->mnt_kern_flag
|= MNTK_EXTENDED_SECURITY
;
628 vfs_clearextendedsecurity(mount_t mp
)
631 mp
->mnt_kern_flag
&= ~MNTK_EXTENDED_SECURITY
;
636 vfs_setnoswap(mount_t mp
)
639 mp
->mnt_kern_flag
|= MNTK_NOSWAP
;
644 vfs_clearnoswap(mount_t mp
)
647 mp
->mnt_kern_flag
&= ~MNTK_NOSWAP
;
652 vfs_extendedsecurity(mount_t mp
)
654 return(mp
->mnt_kern_flag
& MNTK_EXTENDED_SECURITY
);
657 /* returns the max size of short symlink in this mount_t */
659 vfs_maxsymlen(mount_t mp
)
661 return(mp
->mnt_maxsymlinklen
);
664 /* set max size of short symlink on mount_t */
666 vfs_setmaxsymlen(mount_t mp
, uint32_t symlen
)
668 mp
->mnt_maxsymlinklen
= symlen
;
671 /* return a pointer to the RO vfs_statfs associated with mount_t */
673 vfs_statfs(mount_t mp
)
675 return(&mp
->mnt_vfsstat
);
679 vfs_getattr(mount_t mp
, struct vfs_attr
*vfa
, vfs_context_t ctx
)
683 if ((error
= VFS_GETATTR(mp
, vfa
, ctx
)) != 0)
687 * If we have a filesystem create time, use it to default some others.
689 if (VFSATTR_IS_SUPPORTED(vfa
, f_create_time
)) {
690 if (VFSATTR_IS_ACTIVE(vfa
, f_modify_time
) && !VFSATTR_IS_SUPPORTED(vfa
, f_modify_time
))
691 VFSATTR_RETURN(vfa
, f_modify_time
, vfa
->f_create_time
);
698 vfs_setattr(mount_t mp
, struct vfs_attr
*vfa
, vfs_context_t ctx
)
702 if (vfs_isrdonly(mp
))
705 error
= VFS_SETATTR(mp
, vfa
, ctx
);
708 * If we had alternate ways of setting vfs attributes, we'd
715 /* return the private data handle stored in mount_t */
717 vfs_fsprivate(mount_t mp
)
719 return(mp
->mnt_data
);
722 /* set the private data handle in mount_t */
724 vfs_setfsprivate(mount_t mp
, void *mntdata
)
727 mp
->mnt_data
= mntdata
;
731 /* query whether the mount point supports native EAs */
733 vfs_nativexattrs(mount_t mp
) {
734 return (mp
->mnt_kern_flag
& MNTK_EXTENDED_ATTRS
);
738 * return the block size of the underlying
739 * device associated with mount_t
742 vfs_devblocksize(mount_t mp
) {
744 return(mp
->mnt_devblocksize
);
748 * Returns vnode with an iocount that must be released with vnode_put()
751 vfs_vnodecovered(mount_t mp
)
753 vnode_t vp
= mp
->mnt_vnodecovered
;
754 if ((vp
== NULL
) || (vnode_getwithref(vp
) != 0)) {
762 * Returns device vnode backing a mountpoint with an iocount (if valid vnode exists).
763 * The iocount must be released with vnode_put(). Note that this KPI is subtle
764 * with respect to the validity of using this device vnode for anything substantial
765 * (which is discouraged). If commands are sent to the device driver without
766 * taking proper steps to ensure that the device is still open, chaos may ensue.
767 * Similarly, this routine should only be called if there is some guarantee that
768 * the mount itself is still valid.
771 vfs_devvp(mount_t mp
)
773 vnode_t vp
= mp
->mnt_devvp
;
775 if ((vp
!= NULLVP
) && (vnode_get(vp
) == 0)) {
783 * return the io attributes associated with mount_t
786 vfs_ioattr(mount_t mp
, struct vfsioattr
*ioattrp
)
788 ioattrp
->io_reserved
[0] = NULL
;
789 ioattrp
->io_reserved
[1] = NULL
;
791 ioattrp
->io_maxreadcnt
= MAXPHYS
;
792 ioattrp
->io_maxwritecnt
= MAXPHYS
;
793 ioattrp
->io_segreadcnt
= 32;
794 ioattrp
->io_segwritecnt
= 32;
795 ioattrp
->io_maxsegreadsize
= MAXPHYS
;
796 ioattrp
->io_maxsegwritesize
= MAXPHYS
;
797 ioattrp
->io_devblocksize
= DEV_BSIZE
;
798 ioattrp
->io_flags
= 0;
799 ioattrp
->io_max_swappin_available
= 0;
801 ioattrp
->io_maxreadcnt
= mp
->mnt_maxreadcnt
;
802 ioattrp
->io_maxwritecnt
= mp
->mnt_maxwritecnt
;
803 ioattrp
->io_segreadcnt
= mp
->mnt_segreadcnt
;
804 ioattrp
->io_segwritecnt
= mp
->mnt_segwritecnt
;
805 ioattrp
->io_maxsegreadsize
= mp
->mnt_maxsegreadsize
;
806 ioattrp
->io_maxsegwritesize
= mp
->mnt_maxsegwritesize
;
807 ioattrp
->io_devblocksize
= mp
->mnt_devblocksize
;
808 ioattrp
->io_flags
= mp
->mnt_ioflags
;
809 ioattrp
->io_max_swappin_available
= mp
->mnt_max_swappin_available
;
815 * set the IO attributes associated with mount_t
818 vfs_setioattr(mount_t mp
, struct vfsioattr
* ioattrp
)
822 mp
->mnt_maxreadcnt
= ioattrp
->io_maxreadcnt
;
823 mp
->mnt_maxwritecnt
= ioattrp
->io_maxwritecnt
;
824 mp
->mnt_segreadcnt
= ioattrp
->io_segreadcnt
;
825 mp
->mnt_segwritecnt
= ioattrp
->io_segwritecnt
;
826 mp
->mnt_maxsegreadsize
= ioattrp
->io_maxsegreadsize
;
827 mp
->mnt_maxsegwritesize
= ioattrp
->io_maxsegwritesize
;
828 mp
->mnt_devblocksize
= ioattrp
->io_devblocksize
;
829 mp
->mnt_ioflags
= ioattrp
->io_flags
;
830 mp
->mnt_max_swappin_available
= ioattrp
->io_max_swappin_available
;
834 * Add a new filesystem into the kernel specified in passed in
835 * vfstable structure. It fills in the vnode
836 * dispatch vector that is to be passed to when vnodes are created.
837 * It returns a handle which is to be used to when the FS is to be removed
839 typedef int (*PFI
)(void *);
840 extern int vfs_opv_numops
;
842 vfs_fsadd(struct vfs_fsentry
*vfe
, vfstable_t
*handle
)
844 struct vfstable
*newvfstbl
= NULL
;
846 int (***opv_desc_vector_p
)(void *);
847 int (**opv_desc_vector
)(void *);
848 struct vnodeopv_entry_desc
*opve_descp
;
854 * This routine is responsible for all the initialization that would
855 * ordinarily be done as part of the system startup;
858 if (vfe
== (struct vfs_fsentry
*)0)
861 desccount
= vfe
->vfe_vopcnt
;
862 if ((desccount
<=0) || ((desccount
> 8)) || (vfe
->vfe_vfsops
== (struct vfsops
*)NULL
)
863 || (vfe
->vfe_opvdescs
== (struct vnodeopv_desc
**)NULL
))
866 /* Non-threadsafe filesystems are not supported */
867 if ((vfe
->vfe_flags
& (VFS_TBLTHREADSAFE
| VFS_TBLFSNODELOCK
)) == 0) {
871 MALLOC(newvfstbl
, void *, sizeof(struct vfstable
), M_TEMP
,
873 bzero(newvfstbl
, sizeof(struct vfstable
));
874 newvfstbl
->vfc_vfsops
= vfe
->vfe_vfsops
;
875 strncpy(&newvfstbl
->vfc_name
[0], vfe
->vfe_fsname
, MFSNAMELEN
);
876 if ((vfe
->vfe_flags
& VFS_TBLNOTYPENUM
))
877 newvfstbl
->vfc_typenum
= maxvfstypenum
++;
879 newvfstbl
->vfc_typenum
= vfe
->vfe_fstypenum
;
881 newvfstbl
->vfc_refcount
= 0;
882 newvfstbl
->vfc_flags
= 0;
883 newvfstbl
->vfc_mountroot
= NULL
;
884 newvfstbl
->vfc_next
= NULL
;
885 newvfstbl
->vfc_vfsflags
= 0;
886 if (vfe
->vfe_flags
& VFS_TBL64BITREADY
)
887 newvfstbl
->vfc_vfsflags
|= VFC_VFS64BITREADY
;
888 if (vfe
->vfe_flags
& VFS_TBLVNOP_PAGEINV2
)
889 newvfstbl
->vfc_vfsflags
|= VFC_VFSVNOP_PAGEINV2
;
890 if (vfe
->vfe_flags
& VFS_TBLVNOP_PAGEOUTV2
)
891 newvfstbl
->vfc_vfsflags
|= VFC_VFSVNOP_PAGEOUTV2
;
892 if ((vfe
->vfe_flags
& VFS_TBLLOCALVOL
) == VFS_TBLLOCALVOL
)
893 newvfstbl
->vfc_flags
|= MNT_LOCAL
;
894 if ((vfe
->vfe_flags
& VFS_TBLLOCALVOL
) && (vfe
->vfe_flags
& VFS_TBLGENERICMNTARGS
) == 0)
895 newvfstbl
->vfc_vfsflags
|= VFC_VFSLOCALARGS
;
897 newvfstbl
->vfc_vfsflags
|= VFC_VFSGENERICARGS
;
899 if (vfe
->vfe_flags
& VFS_TBLNATIVEXATTR
)
900 newvfstbl
->vfc_vfsflags
|= VFC_VFSNATIVEXATTR
;
901 if (vfe
->vfe_flags
& VFS_TBLUNMOUNT_PREFLIGHT
)
902 newvfstbl
->vfc_vfsflags
|= VFC_VFSPREFLIGHT
;
903 if (vfe
->vfe_flags
& VFS_TBLREADDIR_EXTENDED
)
904 newvfstbl
->vfc_vfsflags
|= VFC_VFSREADDIR_EXTENDED
;
905 if (vfe
->vfe_flags
& VFS_TBLNOMACLABEL
)
906 newvfstbl
->vfc_vfsflags
|= VFC_VFSNOMACLABEL
;
907 if (vfe
->vfe_flags
& VFS_TBLVNOP_NOUPDATEID_RENAME
)
908 newvfstbl
->vfc_vfsflags
|= VFC_VFSVNOP_NOUPDATEID_RENAME
;
909 if (vfe
->vfe_flags
& VFS_TBLVNOP_SECLUDE_RENAME
)
910 newvfstbl
->vfc_vfsflags
|= VFC_VFSVNOP_SECLUDE_RENAME
;
911 if (vfe
->vfe_flags
& VFS_TBLCANMOUNTROOT
)
912 newvfstbl
->vfc_vfsflags
|= VFC_VFSCANMOUNTROOT
;
915 * Allocate and init the vectors.
916 * Also handle backwards compatibility.
918 * We allocate one large block to hold all <desccount>
919 * vnode operation vectors stored contiguously.
921 /* XXX - shouldn't be M_TEMP */
923 descsize
= desccount
* vfs_opv_numops
* sizeof(PFI
);
924 MALLOC(descptr
, PFI
*, descsize
,
926 bzero(descptr
, descsize
);
928 newvfstbl
->vfc_descptr
= descptr
;
929 newvfstbl
->vfc_descsize
= descsize
;
931 newvfstbl
->vfc_sysctl
= NULL
;
933 for (i
= 0; i
< desccount
; i
++ ) {
934 opv_desc_vector_p
= vfe
->vfe_opvdescs
[i
]->opv_desc_vector_p
;
936 * Fill in the caller's pointer to the start of the i'th vector.
937 * They'll need to supply it when calling vnode_create.
939 opv_desc_vector
= descptr
+ i
* vfs_opv_numops
;
940 *opv_desc_vector_p
= opv_desc_vector
;
942 for (j
= 0; vfe
->vfe_opvdescs
[i
]->opv_desc_ops
[j
].opve_op
; j
++) {
943 opve_descp
= &(vfe
->vfe_opvdescs
[i
]->opv_desc_ops
[j
]);
945 /* Silently skip known-disabled operations */
946 if (opve_descp
->opve_op
->vdesc_flags
& VDESC_DISABLED
) {
947 printf("vfs_fsadd: Ignoring reference in %p to disabled operation %s.\n",
948 vfe
->vfe_opvdescs
[i
], opve_descp
->opve_op
->vdesc_name
);
953 * Sanity check: is this operation listed
954 * in the list of operations? We check this
955 * by seeing if its offset is zero. Since
956 * the default routine should always be listed
957 * first, it should be the only one with a zero
958 * offset. Any other operation with a zero
959 * offset is probably not listed in
960 * vfs_op_descs, and so is probably an error.
962 * A panic here means the layer programmer
963 * has committed the all-too common bug
964 * of adding a new operation to the layer's
965 * list of vnode operations but
966 * not adding the operation to the system-wide
967 * list of supported operations.
969 if (opve_descp
->opve_op
->vdesc_offset
== 0 &&
970 opve_descp
->opve_op
!= VDESC(vnop_default
)) {
971 printf("vfs_fsadd: operation %s not listed in %s.\n",
972 opve_descp
->opve_op
->vdesc_name
,
974 panic("vfs_fsadd: bad operation");
977 * Fill in this entry.
979 opv_desc_vector
[opve_descp
->opve_op
->vdesc_offset
] =
980 opve_descp
->opve_impl
;
985 * Finally, go back and replace unfilled routines
986 * with their default. (Sigh, an O(n^3) algorithm. I
987 * could make it better, but that'd be work, and n is small.)
989 opv_desc_vector_p
= vfe
->vfe_opvdescs
[i
]->opv_desc_vector_p
;
992 * Force every operations vector to have a default routine.
994 opv_desc_vector
= *opv_desc_vector_p
;
995 if (opv_desc_vector
[VOFFSET(vnop_default
)] == NULL
)
996 panic("vfs_fsadd: operation vector without default routine.");
997 for (j
= 0; j
< vfs_opv_numops
; j
++)
998 if (opv_desc_vector
[j
] == NULL
)
1000 opv_desc_vector
[VOFFSET(vnop_default
)];
1002 } /* end of each vnodeopv_desc parsing */
1006 *handle
= vfstable_add(newvfstbl
);
1008 if (newvfstbl
->vfc_typenum
<= maxvfstypenum
)
1009 maxvfstypenum
= newvfstbl
->vfc_typenum
+ 1;
1011 if (newvfstbl
->vfc_vfsops
->vfs_init
) {
1012 struct vfsconf vfsc
;
1013 bzero(&vfsc
, sizeof(struct vfsconf
));
1014 vfsc
.vfc_reserved1
= 0;
1015 bcopy((*handle
)->vfc_name
, vfsc
.vfc_name
, sizeof(vfsc
.vfc_name
));
1016 vfsc
.vfc_typenum
= (*handle
)->vfc_typenum
;
1017 vfsc
.vfc_refcount
= (*handle
)->vfc_refcount
;
1018 vfsc
.vfc_flags
= (*handle
)->vfc_flags
;
1019 vfsc
.vfc_reserved2
= 0;
1020 vfsc
.vfc_reserved3
= 0;
1022 (*newvfstbl
->vfc_vfsops
->vfs_init
)(&vfsc
);
1025 FREE(newvfstbl
, M_TEMP
);
1031 * Removes the filesystem from kernel.
1032 * The argument passed in is the handle that was given when
1033 * file system was added
1036 vfs_fsremove(vfstable_t handle
)
1038 struct vfstable
* vfstbl
= (struct vfstable
*)handle
;
1039 void *old_desc
= NULL
;
1042 /* Preflight check for any mounts */
1044 if ( vfstbl
->vfc_refcount
!= 0 ) {
1045 mount_list_unlock();
1050 * save the old descriptor; the free cannot occur unconditionally,
1051 * since vfstable_del() may fail.
1053 if (vfstbl
->vfc_descptr
&& vfstbl
->vfc_descsize
) {
1054 old_desc
= vfstbl
->vfc_descptr
;
1056 err
= vfstable_del(vfstbl
);
1058 mount_list_unlock();
1060 /* free the descriptor if the delete was successful */
1061 if (err
== 0 && old_desc
) {
1062 FREE(old_desc
, M_TEMP
);
1068 void vfs_setowner(mount_t mp
, uid_t uid
, gid_t gid
)
1070 mp
->mnt_fsowner
= uid
;
1071 mp
->mnt_fsgroup
= gid
;
1075 * Callers should be careful how they use this; accessing
1076 * mnt_last_write_completed_timestamp is not thread-safe. Writing to
1077 * it isn't either. Point is: be prepared to deal with strange values
1080 uint64_t vfs_idle_time(mount_t mp
)
1082 if (mp
->mnt_pending_write_size
)
1090 - mp
->mnt_last_write_completed_timestamp
.tv_sec
) * 1000000
1091 + now
.tv_usec
- mp
->mnt_last_write_completed_timestamp
.tv_usec
);
1095 vfs_context_pid(vfs_context_t ctx
)
1097 return (proc_pid(vfs_context_proc(ctx
)));
1101 vfs_context_suser(vfs_context_t ctx
)
1103 return (suser(ctx
->vc_ucred
, NULL
));
1107 * Return bit field of signals posted to all threads in the context's process.
1109 * XXX Signals should be tied to threads, not processes, for most uses of this
1113 vfs_context_issignal(vfs_context_t ctx
, sigset_t mask
)
1115 proc_t p
= vfs_context_proc(ctx
);
1117 return(proc_pendingsignals(p
, mask
));
1122 vfs_context_is64bit(vfs_context_t ctx
)
1124 proc_t proc
= vfs_context_proc(ctx
);
1127 return(proc_is64bit(proc
));
1135 * Description: Given a vfs_context_t, return the proc_t associated with it.
1137 * Parameters: vfs_context_t The context to use
1139 * Returns: proc_t The process for this context
1141 * Notes: This function will return the current_proc() if any of the
1142 * following conditions are true:
1144 * o The supplied context pointer is NULL
1145 * o There is no Mach thread associated with the context
1146 * o There is no Mach task associated with the Mach thread
1147 * o There is no proc_t associated with the Mach task
1148 * o The proc_t has no per process open file table
1149 * o The proc_t is post-vfork()
1151 * This causes this function to return a value matching as
1152 * closely as possible the previous behaviour, while at the
1153 * same time avoiding the task lending that results from vfork()
1156 vfs_context_proc(vfs_context_t ctx
)
1160 if (ctx
!= NULL
&& ctx
->vc_thread
!= NULL
)
1161 proc
= (proc_t
)get_bsdthreadtask_info(ctx
->vc_thread
);
1162 if (proc
!= NULL
&& (proc
->p_fd
== NULL
|| (proc
->p_lflag
& P_LVFORK
)))
1165 return(proc
== NULL
? current_proc() : proc
);
1169 * vfs_context_get_special_port
1171 * Description: Return the requested special port from the task associated
1172 * with the given context.
1174 * Parameters: vfs_context_t The context to use
1175 * int Index of special port
1176 * ipc_port_t * Pointer to returned port
1178 * Returns: kern_return_t see task_get_special_port()
1181 vfs_context_get_special_port(vfs_context_t ctx
, int which
, ipc_port_t
*portp
)
1185 if (ctx
!= NULL
&& ctx
->vc_thread
!= NULL
)
1186 task
= get_threadtask(ctx
->vc_thread
);
1188 return task_get_special_port(task
, which
, portp
);
1192 * vfs_context_set_special_port
1194 * Description: Set the requested special port in the task associated
1195 * with the given context.
1197 * Parameters: vfs_context_t The context to use
1198 * int Index of special port
1199 * ipc_port_t New special port
1201 * Returns: kern_return_t see task_set_special_port()
1204 vfs_context_set_special_port(vfs_context_t ctx
, int which
, ipc_port_t port
)
1208 if (ctx
!= NULL
&& ctx
->vc_thread
!= NULL
)
1209 task
= get_threadtask(ctx
->vc_thread
);
1211 return task_set_special_port(task
, which
, port
);
1215 * vfs_context_thread
1217 * Description: Return the Mach thread associated with a vfs_context_t
1219 * Parameters: vfs_context_t The context to use
1221 * Returns: thread_t The thread for this context, or
1222 * NULL, if there is not one.
1224 * Notes: NULL thread_t's are legal, but discouraged. They occur only
1225 * as a result of a static vfs_context_t declaration in a function
1226 * and will result in this function returning NULL.
1228 * This is intentional; this function should NOT return the
1229 * current_thread() in this case.
1232 vfs_context_thread(vfs_context_t ctx
)
1234 return(ctx
->vc_thread
);
1241 * Description: Returns a reference on the vnode for the current working
1242 * directory for the supplied context
1244 * Parameters: vfs_context_t The context to use
1246 * Returns: vnode_t The current working directory
1249 * Notes: The function first attempts to obtain the current directory
1250 * from the thread, and if it is not present there, falls back
1251 * to obtaining it from the process instead. If it can't be
1252 * obtained from either place, we return NULLVP.
1255 vfs_context_cwd(vfs_context_t ctx
)
1257 vnode_t cwd
= NULLVP
;
1259 if(ctx
!= NULL
&& ctx
->vc_thread
!= NULL
) {
1260 uthread_t uth
= get_bsdthread_info(ctx
->vc_thread
);
1264 * Get the cwd from the thread; if there isn't one, get it
1265 * from the process, instead.
1267 if ((cwd
= uth
->uu_cdir
) == NULLVP
&&
1268 (proc
= (proc_t
)get_bsdthreadtask_info(ctx
->vc_thread
)) != NULL
&&
1270 cwd
= proc
->p_fd
->fd_cdir
;
1277 * vfs_context_create
1279 * Description: Allocate and initialize a new context.
1281 * Parameters: vfs_context_t: Context to copy, or NULL for new
1283 * Returns: Pointer to new context
1285 * Notes: Copy cred and thread from argument, if available; else
1286 * initialize with current thread and new cred. Returns
1287 * with a reference held on the credential.
1290 vfs_context_create(vfs_context_t ctx
)
1292 vfs_context_t newcontext
;
1294 newcontext
= (vfs_context_t
)kalloc(sizeof(struct vfs_context
));
1297 kauth_cred_t safecred
;
1299 newcontext
->vc_thread
= ctx
->vc_thread
;
1300 safecred
= ctx
->vc_ucred
;
1302 newcontext
->vc_thread
= current_thread();
1303 safecred
= kauth_cred_get();
1305 if (IS_VALID_CRED(safecred
))
1306 kauth_cred_ref(safecred
);
1307 newcontext
->vc_ucred
= safecred
;
1315 vfs_context_current(void)
1317 vfs_context_t ctx
= NULL
;
1318 volatile uthread_t ut
= (uthread_t
)get_bsdthread_info(current_thread());
1321 if (ut
->uu_context
.vc_ucred
!= NULL
) {
1322 ctx
= &ut
->uu_context
;
1326 return(ctx
== NULL
? vfs_context_kernel() : ctx
);
1333 * Dangerous hack - adopt the first kernel thread as the current thread, to
1334 * get to the vfs_context_t in the uthread associated with a kernel thread.
1335 * This is used by UDF to make the call into IOCDMediaBSDClient,
1336 * IOBDMediaBSDClient, and IODVDMediaBSDClient to determine whether the
1337 * ioctl() is being called from kernel or user space (and all this because
1338 * we do not pass threads into our ioctl()'s, instead of processes).
1340 * This is also used by imageboot_setup(), called early from bsd_init() after
1341 * kernproc has been given a credential.
1343 * Note: The use of proc_thread() here is a convenience to avoid inclusion
1344 * of many Mach headers to do the reference directly rather than indirectly;
1345 * we will need to forego this convenience when we reture proc_thread().
1347 static struct vfs_context kerncontext
;
1349 vfs_context_kernel(void)
1351 if (kerncontext
.vc_ucred
== NOCRED
)
1352 kerncontext
.vc_ucred
= kernproc
->p_ucred
;
1353 if (kerncontext
.vc_thread
== NULL
)
1354 kerncontext
.vc_thread
= proc_thread(kernproc
);
1356 return(&kerncontext
);
1361 vfs_context_rele(vfs_context_t ctx
)
1364 if (IS_VALID_CRED(ctx
->vc_ucred
))
1365 kauth_cred_unref(&ctx
->vc_ucred
);
1366 kfree(ctx
, sizeof(struct vfs_context
));
1373 vfs_context_ucred(vfs_context_t ctx
)
1375 return (ctx
->vc_ucred
);
1379 * Return true if the context is owned by the superuser.
1382 vfs_context_issuser(vfs_context_t ctx
)
1384 return(kauth_cred_issuser(vfs_context_ucred(ctx
)));
1387 int vfs_context_iskernel(vfs_context_t ctx
)
1389 return ctx
== &kerncontext
;
1393 * Given a context, for all fields of vfs_context_t which
1394 * are not held with a reference, set those fields to the
1395 * values for the current execution context. Currently, this
1396 * just means the vc_thread.
1398 * Returns: 0 for success, nonzero for failure
1400 * The intended use is:
1401 * 1. vfs_context_create() gets the caller a context
1402 * 2. vfs_context_bind() sets the unrefcounted data
1403 * 3. vfs_context_rele() releases the context
1407 vfs_context_bind(vfs_context_t ctx
)
1409 ctx
->vc_thread
= current_thread();
1413 int vfs_isswapmount(mount_t mnt
)
1415 return mnt
&& ISSET(mnt
->mnt_kern_flag
, MNTK_SWAP_MOUNT
) ? 1 : 0;
1418 /* XXXXXXXXXXXXXX VNODE KAPIS XXXXXXXXXXXXXXXXXXXXXXXXX */
1422 * Convert between vnode types and inode formats (since POSIX.1
1423 * defines mode word of stat structure in terms of inode formats).
1426 vnode_iftovt(int mode
)
1428 return(iftovt_tab
[((mode
) & S_IFMT
) >> 12]);
1432 vnode_vttoif(enum vtype indx
)
1434 return(vttoif_tab
[(int)(indx
)]);
1438 vnode_makeimode(int indx
, int mode
)
1440 return (int)(VTTOIF(indx
) | (mode
));
1445 * vnode manipulation functions.
1448 /* returns system root vnode iocount; It should be released using vnode_put() */
1454 error
= vnode_get(rootvnode
);
1456 return ((vnode_t
)0);
1463 vnode_vid(vnode_t vp
)
1465 return ((uint32_t)(vp
->v_id
));
1469 vnode_mount(vnode_t vp
)
1471 return (vp
->v_mount
);
1476 vnode_mountdevvp(vnode_t vp
)
1479 return (vp
->v_mount
->mnt_devvp
);
1481 return ((vnode_t
)0);
1486 vnode_mountedhere(vnode_t vp
)
1490 if ((vp
->v_type
== VDIR
) && ((mp
= vp
->v_mountedhere
) != NULL
) &&
1491 (mp
->mnt_vnodecovered
== vp
))
1494 return (mount_t
)NULL
;
1497 /* returns vnode type of vnode_t */
1499 vnode_vtype(vnode_t vp
)
1501 return (vp
->v_type
);
1504 /* returns FS specific node saved in vnode */
1506 vnode_fsnode(vnode_t vp
)
1508 return (vp
->v_data
);
1512 vnode_clearfsnode(vnode_t vp
)
1518 vnode_specrdev(vnode_t vp
)
1524 /* Accessor functions */
1525 /* is vnode_t a root vnode */
1527 vnode_isvroot(vnode_t vp
)
1529 return ((vp
->v_flag
& VROOT
)? 1 : 0);
1532 /* is vnode_t a system vnode */
1534 vnode_issystem(vnode_t vp
)
1536 return ((vp
->v_flag
& VSYSTEM
)? 1 : 0);
1539 /* is vnode_t a swap file vnode */
1541 vnode_isswap(vnode_t vp
)
1543 return ((vp
->v_flag
& VSWAP
)? 1 : 0);
1546 /* is vnode_t a tty */
1548 vnode_istty(vnode_t vp
)
1550 return ((vp
->v_flag
& VISTTY
) ? 1 : 0);
1553 /* if vnode_t mount operation in progress */
1555 vnode_ismount(vnode_t vp
)
1557 return ((vp
->v_flag
& VMOUNT
)? 1 : 0);
1560 /* is this vnode under recyle now */
1562 vnode_isrecycled(vnode_t vp
)
1566 vnode_lock_spin(vp
);
1567 ret
= (vp
->v_lflag
& (VL_TERMINATE
|VL_DEAD
))? 1 : 0;
1572 /* vnode was created by background task requesting rapid aging
1573 and has not since been referenced by a normal task */
1575 vnode_israge(vnode_t vp
)
1577 return ((vp
->v_flag
& VRAGE
)? 1 : 0);
1581 vnode_needssnapshots(vnode_t vp
)
1583 return ((vp
->v_flag
& VNEEDSSNAPSHOT
)? 1 : 0);
1587 /* Check the process/thread to see if we should skip atime updates */
1589 vfs_ctx_skipatime (vfs_context_t ctx
) {
1594 proc
= vfs_context_proc(ctx
);
1595 thr
= vfs_context_thread (ctx
);
1597 /* Validate pointers in case we were invoked via a kernel context */
1599 ut
= get_bsdthread_info (thr
);
1601 if (proc
->p_lflag
& P_LRAGE_VNODES
) {
1606 if (ut
->uu_flag
& (UT_RAGE_VNODES
| UT_ATIME_UPDATE
)) {
1611 if (proc
->p_vfs_iopolicy
& P_VFS_IOPOLICY_ATIME_UPDATES
) {
1618 /* is vnode_t marked to not keep data cached once it's been consumed */
1620 vnode_isnocache(vnode_t vp
)
1622 return ((vp
->v_flag
& VNOCACHE_DATA
)? 1 : 0);
1626 * has sequential readahead been disabled on this vnode
1629 vnode_isnoreadahead(vnode_t vp
)
1631 return ((vp
->v_flag
& VRAOFF
)? 1 : 0);
1635 vnode_is_openevt(vnode_t vp
)
1637 return ((vp
->v_flag
& VOPENEVT
)? 1 : 0);
1640 /* is vnode_t a standard one? */
1642 vnode_isstandard(vnode_t vp
)
1644 return ((vp
->v_flag
& VSTANDARD
)? 1 : 0);
1647 /* don't vflush() if SKIPSYSTEM */
1649 vnode_isnoflush(vnode_t vp
)
1651 return ((vp
->v_flag
& VNOFLUSH
)? 1 : 0);
1654 /* is vnode_t a regular file */
1656 vnode_isreg(vnode_t vp
)
1658 return ((vp
->v_type
== VREG
)? 1 : 0);
1661 /* is vnode_t a directory? */
1663 vnode_isdir(vnode_t vp
)
1665 return ((vp
->v_type
== VDIR
)? 1 : 0);
1668 /* is vnode_t a symbolic link ? */
1670 vnode_islnk(vnode_t vp
)
1672 return ((vp
->v_type
== VLNK
)? 1 : 0);
1676 vnode_lookup_continue_needed(vnode_t vp
, struct componentname
*cnp
)
1678 struct nameidata
*ndp
= cnp
->cn_ndp
;
1681 panic("vnode_lookup_continue_needed(): cnp->cn_ndp is NULL\n");
1684 if (vnode_isdir(vp
)) {
1685 if (vp
->v_mountedhere
!= NULL
) {
1690 if (vp
->v_resolve
) {
1693 #endif /* CONFIG_TRIGGERS */
1698 if (vnode_islnk(vp
)) {
1699 /* From lookup(): || *ndp->ni_next == '/') No need for this, we know we're NULL-terminated here */
1700 if (cnp
->cn_flags
& FOLLOW
) {
1703 if (ndp
->ni_flag
& NAMEI_TRAILINGSLASH
) {
1711 ndp
->ni_flag
|= NAMEI_CONTLOOKUP
;
1712 return EKEEPLOOKING
;
1715 /* is vnode_t a fifo ? */
1717 vnode_isfifo(vnode_t vp
)
1719 return ((vp
->v_type
== VFIFO
)? 1 : 0);
1722 /* is vnode_t a block device? */
1724 vnode_isblk(vnode_t vp
)
1726 return ((vp
->v_type
== VBLK
)? 1 : 0);
1730 vnode_isspec(vnode_t vp
)
1732 return (((vp
->v_type
== VCHR
) || (vp
->v_type
== VBLK
)) ? 1 : 0);
1735 /* is vnode_t a char device? */
1737 vnode_ischr(vnode_t vp
)
1739 return ((vp
->v_type
== VCHR
)? 1 : 0);
1742 /* is vnode_t a socket? */
1744 vnode_issock(vnode_t vp
)
1746 return ((vp
->v_type
== VSOCK
)? 1 : 0);
1749 /* is vnode_t a device with multiple active vnodes referring to it? */
1751 vnode_isaliased(vnode_t vp
)
1753 enum vtype vt
= vp
->v_type
;
1754 if (!((vt
== VCHR
) || (vt
== VBLK
))) {
1757 return (vp
->v_specflags
& SI_ALIASED
);
1761 /* is vnode_t a named stream? */
1763 vnode_isnamedstream(
1772 return ((vp
->v_flag
& VISNAMEDSTREAM
) ? 1 : 0);
1788 return ((vp
->v_flag
& VISSHADOW
) ? 1 : 0);
1794 /* does vnode have associated named stream vnodes ? */
1796 vnode_hasnamedstreams(
1805 return ((vp
->v_lflag
& VL_HASSTREAMS
) ? 1 : 0);
1810 /* TBD: set vnode_t to not cache data after it is consumed once; used for quota */
1812 vnode_setnocache(vnode_t vp
)
1814 vnode_lock_spin(vp
);
1815 vp
->v_flag
|= VNOCACHE_DATA
;
1820 vnode_clearnocache(vnode_t vp
)
1822 vnode_lock_spin(vp
);
1823 vp
->v_flag
&= ~VNOCACHE_DATA
;
1828 vnode_set_openevt(vnode_t vp
)
1830 vnode_lock_spin(vp
);
1831 vp
->v_flag
|= VOPENEVT
;
1836 vnode_clear_openevt(vnode_t vp
)
1838 vnode_lock_spin(vp
);
1839 vp
->v_flag
&= ~VOPENEVT
;
1845 vnode_setnoreadahead(vnode_t vp
)
1847 vnode_lock_spin(vp
);
1848 vp
->v_flag
|= VRAOFF
;
1853 vnode_clearnoreadahead(vnode_t vp
)
1855 vnode_lock_spin(vp
);
1856 vp
->v_flag
&= ~VRAOFF
;
1861 vnode_isfastdevicecandidate(vnode_t vp
)
1863 return ((vp
->v_flag
& VFASTDEVCANDIDATE
)? 1 : 0);
1867 vnode_setfastdevicecandidate(vnode_t vp
)
1869 vnode_lock_spin(vp
);
1870 vp
->v_flag
|= VFASTDEVCANDIDATE
;
1875 vnode_clearfastdevicecandidate(vnode_t vp
)
1877 vnode_lock_spin(vp
);
1878 vp
->v_flag
&= ~VFASTDEVCANDIDATE
;
1883 vnode_isautocandidate(vnode_t vp
)
1885 return ((vp
->v_flag
& VAUTOCANDIDATE
)? 1 : 0);
1889 vnode_setautocandidate(vnode_t vp
)
1891 vnode_lock_spin(vp
);
1892 vp
->v_flag
|= VAUTOCANDIDATE
;
1897 vnode_clearautocandidate(vnode_t vp
)
1899 vnode_lock_spin(vp
);
1900 vp
->v_flag
&= ~VAUTOCANDIDATE
;
1907 /* mark vnode_t to skip vflush() is SKIPSYSTEM */
1909 vnode_setnoflush(vnode_t vp
)
1911 vnode_lock_spin(vp
);
1912 vp
->v_flag
|= VNOFLUSH
;
1917 vnode_clearnoflush(vnode_t vp
)
1919 vnode_lock_spin(vp
);
1920 vp
->v_flag
&= ~VNOFLUSH
;
1925 /* is vnode_t a blkdevice and has a FS mounted on it */
1927 vnode_ismountedon(vnode_t vp
)
1929 return ((vp
->v_specflags
& SI_MOUNTEDON
)? 1 : 0);
1933 vnode_setmountedon(vnode_t vp
)
1935 vnode_lock_spin(vp
);
1936 vp
->v_specflags
|= SI_MOUNTEDON
;
1941 vnode_clearmountedon(vnode_t vp
)
1943 vnode_lock_spin(vp
);
1944 vp
->v_specflags
&= ~SI_MOUNTEDON
;
1950 vnode_settag(vnode_t vp
, int tag
)
1957 vnode_tag(vnode_t vp
)
1963 vnode_parent(vnode_t vp
)
1966 return(vp
->v_parent
);
1970 vnode_setparent(vnode_t vp
, vnode_t dvp
)
1976 vnode_setname(vnode_t vp
, char * name
)
1981 /* return the registered FS name when adding the FS to kernel */
1983 vnode_vfsname(vnode_t vp
, char * buf
)
1985 strlcpy(buf
, vp
->v_mount
->mnt_vtable
->vfc_name
, MFSNAMELEN
);
1988 /* return the FS type number */
1990 vnode_vfstypenum(vnode_t vp
)
1992 return(vp
->v_mount
->mnt_vtable
->vfc_typenum
);
1996 vnode_vfs64bitready(vnode_t vp
)
2000 * Checking for dead_mountp is a bit of a hack for SnowLeopard: <rdar://problem/6269051>
2002 if ((vp
->v_mount
!= dead_mountp
) && (vp
->v_mount
->mnt_vtable
->vfc_vfsflags
& VFC_VFS64BITREADY
))
2010 /* return the visible flags on associated mount point of vnode_t */
2012 vnode_vfsvisflags(vnode_t vp
)
2014 return(vp
->v_mount
->mnt_flag
& MNT_VISFLAGMASK
);
2017 /* return the command modifier flags on associated mount point of vnode_t */
2019 vnode_vfscmdflags(vnode_t vp
)
2021 return(vp
->v_mount
->mnt_flag
& MNT_CMDFLAGS
);
2024 /* return the max symlink of short links of vnode_t */
2026 vnode_vfsmaxsymlen(vnode_t vp
)
2028 return(vp
->v_mount
->mnt_maxsymlinklen
);
2031 /* return a pointer to the RO vfs_statfs associated with vnode_t's mount point */
2033 vnode_vfsstatfs(vnode_t vp
)
2035 return(&vp
->v_mount
->mnt_vfsstat
);
2038 /* return a handle to the FSs specific private handle associated with vnode_t's mount point */
2040 vnode_vfsfsprivate(vnode_t vp
)
2042 return(vp
->v_mount
->mnt_data
);
2045 /* is vnode_t in a rdonly mounted FS */
2047 vnode_vfsisrdonly(vnode_t vp
)
2049 return ((vp
->v_mount
->mnt_flag
& MNT_RDONLY
)? 1 : 0);
2053 vnode_compound_rename_available(vnode_t vp
)
2055 return vnode_compound_op_available(vp
, COMPOUND_VNOP_RENAME
);
2058 vnode_compound_rmdir_available(vnode_t vp
)
2060 return vnode_compound_op_available(vp
, COMPOUND_VNOP_RMDIR
);
2063 vnode_compound_mkdir_available(vnode_t vp
)
2065 return vnode_compound_op_available(vp
, COMPOUND_VNOP_MKDIR
);
2068 vnode_compound_remove_available(vnode_t vp
)
2070 return vnode_compound_op_available(vp
, COMPOUND_VNOP_REMOVE
);
2073 vnode_compound_open_available(vnode_t vp
)
2075 return vnode_compound_op_available(vp
, COMPOUND_VNOP_OPEN
);
2079 vnode_compound_op_available(vnode_t vp
, compound_vnop_id_t opid
)
2081 return ((vp
->v_mount
->mnt_compound_ops
& opid
) != 0);
2085 * Returns vnode ref to current working directory; if a per-thread current
2086 * working directory is in effect, return that instead of the per process one.
2088 * XXX Published, but not used.
2091 current_workingdir(void)
2093 return vfs_context_cwd(vfs_context_current());
2096 /* returns vnode ref to current root(chroot) directory */
2098 current_rootdir(void)
2100 proc_t proc
= current_proc();
2103 if ( (vp
= proc
->p_fd
->fd_rdir
) ) {
2104 if ( (vnode_getwithref(vp
)) )
2111 * Get a filesec and optional acl contents from an extended attribute.
2112 * Function will attempt to retrive ACL, UUID, and GUID information using a
2113 * read of a named extended attribute (KAUTH_FILESEC_XATTR).
2115 * Parameters: vp The vnode on which to operate.
2116 * fsecp The filesec (and ACL, if any) being
2118 * ctx The vnode context in which the
2119 * operation is to be attempted.
2121 * Returns: 0 Success
2124 * Notes: The kauth_filesec_t in '*fsecp', if retrieved, will be in
2125 * host byte order, as will be the ACL contents, if any.
2126 * Internally, we will cannonize these values from network (PPC)
2127 * byte order after we retrieve them so that the on-disk contents
2128 * of the extended attribute are identical for both PPC and Intel
2129 * (if we were not being required to provide this service via
2130 * fallback, this would be the job of the filesystem
2131 * 'VNOP_GETATTR' call).
2133 * We use ntohl() because it has a transitive property on Intel
2134 * machines and no effect on PPC mancines. This guarantees us
2136 * XXX: Deleting rather than ignoreing a corrupt security structure is
2137 * probably the only way to reset it without assistance from an
2138 * file system integrity checking tool. Right now we ignore it.
2140 * XXX: We should enummerate the possible errno values here, and where
2141 * in the code they originated.
2144 vnode_get_filesec(vnode_t vp
, kauth_filesec_t
*fsecp
, vfs_context_t ctx
)
2146 kauth_filesec_t fsec
;
2149 size_t xsize
, rsize
;
2151 uint32_t host_fsec_magic
;
2152 uint32_t host_acl_entrycount
;
2157 /* find out how big the EA is */
2158 error
= vn_getxattr(vp
, KAUTH_FILESEC_XATTR
, NULL
, &xsize
, XATTR_NOSECURITY
, ctx
);
2160 /* no EA, no filesec */
2161 if ((error
== ENOATTR
) || (error
== ENOENT
) || (error
== EJUSTRETURN
))
2163 /* either way, we are done */
2168 * To be valid, a kauth_filesec_t must be large enough to hold a zero
2169 * ACE entrly ACL, and if it's larger than that, it must have the right
2170 * number of bytes such that it contains an atomic number of ACEs,
2171 * rather than partial entries. Otherwise, we ignore it.
2173 if (!KAUTH_FILESEC_VALID(xsize
)) {
2174 KAUTH_DEBUG(" ERROR - Bogus kauth_fiilesec_t: %ld bytes", xsize
);
2179 /* how many entries would fit? */
2180 fsec_size
= KAUTH_FILESEC_COUNT(xsize
);
2181 if (fsec_size
> KAUTH_ACL_MAX_ENTRIES
) {
2182 KAUTH_DEBUG(" ERROR - Bogus (too large) kauth_fiilesec_t: %ld bytes", xsize
);
2187 /* get buffer and uio */
2188 if (((fsec
= kauth_filesec_alloc(fsec_size
)) == NULL
) ||
2189 ((fsec_uio
= uio_create(1, 0, UIO_SYSSPACE
, UIO_READ
)) == NULL
) ||
2190 uio_addiov(fsec_uio
, CAST_USER_ADDR_T(fsec
), xsize
)) {
2191 KAUTH_DEBUG(" ERROR - could not allocate iov to read ACL");
2196 /* read security attribute */
2198 if ((error
= vn_getxattr(vp
,
2199 KAUTH_FILESEC_XATTR
,
2205 /* no attribute - no security data */
2206 if ((error
== ENOATTR
) || (error
== ENOENT
) || (error
== EJUSTRETURN
))
2208 /* either way, we are done */
2213 * Validate security structure; the validation must take place in host
2214 * byte order. If it's corrupt, we will just ignore it.
2217 /* Validate the size before trying to convert it */
2218 if (rsize
< KAUTH_FILESEC_SIZE(0)) {
2219 KAUTH_DEBUG("ACL - DATA TOO SMALL (%d)", rsize
);
2223 /* Validate the magic number before trying to convert it */
2224 host_fsec_magic
= ntohl(KAUTH_FILESEC_MAGIC
);
2225 if (fsec
->fsec_magic
!= host_fsec_magic
) {
2226 KAUTH_DEBUG("ACL - BAD MAGIC %x", host_fsec_magic
);
2230 /* Validate the entry count before trying to convert it. */
2231 host_acl_entrycount
= ntohl(fsec
->fsec_acl
.acl_entrycount
);
2232 if (host_acl_entrycount
!= KAUTH_FILESEC_NOACL
) {
2233 if (host_acl_entrycount
> KAUTH_ACL_MAX_ENTRIES
) {
2234 KAUTH_DEBUG("ACL - BAD ENTRYCOUNT %x", host_acl_entrycount
);
2237 if (KAUTH_FILESEC_SIZE(host_acl_entrycount
) > rsize
) {
2238 KAUTH_DEBUG("ACL - BUFFER OVERFLOW (%d entries too big for %d)", host_acl_entrycount
, rsize
);
2243 kauth_filesec_acl_setendian(KAUTH_ENDIAN_HOST
, fsec
, NULL
);
2250 kauth_filesec_free(fsec
);
2251 if (fsec_uio
!= NULL
)
2259 * Set a filesec and optional acl contents into an extended attribute.
2260 * function will attempt to store ACL, UUID, and GUID information using a
2261 * write to a named extended attribute (KAUTH_FILESEC_XATTR). The 'acl'
2262 * may or may not point to the `fsec->fsec_acl`, depending on whether the
2263 * original caller supplied an acl.
2265 * Parameters: vp The vnode on which to operate.
2266 * fsec The filesec being set.
2267 * acl The acl to be associated with 'fsec'.
2268 * ctx The vnode context in which the
2269 * operation is to be attempted.
2271 * Returns: 0 Success
2274 * Notes: Both the fsec and the acl are always valid.
2276 * The kauth_filesec_t in 'fsec', if any, is in host byte order,
2277 * as are the acl contents, if they are used. Internally, we will
2278 * cannonize these values into network (PPC) byte order before we
2279 * attempt to write them so that the on-disk contents of the
2280 * extended attribute are identical for both PPC and Intel (if we
2281 * were not being required to provide this service via fallback,
2282 * this would be the job of the filesystem 'VNOP_SETATTR' call).
2283 * We reverse this process on the way out, so we leave with the
2284 * same byte order we started with.
2286 * XXX: We should enummerate the possible errno values here, and where
2287 * in the code they originated.
2290 vnode_set_filesec(vnode_t vp
, kauth_filesec_t fsec
, kauth_acl_t acl
, vfs_context_t ctx
)
2294 uint32_t saved_acl_copysize
;
2298 if ((fsec_uio
= uio_create(2, 0, UIO_SYSSPACE
, UIO_WRITE
)) == NULL
) {
2299 KAUTH_DEBUG(" ERROR - could not allocate iov to write ACL");
2304 * Save the pre-converted ACL copysize, because it gets swapped too
2305 * if we are running with the wrong endianness.
2307 saved_acl_copysize
= KAUTH_ACL_COPYSIZE(acl
);
2309 kauth_filesec_acl_setendian(KAUTH_ENDIAN_DISK
, fsec
, acl
);
2311 uio_addiov(fsec_uio
, CAST_USER_ADDR_T(fsec
), KAUTH_FILESEC_SIZE(0) - KAUTH_ACL_SIZE(KAUTH_FILESEC_NOACL
));
2312 uio_addiov(fsec_uio
, CAST_USER_ADDR_T(acl
), saved_acl_copysize
);
2313 error
= vn_setxattr(vp
,
2314 KAUTH_FILESEC_XATTR
,
2316 XATTR_NOSECURITY
, /* we have auth'ed already */
2318 VFS_DEBUG(ctx
, vp
, "SETATTR - set ACL returning %d", error
);
2320 kauth_filesec_acl_setendian(KAUTH_ENDIAN_HOST
, fsec
, acl
);
2323 if (fsec_uio
!= NULL
)
2330 * Returns: 0 Success
2331 * ENOMEM Not enough space [only if has filesec]
2332 * EINVAL Requested unknown attributes
2334 * vnode_get_filesec: ???
2335 * kauth_cred_guid2uid: ???
2336 * kauth_cred_guid2gid: ???
2337 * vfs_update_vfsstat: ???
2340 vnode_getattr(vnode_t vp
, struct vnode_attr
*vap
, vfs_context_t ctx
)
2342 kauth_filesec_t fsec
;
2349 * Reject attempts to fetch unknown attributes.
2351 if (vap
->va_active
& ~VNODE_ATTR_ALL
)
2354 /* don't ask for extended security data if the filesystem doesn't support it */
2355 if (!vfs_extendedsecurity(vnode_mount(vp
))) {
2356 VATTR_CLEAR_ACTIVE(vap
, va_acl
);
2357 VATTR_CLEAR_ACTIVE(vap
, va_uuuid
);
2358 VATTR_CLEAR_ACTIVE(vap
, va_guuid
);
2362 * If the caller wants size values we might have to synthesise, give the
2363 * filesystem the opportunity to supply better intermediate results.
2365 if (VATTR_IS_ACTIVE(vap
, va_data_alloc
) ||
2366 VATTR_IS_ACTIVE(vap
, va_total_size
) ||
2367 VATTR_IS_ACTIVE(vap
, va_total_alloc
)) {
2368 VATTR_SET_ACTIVE(vap
, va_data_size
);
2369 VATTR_SET_ACTIVE(vap
, va_data_alloc
);
2370 VATTR_SET_ACTIVE(vap
, va_total_size
);
2371 VATTR_SET_ACTIVE(vap
, va_total_alloc
);
2374 error
= VNOP_GETATTR(vp
, vap
, ctx
);
2376 KAUTH_DEBUG("ERROR - returning %d", error
);
2381 * If extended security data was requested but not returned, try the fallback
2384 if (VATTR_NOT_RETURNED(vap
, va_acl
) || VATTR_NOT_RETURNED(vap
, va_uuuid
) || VATTR_NOT_RETURNED(vap
, va_guuid
)) {
2387 if (XATTR_VNODE_SUPPORTED(vp
)) {
2388 /* try to get the filesec */
2389 if ((error
= vnode_get_filesec(vp
, &fsec
, ctx
)) != 0)
2392 /* if no filesec, no attributes */
2394 VATTR_RETURN(vap
, va_acl
, NULL
);
2395 VATTR_RETURN(vap
, va_uuuid
, kauth_null_guid
);
2396 VATTR_RETURN(vap
, va_guuid
, kauth_null_guid
);
2399 /* looks good, try to return what we were asked for */
2400 VATTR_RETURN(vap
, va_uuuid
, fsec
->fsec_owner
);
2401 VATTR_RETURN(vap
, va_guuid
, fsec
->fsec_group
);
2403 /* only return the ACL if we were actually asked for it */
2404 if (VATTR_IS_ACTIVE(vap
, va_acl
)) {
2405 if (fsec
->fsec_acl
.acl_entrycount
== KAUTH_FILESEC_NOACL
) {
2406 VATTR_RETURN(vap
, va_acl
, NULL
);
2408 facl
= kauth_acl_alloc(fsec
->fsec_acl
.acl_entrycount
);
2410 kauth_filesec_free(fsec
);
2414 bcopy(&fsec
->fsec_acl
, facl
, KAUTH_ACL_COPYSIZE(&fsec
->fsec_acl
));
2415 VATTR_RETURN(vap
, va_acl
, facl
);
2418 kauth_filesec_free(fsec
);
2422 * If someone gave us an unsolicited filesec, toss it. We promise that
2423 * we're OK with a filesystem giving us anything back, but our callers
2424 * only expect what they asked for.
2426 if (VATTR_IS_SUPPORTED(vap
, va_acl
) && !VATTR_IS_ACTIVE(vap
, va_acl
)) {
2427 if (vap
->va_acl
!= NULL
)
2428 kauth_acl_free(vap
->va_acl
);
2429 VATTR_CLEAR_SUPPORTED(vap
, va_acl
);
2432 #if 0 /* enable when we have a filesystem only supporting UUIDs */
2434 * Handle the case where we need a UID/GID, but only have extended
2435 * security information.
2437 if (VATTR_NOT_RETURNED(vap
, va_uid
) &&
2438 VATTR_IS_SUPPORTED(vap
, va_uuuid
) &&
2439 !kauth_guid_equal(&vap
->va_uuuid
, &kauth_null_guid
)) {
2440 if ((error
= kauth_cred_guid2uid(&vap
->va_uuuid
, &nuid
)) == 0)
2441 VATTR_RETURN(vap
, va_uid
, nuid
);
2443 if (VATTR_NOT_RETURNED(vap
, va_gid
) &&
2444 VATTR_IS_SUPPORTED(vap
, va_guuid
) &&
2445 !kauth_guid_equal(&vap
->va_guuid
, &kauth_null_guid
)) {
2446 if ((error
= kauth_cred_guid2gid(&vap
->va_guuid
, &ngid
)) == 0)
2447 VATTR_RETURN(vap
, va_gid
, ngid
);
2452 * Handle uid/gid == 99 and MNT_IGNORE_OWNERSHIP here.
2454 if (VATTR_IS_ACTIVE(vap
, va_uid
)) {
2455 if (vfs_context_issuser(ctx
) && VATTR_IS_SUPPORTED(vap
, va_uid
)) {
2457 } else if (vp
->v_mount
->mnt_flag
& MNT_IGNORE_OWNERSHIP
) {
2458 nuid
= vp
->v_mount
->mnt_fsowner
;
2459 if (nuid
== KAUTH_UID_NONE
)
2461 } else if (VATTR_IS_SUPPORTED(vap
, va_uid
)) {
2464 /* this will always be something sensible */
2465 nuid
= vp
->v_mount
->mnt_fsowner
;
2467 if ((nuid
== 99) && !vfs_context_issuser(ctx
))
2468 nuid
= kauth_cred_getuid(vfs_context_ucred(ctx
));
2469 VATTR_RETURN(vap
, va_uid
, nuid
);
2471 if (VATTR_IS_ACTIVE(vap
, va_gid
)) {
2472 if (vfs_context_issuser(ctx
) && VATTR_IS_SUPPORTED(vap
, va_gid
)) {
2474 } else if (vp
->v_mount
->mnt_flag
& MNT_IGNORE_OWNERSHIP
) {
2475 ngid
= vp
->v_mount
->mnt_fsgroup
;
2476 if (ngid
== KAUTH_GID_NONE
)
2478 } else if (VATTR_IS_SUPPORTED(vap
, va_gid
)) {
2481 /* this will always be something sensible */
2482 ngid
= vp
->v_mount
->mnt_fsgroup
;
2484 if ((ngid
== 99) && !vfs_context_issuser(ctx
))
2485 ngid
= kauth_cred_getgid(vfs_context_ucred(ctx
));
2486 VATTR_RETURN(vap
, va_gid
, ngid
);
2490 * Synthesise some values that can be reasonably guessed.
2492 if (!VATTR_IS_SUPPORTED(vap
, va_iosize
))
2493 VATTR_RETURN(vap
, va_iosize
, vp
->v_mount
->mnt_vfsstat
.f_iosize
);
2495 if (!VATTR_IS_SUPPORTED(vap
, va_flags
))
2496 VATTR_RETURN(vap
, va_flags
, 0);
2498 if (!VATTR_IS_SUPPORTED(vap
, va_filerev
))
2499 VATTR_RETURN(vap
, va_filerev
, 0);
2501 if (!VATTR_IS_SUPPORTED(vap
, va_gen
))
2502 VATTR_RETURN(vap
, va_gen
, 0);
2505 * Default sizes. Ordering here is important, as later defaults build on earlier ones.
2507 if (!VATTR_IS_SUPPORTED(vap
, va_data_size
))
2508 VATTR_RETURN(vap
, va_data_size
, 0);
2510 /* do we want any of the possibly-computed values? */
2511 if (VATTR_IS_ACTIVE(vap
, va_data_alloc
) ||
2512 VATTR_IS_ACTIVE(vap
, va_total_size
) ||
2513 VATTR_IS_ACTIVE(vap
, va_total_alloc
)) {
2514 /* make sure f_bsize is valid */
2515 if (vp
->v_mount
->mnt_vfsstat
.f_bsize
== 0) {
2516 if ((error
= vfs_update_vfsstat(vp
->v_mount
, ctx
, VFS_KERNEL_EVENT
)) != 0)
2520 /* default va_data_alloc from va_data_size */
2521 if (!VATTR_IS_SUPPORTED(vap
, va_data_alloc
))
2522 VATTR_RETURN(vap
, va_data_alloc
, roundup(vap
->va_data_size
, vp
->v_mount
->mnt_vfsstat
.f_bsize
));
2524 /* default va_total_size from va_data_size */
2525 if (!VATTR_IS_SUPPORTED(vap
, va_total_size
))
2526 VATTR_RETURN(vap
, va_total_size
, vap
->va_data_size
);
2528 /* default va_total_alloc from va_total_size which is guaranteed at this point */
2529 if (!VATTR_IS_SUPPORTED(vap
, va_total_alloc
))
2530 VATTR_RETURN(vap
, va_total_alloc
, roundup(vap
->va_total_size
, vp
->v_mount
->mnt_vfsstat
.f_bsize
));
2534 * If we don't have a change time, pull it from the modtime.
2536 if (!VATTR_IS_SUPPORTED(vap
, va_change_time
) && VATTR_IS_SUPPORTED(vap
, va_modify_time
))
2537 VATTR_RETURN(vap
, va_change_time
, vap
->va_modify_time
);
2540 * This is really only supported for the creation VNOPs, but since the field is there
2541 * we should populate it correctly.
2543 VATTR_RETURN(vap
, va_type
, vp
->v_type
);
2546 * The fsid can be obtained from the mountpoint directly.
2548 VATTR_RETURN(vap
, va_fsid
, vp
->v_mount
->mnt_vfsstat
.f_fsid
.val
[0]);
2556 * Set the attributes on a vnode in a vnode context.
2558 * Parameters: vp The vnode whose attributes to set.
2559 * vap A pointer to the attributes to set.
2560 * ctx The vnode context in which the
2561 * operation is to be attempted.
2563 * Returns: 0 Success
2566 * Notes: The kauth_filesec_t in 'vap', if any, is in host byte order.
2568 * The contents of the data area pointed to by 'vap' may be
2569 * modified if the vnode is on a filesystem which has been
2570 * mounted with ingore ownership flags, or by the underlyng
2571 * VFS itself, or by the fallback code, if the underlying VFS
2572 * does not support ACL, UUID, or GUUID attributes directly.
2574 * XXX: We should enummerate the possible errno values here, and where
2575 * in the code they originated.
2578 vnode_setattr(vnode_t vp
, struct vnode_attr
*vap
, vfs_context_t ctx
)
2583 int is_perm_change
= 0;
2584 int is_stat_change
= 0;
2588 * Reject attempts to set unknown attributes.
2590 if (vap
->va_active
& ~VNODE_ATTR_ALL
)
2594 * Make sure the filesystem is mounted R/W.
2595 * If not, return an error.
2597 if (vfs_isrdonly(vp
->v_mount
)) {
2602 #if DEVELOPMENT || DEBUG
2604 * XXX VSWAP: Check for entitlements or special flag here
2605 * so we can restrict access appropriately.
2607 #else /* DEVELOPMENT || DEBUG */
2609 if (vnode_isswap(vp
) && (ctx
!= vfs_context_kernel())) {
2613 #endif /* DEVELOPMENT || DEBUG */
2616 /* For streams, va_data_size is the only setable attribute. */
2617 if ((vp
->v_flag
& VISNAMEDSTREAM
) && (vap
->va_active
!= VNODE_ATTR_va_data_size
)) {
2622 /* Check for truncation */
2623 if(VATTR_IS_ACTIVE(vap
, va_data_size
)) {
2624 switch(vp
->v_type
) {
2626 /* For regular files it's ok */
2629 /* Not allowed to truncate directories */
2633 /* For everything else we will clear the bit and let underlying FS decide on the rest */
2634 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
2637 /* If it was the only bit set, return success, to handle cases like redirect to /dev/null */
2643 * If ownership is being ignored on this volume, we silently discard
2644 * ownership changes.
2646 if (vp
->v_mount
->mnt_flag
& MNT_IGNORE_OWNERSHIP
) {
2647 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
2648 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
2652 * Make sure that extended security is enabled if we're going to try
2655 if (!vfs_extendedsecurity(vnode_mount(vp
)) &&
2656 (VATTR_IS_ACTIVE(vap
, va_acl
) || VATTR_IS_ACTIVE(vap
, va_uuuid
) || VATTR_IS_ACTIVE(vap
, va_guuid
))) {
2657 KAUTH_DEBUG("SETATTR - returning ENOTSUP to request to set extended security");
2662 /* Never allow the setting of any unsupported superuser flags. */
2663 if (VATTR_IS_ACTIVE(vap
, va_flags
)) {
2664 vap
->va_flags
&= (SF_SUPPORTED
| UF_SETTABLE
);
2669 * Remember all of the active attributes that we're
2670 * attempting to modify.
2672 active
= vap
->va_active
& ~VNODE_ATTR_RDONLY
;
2675 error
= VNOP_SETATTR(vp
, vap
, ctx
);
2677 if ((error
== 0) && !VATTR_ALL_SUPPORTED(vap
))
2678 error
= vnode_setattr_fallback(vp
, vap
, ctx
);
2681 #define PERMISSION_BITS (VNODE_ATTR_BIT(va_uid) | VNODE_ATTR_BIT(va_uuuid) | \
2682 VNODE_ATTR_BIT(va_gid) | VNODE_ATTR_BIT(va_guuid) | \
2683 VNODE_ATTR_BIT(va_mode) | VNODE_ATTR_BIT(va_acl))
2686 * Now that we've changed them, decide whether to send an
2689 if ((active
& PERMISSION_BITS
) & vap
->va_supported
) {
2693 * We've already checked the permission bits, and we
2694 * also want to filter out access time / backup time
2697 active
&= ~(PERMISSION_BITS
|
2698 VNODE_ATTR_BIT(va_access_time
) |
2699 VNODE_ATTR_BIT(va_backup_time
));
2701 /* Anything left to notify about? */
2702 if (active
& vap
->va_supported
)
2707 if (is_perm_change
) {
2708 if (need_fsevent(FSE_CHOWN
, vp
)) {
2709 add_fsevent(FSE_CHOWN
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
2711 } else if (is_stat_change
&& need_fsevent(FSE_STAT_CHANGED
, vp
)) {
2712 add_fsevent(FSE_STAT_CHANGED
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
2715 #undef PERMISSION_BITS
2723 * Fallback for setting the attributes on a vnode in a vnode context. This
2724 * Function will attempt to store ACL, UUID, and GUID information utilizing
2725 * a read/modify/write operation against an EA used as a backing store for
2728 * Parameters: vp The vnode whose attributes to set.
2729 * vap A pointer to the attributes to set.
2730 * ctx The vnode context in which the
2731 * operation is to be attempted.
2733 * Returns: 0 Success
2736 * Notes: The kauth_filesec_t in 'vap', if any, is in host byte order,
2737 * as are the fsec and lfsec, if they are used.
2739 * The contents of the data area pointed to by 'vap' may be
2740 * modified to indicate that the attribute is supported for
2741 * any given requested attribute.
2743 * XXX: We should enummerate the possible errno values here, and where
2744 * in the code they originated.
2747 vnode_setattr_fallback(vnode_t vp
, struct vnode_attr
*vap
, vfs_context_t ctx
)
2749 kauth_filesec_t fsec
;
2751 struct kauth_filesec lfsec
;
2757 * Extended security fallback via extended attributes.
2759 * Note that we do not free the filesec; the caller is expected to
2762 if (VATTR_NOT_RETURNED(vap
, va_acl
) ||
2763 VATTR_NOT_RETURNED(vap
, va_uuuid
) ||
2764 VATTR_NOT_RETURNED(vap
, va_guuid
)) {
2765 VFS_DEBUG(ctx
, vp
, "SETATTR - doing filesec fallback");
2768 * Fail for file types that we don't permit extended security
2771 if (!XATTR_VNODE_SUPPORTED(vp
)) {
2772 VFS_DEBUG(ctx
, vp
, "SETATTR - Can't write ACL to file type %d", vnode_vtype(vp
));
2778 * If we don't have all the extended security items, we need
2779 * to fetch the existing data to perform a read-modify-write
2783 if (!VATTR_IS_ACTIVE(vap
, va_acl
) ||
2784 !VATTR_IS_ACTIVE(vap
, va_uuuid
) ||
2785 !VATTR_IS_ACTIVE(vap
, va_guuid
)) {
2786 if ((error
= vnode_get_filesec(vp
, &fsec
, ctx
)) != 0) {
2787 KAUTH_DEBUG("SETATTR - ERROR %d fetching filesec for update", error
);
2791 /* if we didn't get a filesec, use our local one */
2793 KAUTH_DEBUG("SETATTR - using local filesec for new/full update");
2796 KAUTH_DEBUG("SETATTR - updating existing filesec");
2799 facl
= &fsec
->fsec_acl
;
2801 /* if we're using the local filesec, we need to initialise it */
2802 if (fsec
== &lfsec
) {
2803 fsec
->fsec_magic
= KAUTH_FILESEC_MAGIC
;
2804 fsec
->fsec_owner
= kauth_null_guid
;
2805 fsec
->fsec_group
= kauth_null_guid
;
2806 facl
->acl_entrycount
= KAUTH_FILESEC_NOACL
;
2807 facl
->acl_flags
= 0;
2811 * Update with the supplied attributes.
2813 if (VATTR_IS_ACTIVE(vap
, va_uuuid
)) {
2814 KAUTH_DEBUG("SETATTR - updating owner UUID");
2815 fsec
->fsec_owner
= vap
->va_uuuid
;
2816 VATTR_SET_SUPPORTED(vap
, va_uuuid
);
2818 if (VATTR_IS_ACTIVE(vap
, va_guuid
)) {
2819 KAUTH_DEBUG("SETATTR - updating group UUID");
2820 fsec
->fsec_group
= vap
->va_guuid
;
2821 VATTR_SET_SUPPORTED(vap
, va_guuid
);
2823 if (VATTR_IS_ACTIVE(vap
, va_acl
)) {
2824 if (vap
->va_acl
== NULL
) {
2825 KAUTH_DEBUG("SETATTR - removing ACL");
2826 facl
->acl_entrycount
= KAUTH_FILESEC_NOACL
;
2828 KAUTH_DEBUG("SETATTR - setting ACL with %d entries", vap
->va_acl
->acl_entrycount
);
2831 VATTR_SET_SUPPORTED(vap
, va_acl
);
2835 * If the filesec data is all invalid, we can just remove
2836 * the EA completely.
2838 if ((facl
->acl_entrycount
== KAUTH_FILESEC_NOACL
) &&
2839 kauth_guid_equal(&fsec
->fsec_owner
, &kauth_null_guid
) &&
2840 kauth_guid_equal(&fsec
->fsec_group
, &kauth_null_guid
)) {
2841 error
= vn_removexattr(vp
, KAUTH_FILESEC_XATTR
, XATTR_NOSECURITY
, ctx
);
2842 /* no attribute is ok, nothing to delete */
2843 if (error
== ENOATTR
)
2845 VFS_DEBUG(ctx
, vp
, "SETATTR - remove filesec returning %d", error
);
2848 error
= vnode_set_filesec(vp
, fsec
, facl
, ctx
);
2849 VFS_DEBUG(ctx
, vp
, "SETATTR - update filesec returning %d", error
);
2852 /* if we fetched a filesec, dispose of the buffer */
2854 kauth_filesec_free(fsec
);
2862 * Upcall for a filesystem to tell VFS about an EVFILT_VNODE-type
2866 vnode_notify(vnode_t vp
, uint32_t events
, struct vnode_attr
*vap
)
2868 /* These are the same as the corresponding knotes, at least for now. Cheating a little. */
2869 uint32_t knote_mask
= (VNODE_EVENT_WRITE
| VNODE_EVENT_DELETE
| VNODE_EVENT_RENAME
2870 | VNODE_EVENT_LINK
| VNODE_EVENT_EXTEND
| VNODE_EVENT_ATTRIB
);
2871 uint32_t dir_contents_mask
= (VNODE_EVENT_DIR_CREATED
| VNODE_EVENT_FILE_CREATED
2872 | VNODE_EVENT_DIR_REMOVED
| VNODE_EVENT_FILE_REMOVED
);
2873 uint32_t knote_events
= (events
& knote_mask
);
2875 /* Permissions are not explicitly part of the kqueue model */
2876 if (events
& VNODE_EVENT_PERMS
) {
2877 knote_events
|= NOTE_ATTRIB
;
2880 /* Directory contents information just becomes NOTE_WRITE */
2881 if ((vnode_isdir(vp
)) && (events
& dir_contents_mask
)) {
2882 knote_events
|= NOTE_WRITE
;
2886 lock_vnode_and_post(vp
, knote_events
);
2889 create_fsevent_from_kevent(vp
, events
, vap
);
2902 vnode_isdyldsharedcache(vnode_t vp
)
2904 return ((vp
->v_flag
& VSHARED_DYLD
) ? 1 : 0);
2909 * For a filesystem that isn't tracking its own vnode watchers:
2910 * check whether a vnode is being monitored.
2913 vnode_ismonitored(vnode_t vp
) {
2914 return (vp
->v_knotes
.slh_first
!= NULL
);
2918 vnode_getbackingvnode(vnode_t in_vp
, vnode_t
* out_vpp
)
2924 return nullfs_getbackingvnode(in_vp
, out_vpp
);
2926 #pragma unused(in_vp)
2932 * Initialize a struct vnode_attr and activate the attributes required
2933 * by the vnode_notify() call.
2936 vfs_get_notify_attributes(struct vnode_attr
*vap
)
2939 vap
->va_active
= VNODE_NOTIFY_ATTRS
;
2945 vfs_settriggercallback(fsid_t
*fsid
, vfs_trigger_callback_t vtc
, void *data
, uint32_t flags __unused
, vfs_context_t ctx
)
2950 mp
= mount_list_lookupby_fsid(fsid
, 0 /* locked */, 1 /* withref */);
2955 error
= vfs_busy(mp
, LK_NOWAIT
);
2963 if (mp
->mnt_triggercallback
!= NULL
) {
2969 mp
->mnt_triggercallback
= vtc
;
2970 mp
->mnt_triggerdata
= data
;
2973 mp
->mnt_triggercallback(mp
, VTC_REPLACE
, data
, ctx
);
2979 #endif /* CONFIG_TRIGGERS */
2982 * Definition of vnode operations.
2988 *#% lookup dvp L ? ?
2989 *#% lookup vpp - L -
2991 struct vnop_lookup_args
{
2992 struct vnodeop_desc
*a_desc
;
2995 struct componentname
*a_cnp
;
2996 vfs_context_t a_context
;
3001 * Returns: 0 Success
3002 * lock_fsnode:ENOENT No such file or directory [only for VFS
3003 * that is not thread safe & vnode is
3004 * currently being/has been terminated]
3005 * <vfs_lookup>:ENAMETOOLONG
3006 * <vfs_lookup>:ENOENT
3007 * <vfs_lookup>:EJUSTRETURN
3008 * <vfs_lookup>:EPERM
3009 * <vfs_lookup>:EISDIR
3010 * <vfs_lookup>:ENOTDIR
3013 * Note: The return codes from the underlying VFS's lookup routine can't
3014 * be fully enumerated here, since third party VFS authors may not
3015 * limit their error returns to the ones documented here, even
3016 * though this may result in some programs functioning incorrectly.
3018 * The return codes documented above are those which may currently
3019 * be returned by HFS from hfs_lookup, not including additional
3020 * error code which may be propagated from underlying routines.
3023 VNOP_LOOKUP(vnode_t dvp
, vnode_t
*vpp
, struct componentname
*cnp
, vfs_context_t ctx
)
3026 struct vnop_lookup_args a
;
3028 a
.a_desc
= &vnop_lookup_desc
;
3034 _err
= (*dvp
->v_op
[vnop_lookup_desc
.vdesc_offset
])(&a
);
3035 if (_err
== 0 && *vpp
) {
3036 DTRACE_FSINFO(lookup
, vnode_t
, *vpp
);
3043 struct vnop_compound_open_args
{
3044 struct vnodeop_desc
*a_desc
;
3047 struct componentname
*a_cnp
;
3050 struct vnode_attr
*a_vap
;
3051 vfs_context_t a_context
;
3057 VNOP_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
)
3060 struct vnop_compound_open_args a
;
3063 uint32_t tmp_status
= 0;
3064 struct componentname
*cnp
= &ndp
->ni_cnd
;
3066 want_create
= (flags
& O_CREAT
);
3068 a
.a_desc
= &vnop_compound_open_desc
;
3070 a
.a_vpp
= vpp
; /* Could be NULL */
3074 a
.a_status
= (statusp
!= NULL
) ? statusp
: &tmp_status
;
3077 a
.a_open_create_authorizer
= vn_authorize_create
;
3078 a
.a_open_existing_authorizer
= vn_authorize_open_existing
;
3079 a
.a_reserved
= NULL
;
3081 if (dvp
== NULLVP
) {
3084 if (want_create
&& !vap
) {
3085 panic("Want create, but no vap?");
3087 if (!want_create
&& vap
) {
3088 panic("Don't want create, but have a vap?");
3091 _err
= (*dvp
->v_op
[vnop_compound_open_desc
.vdesc_offset
])(&a
);
3093 if (_err
== 0 && *vpp
) {
3094 DTRACE_FSINFO(compound_open
, vnode_t
, *vpp
);
3096 DTRACE_FSINFO(compound_open
, vnode_t
, dvp
);
3099 DTRACE_FSINFO(compound_open
, vnode_t
, *vpp
);
3102 did_create
= (*a
.a_status
& COMPOUND_OPEN_STATUS_DID_CREATE
);
3104 if (did_create
&& !want_create
) {
3105 panic("Filesystem did a create, even though none was requested?");
3109 #if CONFIG_APPLEDOUBLE
3110 if (!NATIVE_XATTR(dvp
)) {
3112 * Remove stale Apple Double file (if any).
3114 xattrfile_remove(dvp
, cnp
->cn_nameptr
, ctx
, 0);
3116 #endif /* CONFIG_APPLEDOUBLE */
3117 /* On create, provide kqueue notification */
3118 post_event_if_success(dvp
, _err
, NOTE_WRITE
);
3121 lookup_compound_vnop_post_hook(_err
, dvp
, *vpp
, ndp
, did_create
);
3122 #if 0 /* FSEvents... */
3123 if (*vpp
&& _err
&& _err
!= EKEEPLOOKING
) {
3134 struct vnop_create_args
{
3135 struct vnodeop_desc
*a_desc
;
3138 struct componentname
*a_cnp
;
3139 struct vnode_attr
*a_vap
;
3140 vfs_context_t a_context
;
3144 VNOP_CREATE(vnode_t dvp
, vnode_t
* vpp
, struct componentname
* cnp
, struct vnode_attr
* vap
, vfs_context_t ctx
)
3147 struct vnop_create_args a
;
3149 a
.a_desc
= &vnop_create_desc
;
3156 _err
= (*dvp
->v_op
[vnop_create_desc
.vdesc_offset
])(&a
);
3157 if (_err
== 0 && *vpp
) {
3158 DTRACE_FSINFO(create
, vnode_t
, *vpp
);
3161 #if CONFIG_APPLEDOUBLE
3162 if (_err
== 0 && !NATIVE_XATTR(dvp
)) {
3164 * Remove stale Apple Double file (if any).
3166 xattrfile_remove(dvp
, cnp
->cn_nameptr
, ctx
, 0);
3168 #endif /* CONFIG_APPLEDOUBLE */
3170 post_event_if_success(dvp
, _err
, NOTE_WRITE
);
3178 *#% whiteout dvp L L L
3179 *#% whiteout cnp - - -
3180 *#% whiteout flag - - -
3183 struct vnop_whiteout_args
{
3184 struct vnodeop_desc
*a_desc
;
3186 struct componentname
*a_cnp
;
3188 vfs_context_t a_context
;
3192 VNOP_WHITEOUT(__unused vnode_t dvp
, __unused
struct componentname
*cnp
,
3193 __unused
int flags
, __unused vfs_context_t ctx
)
3195 return (ENOTSUP
); // XXX OBSOLETE
3205 struct vnop_mknod_args
{
3206 struct vnodeop_desc
*a_desc
;
3209 struct componentname
*a_cnp
;
3210 struct vnode_attr
*a_vap
;
3211 vfs_context_t a_context
;
3215 VNOP_MKNOD(vnode_t dvp
, vnode_t
* vpp
, struct componentname
* cnp
, struct vnode_attr
* vap
, vfs_context_t ctx
)
3219 struct vnop_mknod_args a
;
3221 a
.a_desc
= &vnop_mknod_desc
;
3228 _err
= (*dvp
->v_op
[vnop_mknod_desc
.vdesc_offset
])(&a
);
3229 if (_err
== 0 && *vpp
) {
3230 DTRACE_FSINFO(mknod
, vnode_t
, *vpp
);
3233 post_event_if_success(dvp
, _err
, NOTE_WRITE
);
3244 struct vnop_open_args
{
3245 struct vnodeop_desc
*a_desc
;
3248 vfs_context_t a_context
;
3252 VNOP_OPEN(vnode_t vp
, int mode
, vfs_context_t ctx
)
3255 struct vnop_open_args a
;
3258 ctx
= vfs_context_current();
3260 a
.a_desc
= &vnop_open_desc
;
3265 _err
= (*vp
->v_op
[vnop_open_desc
.vdesc_offset
])(&a
);
3266 DTRACE_FSINFO(open
, vnode_t
, vp
);
3277 struct vnop_close_args
{
3278 struct vnodeop_desc
*a_desc
;
3281 vfs_context_t a_context
;
3285 VNOP_CLOSE(vnode_t vp
, int fflag
, vfs_context_t ctx
)
3288 struct vnop_close_args a
;
3291 ctx
= vfs_context_current();
3293 a
.a_desc
= &vnop_close_desc
;
3298 _err
= (*vp
->v_op
[vnop_close_desc
.vdesc_offset
])(&a
);
3299 DTRACE_FSINFO(close
, vnode_t
, vp
);
3310 struct vnop_access_args
{
3311 struct vnodeop_desc
*a_desc
;
3314 vfs_context_t a_context
;
3318 VNOP_ACCESS(vnode_t vp
, int action
, vfs_context_t ctx
)
3321 struct vnop_access_args a
;
3324 ctx
= vfs_context_current();
3326 a
.a_desc
= &vnop_access_desc
;
3328 a
.a_action
= action
;
3331 _err
= (*vp
->v_op
[vnop_access_desc
.vdesc_offset
])(&a
);
3332 DTRACE_FSINFO(access
, vnode_t
, vp
);
3340 *#% getattr vp = = =
3343 struct vnop_getattr_args
{
3344 struct vnodeop_desc
*a_desc
;
3346 struct vnode_attr
*a_vap
;
3347 vfs_context_t a_context
;
3351 VNOP_GETATTR(vnode_t vp
, struct vnode_attr
* vap
, vfs_context_t ctx
)
3354 struct vnop_getattr_args a
;
3356 a
.a_desc
= &vnop_getattr_desc
;
3361 _err
= (*vp
->v_op
[vnop_getattr_desc
.vdesc_offset
])(&a
);
3362 DTRACE_FSINFO(getattr
, vnode_t
, vp
);
3370 *#% setattr vp L L L
3373 struct vnop_setattr_args
{
3374 struct vnodeop_desc
*a_desc
;
3376 struct vnode_attr
*a_vap
;
3377 vfs_context_t a_context
;
3381 VNOP_SETATTR(vnode_t vp
, struct vnode_attr
* vap
, vfs_context_t ctx
)
3384 struct vnop_setattr_args a
;
3386 a
.a_desc
= &vnop_setattr_desc
;
3391 _err
= (*vp
->v_op
[vnop_setattr_desc
.vdesc_offset
])(&a
);
3392 DTRACE_FSINFO(setattr
, vnode_t
, vp
);
3394 #if CONFIG_APPLEDOUBLE
3396 * Shadow uid/gid/mod change to extended attribute file.
3398 if (_err
== 0 && !NATIVE_XATTR(vp
)) {
3399 struct vnode_attr va
;
3403 if (VATTR_IS_ACTIVE(vap
, va_uid
)) {
3404 VATTR_SET(&va
, va_uid
, vap
->va_uid
);
3407 if (VATTR_IS_ACTIVE(vap
, va_gid
)) {
3408 VATTR_SET(&va
, va_gid
, vap
->va_gid
);
3411 if (VATTR_IS_ACTIVE(vap
, va_mode
)) {
3412 VATTR_SET(&va
, va_mode
, vap
->va_mode
);
3419 dvp
= vnode_getparent(vp
);
3420 vname
= vnode_getname(vp
);
3422 xattrfile_setattr(dvp
, vname
, &va
, ctx
);
3426 vnode_putname(vname
);
3429 #endif /* CONFIG_APPLEDOUBLE */
3432 * If we have changed any of the things about the file that are likely
3433 * to result in changes to authorization results, blow the vnode auth
3437 VATTR_IS_SUPPORTED(vap
, va_mode
) ||
3438 VATTR_IS_SUPPORTED(vap
, va_uid
) ||
3439 VATTR_IS_SUPPORTED(vap
, va_gid
) ||
3440 VATTR_IS_SUPPORTED(vap
, va_flags
) ||
3441 VATTR_IS_SUPPORTED(vap
, va_acl
) ||
3442 VATTR_IS_SUPPORTED(vap
, va_uuuid
) ||
3443 VATTR_IS_SUPPORTED(vap
, va_guuid
))) {
3444 vnode_uncache_authorized_action(vp
, KAUTH_INVALIDATE_CACHED_RIGHTS
);
3447 if (vfs_authopaque(vp
->v_mount
) && vnode_hasnamedstreams(vp
)) {
3449 if (vnode_getnamedstream(vp
, &svp
, XATTR_RESOURCEFORK_NAME
, NS_OPEN
, 0, ctx
) == 0) {
3450 vnode_uncache_authorized_action(svp
, KAUTH_INVALIDATE_CACHED_RIGHTS
);
3454 #endif /* NAMEDSTREAMS */
3458 post_event_if_success(vp
, _err
, NOTE_ATTRIB
);
3470 struct vnop_read_args
{
3471 struct vnodeop_desc
*a_desc
;
3475 vfs_context_t a_context
;
3479 VNOP_READ(vnode_t vp
, struct uio
* uio
, int ioflag
, vfs_context_t ctx
)
3482 struct vnop_read_args a
;
3484 user_ssize_t resid
= uio_resid(uio
);
3491 a
.a_desc
= &vnop_read_desc
;
3494 a
.a_ioflag
= ioflag
;
3497 _err
= (*vp
->v_op
[vnop_read_desc
.vdesc_offset
])(&a
);
3498 DTRACE_FSINFO_IO(read
,
3499 vnode_t
, vp
, user_ssize_t
, (resid
- uio_resid(uio
)));
3511 struct vnop_write_args
{
3512 struct vnodeop_desc
*a_desc
;
3516 vfs_context_t a_context
;
3520 VNOP_WRITE(vnode_t vp
, struct uio
* uio
, int ioflag
, vfs_context_t ctx
)
3522 struct vnop_write_args a
;
3525 user_ssize_t resid
= uio_resid(uio
);
3532 a
.a_desc
= &vnop_write_desc
;
3535 a
.a_ioflag
= ioflag
;
3538 _err
= (*vp
->v_op
[vnop_write_desc
.vdesc_offset
])(&a
);
3539 DTRACE_FSINFO_IO(write
,
3540 vnode_t
, vp
, user_ssize_t
, (resid
- uio_resid(uio
)));
3542 post_event_if_success(vp
, _err
, NOTE_WRITE
);
3554 struct vnop_ioctl_args
{
3555 struct vnodeop_desc
*a_desc
;
3560 vfs_context_t a_context
;
3564 VNOP_IOCTL(vnode_t vp
, u_long command
, caddr_t data
, int fflag
, vfs_context_t ctx
)
3567 struct vnop_ioctl_args a
;
3570 ctx
= vfs_context_current();
3574 * This check should probably have been put in the TTY code instead...
3576 * We have to be careful about what we assume during startup and shutdown.
3577 * We have to be able to use the root filesystem's device vnode even when
3578 * devfs isn't mounted (yet/anymore), so we can't go looking at its mount
3579 * structure. If there is no data pointer, it doesn't matter whether
3580 * the device is 64-bit ready. Any command (like DKIOCSYNCHRONIZE)
3581 * which passes NULL for its data pointer can therefore be used during
3582 * mount or unmount of the root filesystem.
3584 * Depending on what root filesystems need to do during mount/unmount, we
3585 * may need to loosen this check again in the future.
3587 if (vfs_context_is64bit(ctx
) && !(vnode_ischr(vp
) || vnode_isblk(vp
))) {
3588 if (data
!= NULL
&& !vnode_vfs64bitready(vp
)) {
3593 a
.a_desc
= &vnop_ioctl_desc
;
3595 a
.a_command
= command
;
3600 _err
= (*vp
->v_op
[vnop_ioctl_desc
.vdesc_offset
])(&a
);
3601 DTRACE_FSINFO(ioctl
, vnode_t
, vp
);
3613 struct vnop_select_args
{
3614 struct vnodeop_desc
*a_desc
;
3619 vfs_context_t a_context
;
3623 VNOP_SELECT(vnode_t vp
, int which
, int fflags
, void * wql
, vfs_context_t ctx
)
3626 struct vnop_select_args a
;
3629 ctx
= vfs_context_current();
3631 a
.a_desc
= &vnop_select_desc
;
3634 a
.a_fflags
= fflags
;
3638 _err
= (*vp
->v_op
[vnop_select_desc
.vdesc_offset
])(&a
);
3639 DTRACE_FSINFO(select
, vnode_t
, vp
);
3648 *#% exchange fvp L L L
3649 *#% exchange tvp L L L
3652 struct vnop_exchange_args
{
3653 struct vnodeop_desc
*a_desc
;
3657 vfs_context_t a_context
;
3661 VNOP_EXCHANGE(vnode_t fvp
, vnode_t tvp
, int options
, vfs_context_t ctx
)
3664 struct vnop_exchange_args a
;
3666 a
.a_desc
= &vnop_exchange_desc
;
3669 a
.a_options
= options
;
3672 _err
= (*fvp
->v_op
[vnop_exchange_desc
.vdesc_offset
])(&a
);
3673 DTRACE_FSINFO(exchange
, vnode_t
, fvp
);
3675 /* Don't post NOTE_WRITE because file descriptors follow the data ... */
3676 post_event_if_success(fvp
, _err
, NOTE_ATTRIB
);
3677 post_event_if_success(tvp
, _err
, NOTE_ATTRIB
);
3689 struct vnop_revoke_args
{
3690 struct vnodeop_desc
*a_desc
;
3693 vfs_context_t a_context
;
3697 VNOP_REVOKE(vnode_t vp
, int flags
, vfs_context_t ctx
)
3699 struct vnop_revoke_args a
;
3702 a
.a_desc
= &vnop_revoke_desc
;
3707 _err
= (*vp
->v_op
[vnop_revoke_desc
.vdesc_offset
])(&a
);
3708 DTRACE_FSINFO(revoke
, vnode_t
, vp
);
3720 struct vnop_mmap_args
{
3721 struct vnodeop_desc
*a_desc
;
3724 vfs_context_t a_context
;
3728 VNOP_MMAP(vnode_t vp
, int fflags
, vfs_context_t ctx
)
3731 struct vnop_mmap_args a
;
3733 a
.a_desc
= &vnop_mmap_desc
;
3735 a
.a_fflags
= fflags
;
3738 _err
= (*vp
->v_op
[vnop_mmap_desc
.vdesc_offset
])(&a
);
3739 DTRACE_FSINFO(mmap
, vnode_t
, vp
);
3748 *# mnomap - vp U U U
3751 struct vnop_mnomap_args
{
3752 struct vnodeop_desc
*a_desc
;
3754 vfs_context_t a_context
;
3758 VNOP_MNOMAP(vnode_t vp
, vfs_context_t ctx
)
3761 struct vnop_mnomap_args a
;
3763 a
.a_desc
= &vnop_mnomap_desc
;
3767 _err
= (*vp
->v_op
[vnop_mnomap_desc
.vdesc_offset
])(&a
);
3768 DTRACE_FSINFO(mnomap
, vnode_t
, vp
);
3780 struct vnop_fsync_args
{
3781 struct vnodeop_desc
*a_desc
;
3784 vfs_context_t a_context
;
3788 VNOP_FSYNC(vnode_t vp
, int waitfor
, vfs_context_t ctx
)
3790 struct vnop_fsync_args a
;
3793 a
.a_desc
= &vnop_fsync_desc
;
3795 a
.a_waitfor
= waitfor
;
3798 _err
= (*vp
->v_op
[vnop_fsync_desc
.vdesc_offset
])(&a
);
3799 DTRACE_FSINFO(fsync
, vnode_t
, vp
);
3808 *#% remove dvp L U U
3812 struct vnop_remove_args
{
3813 struct vnodeop_desc
*a_desc
;
3816 struct componentname
*a_cnp
;
3818 vfs_context_t a_context
;
3822 VNOP_REMOVE(vnode_t dvp
, vnode_t vp
, struct componentname
* cnp
, int flags
, vfs_context_t ctx
)
3825 struct vnop_remove_args a
;
3827 a
.a_desc
= &vnop_remove_desc
;
3834 _err
= (*dvp
->v_op
[vnop_remove_desc
.vdesc_offset
])(&a
);
3835 DTRACE_FSINFO(remove
, vnode_t
, vp
);
3838 vnode_setneedinactive(vp
);
3839 #if CONFIG_APPLEDOUBLE
3840 if ( !(NATIVE_XATTR(dvp
)) ) {
3842 * Remove any associated extended attribute file (._ AppleDouble file).
3844 xattrfile_remove(dvp
, cnp
->cn_nameptr
, ctx
, 1);
3846 #endif /* CONFIG_APPLEDOUBLE */
3849 post_event_if_success(vp
, _err
, NOTE_DELETE
| NOTE_LINK
);
3850 post_event_if_success(dvp
, _err
, NOTE_WRITE
);
3856 VNOP_COMPOUND_REMOVE(vnode_t dvp
, vnode_t
*vpp
, struct nameidata
*ndp
, int32_t flags
, struct vnode_attr
*vap
, vfs_context_t ctx
)
3859 struct vnop_compound_remove_args a
;
3860 int no_vp
= (*vpp
== NULLVP
);
3862 a
.a_desc
= &vnop_compound_remove_desc
;
3865 a
.a_cnp
= &ndp
->ni_cnd
;
3869 a
.a_remove_authorizer
= vn_authorize_unlink
;
3871 _err
= (*dvp
->v_op
[vnop_compound_remove_desc
.vdesc_offset
])(&a
);
3872 if (_err
== 0 && *vpp
) {
3873 DTRACE_FSINFO(compound_remove
, vnode_t
, *vpp
);
3875 DTRACE_FSINFO(compound_remove
, vnode_t
, dvp
);
3878 vnode_setneedinactive(*vpp
);
3879 #if CONFIG_APPLEDOUBLE
3880 if ( !(NATIVE_XATTR(dvp
)) ) {
3882 * Remove any associated extended attribute file (._ AppleDouble file).
3884 xattrfile_remove(dvp
, ndp
->ni_cnd
.cn_nameptr
, ctx
, 1);
3886 #endif /* CONFIG_APPLEDOUBLE */
3889 post_event_if_success(*vpp
, _err
, NOTE_DELETE
| NOTE_LINK
);
3890 post_event_if_success(dvp
, _err
, NOTE_WRITE
);
3893 lookup_compound_vnop_post_hook(_err
, dvp
, *vpp
, ndp
, 0);
3894 if (*vpp
&& _err
&& _err
!= EKEEPLOOKING
) {
3900 //printf("VNOP_COMPOUND_REMOVE() returning %d\n", _err);
3912 struct vnop_link_args
{
3913 struct vnodeop_desc
*a_desc
;
3916 struct componentname
*a_cnp
;
3917 vfs_context_t a_context
;
3921 VNOP_LINK(vnode_t vp
, vnode_t tdvp
, struct componentname
* cnp
, vfs_context_t ctx
)
3924 struct vnop_link_args a
;
3926 #if CONFIG_APPLEDOUBLE
3928 * For file systems with non-native extended attributes,
3929 * disallow linking to an existing "._" Apple Double file.
3931 if ( !NATIVE_XATTR(tdvp
) && (vp
->v_type
== VREG
)) {
3934 vname
= vnode_getname(vp
);
3935 if (vname
!= NULL
) {
3937 if (vname
[0] == '.' && vname
[1] == '_' && vname
[2] != '\0') {
3940 vnode_putname(vname
);
3945 #endif /* CONFIG_APPLEDOUBLE */
3947 a
.a_desc
= &vnop_link_desc
;
3953 _err
= (*tdvp
->v_op
[vnop_link_desc
.vdesc_offset
])(&a
);
3954 DTRACE_FSINFO(link
, vnode_t
, vp
);
3956 post_event_if_success(vp
, _err
, NOTE_LINK
);
3957 post_event_if_success(tdvp
, _err
, NOTE_WRITE
);
3963 vn_rename(struct vnode
*fdvp
, struct vnode
**fvpp
, struct componentname
*fcnp
, struct vnode_attr
*fvap
,
3964 struct vnode
*tdvp
, struct vnode
**tvpp
, struct componentname
*tcnp
, struct vnode_attr
*tvap
,
3965 vfs_rename_flags_t flags
, vfs_context_t ctx
)
3968 struct nameidata
*fromnd
= NULL
;
3969 struct nameidata
*tond
= NULL
;
3970 #if CONFIG_APPLEDOUBLE
3971 vnode_t src_attr_vp
= NULLVP
;
3972 vnode_t dst_attr_vp
= NULLVP
;
3973 char smallname1
[48];
3974 char smallname2
[48];
3975 char *xfromname
= NULL
;
3976 char *xtoname
= NULL
;
3977 #endif /* CONFIG_APPLEDOUBLE */
3979 uint32_t tdfflags
; // Target directory file flags
3981 batched
= vnode_compound_rename_available(fdvp
);
3984 if (*fvpp
== NULLVP
)
3985 panic("Not batched, and no fvp?");
3988 #if CONFIG_APPLEDOUBLE
3990 * We need to preflight any potential AppleDouble file for the source file
3991 * before doing the rename operation, since we could potentially be doing
3992 * this operation on a network filesystem, and would end up duplicating
3993 * the work. Also, save the source and destination names. Skip it if the
3994 * source has a "._" prefix.
3997 if (!NATIVE_XATTR(fdvp
) &&
3998 !(fcnp
->cn_nameptr
[0] == '.' && fcnp
->cn_nameptr
[1] == '_')) {
4002 /* Get source attribute file name. */
4003 len
= fcnp
->cn_namelen
+ 3;
4004 if (len
> sizeof(smallname1
)) {
4005 MALLOC(xfromname
, char *, len
, M_TEMP
, M_WAITOK
);
4007 xfromname
= &smallname1
[0];
4009 strlcpy(xfromname
, "._", min(sizeof smallname1
, len
));
4010 strncat(xfromname
, fcnp
->cn_nameptr
, fcnp
->cn_namelen
);
4011 xfromname
[len
-1] = '\0';
4013 /* Get destination attribute file name. */
4014 len
= tcnp
->cn_namelen
+ 3;
4015 if (len
> sizeof(smallname2
)) {
4016 MALLOC(xtoname
, char *, len
, M_TEMP
, M_WAITOK
);
4018 xtoname
= &smallname2
[0];
4020 strlcpy(xtoname
, "._", min(sizeof smallname2
, len
));
4021 strncat(xtoname
, tcnp
->cn_nameptr
, tcnp
->cn_namelen
);
4022 xtoname
[len
-1] = '\0';
4025 * Look up source attribute file, keep reference on it if exists.
4026 * Note that we do the namei with the nameiop of RENAME, which is different than
4027 * in the rename syscall. It's OK if the source file does not exist, since this
4028 * is only for AppleDouble files.
4030 MALLOC(fromnd
, struct nameidata
*, sizeof (struct nameidata
), M_TEMP
, M_WAITOK
);
4031 NDINIT(fromnd
, RENAME
, OP_RENAME
, NOFOLLOW
| USEDVP
| CN_NBMOUNTLOOK
,
4032 UIO_SYSSPACE
, CAST_USER_ADDR_T(xfromname
), ctx
);
4033 fromnd
->ni_dvp
= fdvp
;
4034 error
= namei(fromnd
);
4037 * If there was an error looking up source attribute file,
4038 * we'll behave as if it didn't exist.
4042 if (fromnd
->ni_vp
) {
4043 /* src_attr_vp indicates need to call vnode_put / nameidone later */
4044 src_attr_vp
= fromnd
->ni_vp
;
4046 if (fromnd
->ni_vp
->v_type
!= VREG
) {
4047 src_attr_vp
= NULLVP
;
4048 vnode_put(fromnd
->ni_vp
);
4052 * Either we got an invalid vnode type (not a regular file) or the namei lookup
4053 * suppressed ENOENT as a valid error since we're renaming. Either way, we don't
4054 * have a vnode here, so we drop our namei buffer for the source attribute file
4056 if (src_attr_vp
== NULLVP
) {
4061 #endif /* CONFIG_APPLEDOUBLE */
4064 _err
= VNOP_COMPOUND_RENAME(fdvp
, fvpp
, fcnp
, fvap
, tdvp
, tvpp
, tcnp
, tvap
, flags
, ctx
);
4066 printf("VNOP_COMPOUND_RENAME() returned %d\n", _err
);
4070 _err
= VNOP_RENAMEX(fdvp
, *fvpp
, fcnp
, tdvp
, *tvpp
, tcnp
, flags
, ctx
);
4071 if (_err
== ENOTSUP
&& flags
== VFS_RENAME_SECLUDE
) {
4073 if ((*fvpp
)->v_mount
->mnt_vtable
->vfc_vfsflags
& VFC_VFSVNOP_SECLUDE_RENAME
) {
4074 fcnp
->cn_flags
|= CN_SECLUDE_RENAME
;
4075 _err
= VNOP_RENAME(fdvp
, *fvpp
, fcnp
, tdvp
, *tvpp
, tcnp
, ctx
);
4079 _err
= VNOP_RENAME(fdvp
, *fvpp
, fcnp
, tdvp
, *tvpp
, tcnp
, ctx
);
4083 * If moved to a new directory that is restricted,
4084 * set the restricted flag on the item moved.
4087 _err
= vnode_flags(tdvp
, &tdfflags
, ctx
);
4089 uint32_t inherit_flags
= tdfflags
& (UF_DATAVAULT
| SF_RESTRICTED
);
4090 if (inherit_flags
) {
4092 _err
= vnode_flags(*fvpp
, &fflags
, ctx
);
4093 if (_err
== 0 && fflags
!= (fflags
| inherit_flags
)) {
4094 struct vnode_attr va
;
4096 VATTR_SET(&va
, va_flags
, fflags
| inherit_flags
);
4097 _err
= vnode_setattr(*fvpp
, &va
, ctx
);
4105 mac_vnode_notify_rename(ctx
, *fvpp
, tdvp
, tcnp
);
4109 #if CONFIG_APPLEDOUBLE
4111 * Rename any associated extended attribute file (._ AppleDouble file).
4113 if (_err
== 0 && !NATIVE_XATTR(fdvp
) && xfromname
!= NULL
) {
4117 * Get destination attribute file vnode.
4118 * Note that tdvp already has an iocount reference. Make sure to check that we
4119 * get a valid vnode from namei.
4121 MALLOC(tond
, struct nameidata
*, sizeof(struct nameidata
), M_TEMP
, M_WAITOK
);
4122 NDINIT(tond
, RENAME
, OP_RENAME
,
4123 NOCACHE
| NOFOLLOW
| USEDVP
| CN_NBMOUNTLOOK
, UIO_SYSSPACE
,
4124 CAST_USER_ADDR_T(xtoname
), ctx
);
4125 tond
->ni_dvp
= tdvp
;
4126 error
= namei(tond
);
4132 dst_attr_vp
= tond
->ni_vp
;
4136 const char *old_name
= src_attr_vp
->v_name
;
4137 vnode_t old_parent
= src_attr_vp
->v_parent
;
4140 error
= VNOP_COMPOUND_RENAME(fdvp
, &src_attr_vp
, &fromnd
->ni_cnd
, NULL
,
4141 tdvp
, &dst_attr_vp
, &tond
->ni_cnd
, NULL
,
4144 error
= VNOP_RENAME(fdvp
, src_attr_vp
, &fromnd
->ni_cnd
,
4145 tdvp
, dst_attr_vp
, &tond
->ni_cnd
, ctx
);
4148 if (error
== 0 && old_name
== src_attr_vp
->v_name
&&
4149 old_parent
== src_attr_vp
->v_parent
) {
4150 int update_flags
= VNODE_UPDATE_NAME
;
4153 update_flags
|= VNODE_UPDATE_PARENT
;
4155 if ((src_attr_vp
->v_mount
->mnt_vtable
->vfc_vfsflags
& VFC_VFSVNOP_NOUPDATEID_RENAME
) == 0) {
4156 vnode_update_identity(src_attr_vp
, tdvp
,
4157 tond
->ni_cnd
.cn_nameptr
,
4158 tond
->ni_cnd
.cn_namelen
,
4159 tond
->ni_cnd
.cn_hash
,
4164 /* kevent notifications for moving resource files
4165 * _err is zero if we're here, so no need to notify directories, code
4166 * below will do that. only need to post the rename on the source and
4167 * possibly a delete on the dest
4169 post_event_if_success(src_attr_vp
, error
, NOTE_RENAME
);
4171 post_event_if_success(dst_attr_vp
, error
, NOTE_DELETE
);
4174 } else if (dst_attr_vp
) {
4176 * Just delete destination attribute file vnode if it exists, since
4177 * we didn't have a source attribute file.
4178 * Note that tdvp already has an iocount reference.
4181 struct vnop_remove_args args
;
4183 args
.a_desc
= &vnop_remove_desc
;
4185 args
.a_vp
= dst_attr_vp
;
4186 args
.a_cnp
= &tond
->ni_cnd
;
4187 args
.a_context
= ctx
;
4190 error
= (*tdvp
->v_op
[vnop_remove_desc
.vdesc_offset
])(&args
);
4193 vnode_setneedinactive(dst_attr_vp
);
4196 /* kevent notification for deleting the destination's attribute file
4197 * if it existed. Only need to post the delete on the destination, since
4198 * the code below will handle the directories.
4200 post_event_if_success(dst_attr_vp
, error
, NOTE_DELETE
);
4205 vnode_put(src_attr_vp
);
4209 vnode_put(dst_attr_vp
);
4212 if (xfromname
&& xfromname
!= &smallname1
[0]) {
4213 FREE(xfromname
, M_TEMP
);
4215 if (xtoname
&& xtoname
!= &smallname2
[0]) {
4216 FREE(xtoname
, M_TEMP
);
4218 #endif /* CONFIG_APPLEDOUBLE */
4220 FREE(fromnd
, M_TEMP
);
4232 *#% rename fdvp U U U
4233 *#% rename fvp U U U
4234 *#% rename tdvp L U U
4235 *#% rename tvp X U U
4238 struct vnop_rename_args
{
4239 struct vnodeop_desc
*a_desc
;
4242 struct componentname
*a_fcnp
;
4245 struct componentname
*a_tcnp
;
4246 vfs_context_t a_context
;
4250 VNOP_RENAME(struct vnode
*fdvp
, struct vnode
*fvp
, struct componentname
*fcnp
,
4251 struct vnode
*tdvp
, struct vnode
*tvp
, struct componentname
*tcnp
,
4255 struct vnop_rename_args a
;
4257 a
.a_desc
= &vnop_rename_desc
;
4266 /* do the rename of the main file. */
4267 _err
= (*fdvp
->v_op
[vnop_rename_desc
.vdesc_offset
])(&a
);
4268 DTRACE_FSINFO(rename
, vnode_t
, fdvp
);
4273 return post_rename(fdvp
, fvp
, tdvp
, tvp
);
4277 post_rename(vnode_t fdvp
, vnode_t fvp
, vnode_t tdvp
, vnode_t tvp
)
4279 if (tvp
&& tvp
!= fvp
)
4280 vnode_setneedinactive(tvp
);
4282 /* Wrote at least one directory. If transplanted a dir, also changed link counts */
4283 int events
= NOTE_WRITE
;
4284 if (vnode_isdir(fvp
)) {
4285 /* Link count on dir changed only if we are moving a dir and...
4286 * --Moved to new dir, not overwriting there
4287 * --Kept in same dir and DID overwrite
4289 if (((fdvp
!= tdvp
) && (!tvp
)) || ((fdvp
== tdvp
) && (tvp
))) {
4290 events
|= NOTE_LINK
;
4294 lock_vnode_and_post(fdvp
, events
);
4296 lock_vnode_and_post(tdvp
, events
);
4299 /* If you're replacing the target, post a deletion for it */
4302 lock_vnode_and_post(tvp
, NOTE_DELETE
);
4305 lock_vnode_and_post(fvp
, NOTE_RENAME
);
4313 *#% renamex fdvp U U U
4314 *#% renamex fvp U U U
4315 *#% renamex tdvp L U U
4316 *#% renamex tvp X U U
4319 struct vnop_renamex_args
{
4320 struct vnodeop_desc
*a_desc
;
4323 struct componentname
*a_fcnp
;
4326 struct componentname
*a_tcnp
;
4327 vfs_rename_flags_t a_flags
;
4328 vfs_context_t a_context
;
4332 VNOP_RENAMEX(struct vnode
*fdvp
, struct vnode
*fvp
, struct componentname
*fcnp
,
4333 struct vnode
*tdvp
, struct vnode
*tvp
, struct componentname
*tcnp
,
4334 vfs_rename_flags_t flags
, vfs_context_t ctx
)
4337 struct vnop_renamex_args a
;
4339 a
.a_desc
= &vnop_renamex_desc
;
4349 /* do the rename of the main file. */
4350 _err
= (*fdvp
->v_op
[vnop_renamex_desc
.vdesc_offset
])(&a
);
4351 DTRACE_FSINFO(renamex
, vnode_t
, fdvp
);
4356 return post_rename(fdvp
, fvp
, tdvp
, tvp
);
4361 VNOP_COMPOUND_RENAME(
4362 struct vnode
*fdvp
, struct vnode
**fvpp
, struct componentname
*fcnp
, struct vnode_attr
*fvap
,
4363 struct vnode
*tdvp
, struct vnode
**tvpp
, struct componentname
*tcnp
, struct vnode_attr
*tvap
,
4364 uint32_t flags
, vfs_context_t ctx
)
4368 struct vnop_compound_rename_args a
;
4371 no_fvp
= (*fvpp
) == NULLVP
;
4372 no_tvp
= (*tvpp
) == NULLVP
;
4374 a
.a_desc
= &vnop_compound_rename_desc
;
4388 a
.a_rename_authorizer
= vn_authorize_rename
;
4389 a
.a_reserved
= NULL
;
4391 /* do the rename of the main file. */
4392 _err
= (*fdvp
->v_op
[vnop_compound_rename_desc
.vdesc_offset
])(&a
);
4393 DTRACE_FSINFO(compound_rename
, vnode_t
, fdvp
);
4396 if (*tvpp
&& *tvpp
!= *fvpp
)
4397 vnode_setneedinactive(*tvpp
);
4400 /* Wrote at least one directory. If transplanted a dir, also changed link counts */
4401 if (_err
== 0 && *fvpp
!= *tvpp
) {
4403 panic("No fvpp after compound rename?");
4406 events
= NOTE_WRITE
;
4407 if (vnode_isdir(*fvpp
)) {
4408 /* Link count on dir changed only if we are moving a dir and...
4409 * --Moved to new dir, not overwriting there
4410 * --Kept in same dir and DID overwrite
4412 if (((fdvp
!= tdvp
) && (!*tvpp
)) || ((fdvp
== tdvp
) && (*tvpp
))) {
4413 events
|= NOTE_LINK
;
4417 lock_vnode_and_post(fdvp
, events
);
4419 lock_vnode_and_post(tdvp
, events
);
4422 /* If you're replacing the target, post a deletion for it */
4425 lock_vnode_and_post(*tvpp
, NOTE_DELETE
);
4428 lock_vnode_and_post(*fvpp
, NOTE_RENAME
);
4432 lookup_compound_vnop_post_hook(_err
, fdvp
, *fvpp
, fcnp
->cn_ndp
, 0);
4434 if (no_tvp
&& *tvpp
!= NULLVP
) {
4435 lookup_compound_vnop_post_hook(_err
, tdvp
, *tvpp
, tcnp
->cn_ndp
, 0);
4438 if (_err
&& _err
!= EKEEPLOOKING
) {
4453 vn_mkdir(struct vnode
*dvp
, struct vnode
**vpp
, struct nameidata
*ndp
,
4454 struct vnode_attr
*vap
, vfs_context_t ctx
)
4456 if (ndp
->ni_cnd
.cn_nameiop
!= CREATE
) {
4457 panic("Non-CREATE nameiop in vn_mkdir()?");
4460 if (vnode_compound_mkdir_available(dvp
)) {
4461 return VNOP_COMPOUND_MKDIR(dvp
, vpp
, ndp
, vap
, ctx
);
4463 return VNOP_MKDIR(dvp
, vpp
, &ndp
->ni_cnd
, vap
, ctx
);
4474 struct vnop_mkdir_args
{
4475 struct vnodeop_desc
*a_desc
;
4478 struct componentname
*a_cnp
;
4479 struct vnode_attr
*a_vap
;
4480 vfs_context_t a_context
;
4484 VNOP_MKDIR(struct vnode
*dvp
, struct vnode
**vpp
, struct componentname
*cnp
,
4485 struct vnode_attr
*vap
, vfs_context_t ctx
)
4488 struct vnop_mkdir_args a
;
4490 a
.a_desc
= &vnop_mkdir_desc
;
4497 _err
= (*dvp
->v_op
[vnop_mkdir_desc
.vdesc_offset
])(&a
);
4498 if (_err
== 0 && *vpp
) {
4499 DTRACE_FSINFO(mkdir
, vnode_t
, *vpp
);
4501 #if CONFIG_APPLEDOUBLE
4502 if (_err
== 0 && !NATIVE_XATTR(dvp
)) {
4504 * Remove stale Apple Double file (if any).
4506 xattrfile_remove(dvp
, cnp
->cn_nameptr
, ctx
, 0);
4508 #endif /* CONFIG_APPLEDOUBLE */
4510 post_event_if_success(dvp
, _err
, NOTE_LINK
| NOTE_WRITE
);
4516 VNOP_COMPOUND_MKDIR(struct vnode
*dvp
, struct vnode
**vpp
, struct nameidata
*ndp
,
4517 struct vnode_attr
*vap
, vfs_context_t ctx
)
4520 struct vnop_compound_mkdir_args a
;
4522 a
.a_desc
= &vnop_compound_mkdir_desc
;
4525 a
.a_cnp
= &ndp
->ni_cnd
;
4530 a
.a_mkdir_authorizer
= vn_authorize_mkdir
;
4532 a
.a_reserved
= NULL
;
4534 _err
= (*dvp
->v_op
[vnop_compound_mkdir_desc
.vdesc_offset
])(&a
);
4535 if (_err
== 0 && *vpp
) {
4536 DTRACE_FSINFO(compound_mkdir
, vnode_t
, *vpp
);
4538 #if CONFIG_APPLEDOUBLE
4539 if (_err
== 0 && !NATIVE_XATTR(dvp
)) {
4541 * Remove stale Apple Double file (if any).
4543 xattrfile_remove(dvp
, ndp
->ni_cnd
.cn_nameptr
, ctx
, 0);
4545 #endif /* CONFIG_APPLEDOUBLE */
4547 post_event_if_success(dvp
, _err
, NOTE_LINK
| NOTE_WRITE
);
4549 lookup_compound_vnop_post_hook(_err
, dvp
, *vpp
, ndp
, (_err
== 0));
4550 if (*vpp
&& _err
&& _err
!= EKEEPLOOKING
) {
4559 vn_rmdir(vnode_t dvp
, vnode_t
*vpp
, struct nameidata
*ndp
, struct vnode_attr
*vap
, vfs_context_t ctx
)
4561 if (vnode_compound_rmdir_available(dvp
)) {
4562 return VNOP_COMPOUND_RMDIR(dvp
, vpp
, ndp
, vap
, ctx
);
4564 if (*vpp
== NULLVP
) {
4565 panic("NULL vp, but not a compound VNOP?");
4568 panic("Non-NULL vap, but not a compound VNOP?");
4570 return VNOP_RMDIR(dvp
, *vpp
, &ndp
->ni_cnd
, ctx
);
4581 struct vnop_rmdir_args
{
4582 struct vnodeop_desc
*a_desc
;
4585 struct componentname
*a_cnp
;
4586 vfs_context_t a_context
;
4591 VNOP_RMDIR(struct vnode
*dvp
, struct vnode
*vp
, struct componentname
*cnp
, vfs_context_t ctx
)
4594 struct vnop_rmdir_args a
;
4596 a
.a_desc
= &vnop_rmdir_desc
;
4602 _err
= (*vp
->v_op
[vnop_rmdir_desc
.vdesc_offset
])(&a
);
4603 DTRACE_FSINFO(rmdir
, vnode_t
, vp
);
4606 vnode_setneedinactive(vp
);
4607 #if CONFIG_APPLEDOUBLE
4608 if ( !(NATIVE_XATTR(dvp
)) ) {
4610 * Remove any associated extended attribute file (._ AppleDouble file).
4612 xattrfile_remove(dvp
, cnp
->cn_nameptr
, ctx
, 1);
4617 /* If you delete a dir, it loses its "." reference --> NOTE_LINK */
4618 post_event_if_success(vp
, _err
, NOTE_DELETE
| NOTE_LINK
);
4619 post_event_if_success(dvp
, _err
, NOTE_LINK
| NOTE_WRITE
);
4625 VNOP_COMPOUND_RMDIR(struct vnode
*dvp
, struct vnode
**vpp
, struct nameidata
*ndp
,
4626 struct vnode_attr
*vap
, vfs_context_t ctx
)
4629 struct vnop_compound_rmdir_args a
;
4632 a
.a_desc
= &vnop_mkdir_desc
;
4635 a
.a_cnp
= &ndp
->ni_cnd
;
4639 a
.a_rmdir_authorizer
= vn_authorize_rmdir
;
4640 a
.a_reserved
= NULL
;
4642 no_vp
= (*vpp
== NULLVP
);
4644 _err
= (*dvp
->v_op
[vnop_compound_rmdir_desc
.vdesc_offset
])(&a
);
4645 if (_err
== 0 && *vpp
) {
4646 DTRACE_FSINFO(compound_rmdir
, vnode_t
, *vpp
);
4648 #if CONFIG_APPLEDOUBLE
4649 if (_err
== 0 && !NATIVE_XATTR(dvp
)) {
4651 * Remove stale Apple Double file (if any).
4653 xattrfile_remove(dvp
, ndp
->ni_cnd
.cn_nameptr
, ctx
, 0);
4658 post_event_if_success(*vpp
, _err
, NOTE_DELETE
| NOTE_LINK
);
4660 post_event_if_success(dvp
, _err
, NOTE_LINK
| NOTE_WRITE
);
4663 lookup_compound_vnop_post_hook(_err
, dvp
, *vpp
, ndp
, 0);
4665 #if 0 /* Removing orphaned ._ files requires a vp.... */
4666 if (*vpp
&& _err
&& _err
!= EKEEPLOOKING
) {
4676 #if CONFIG_APPLEDOUBLE
4678 * Remove a ._ AppleDouble file
4680 #define AD_STALE_SECS (180)
4682 xattrfile_remove(vnode_t dvp
, const char * basename
, vfs_context_t ctx
, int force
)
4685 struct nameidata nd
;
4687 char *filename
= NULL
;
4690 if ((basename
== NULL
) || (basename
[0] == '\0') ||
4691 (basename
[0] == '.' && basename
[1] == '_')) {
4694 filename
= &smallname
[0];
4695 len
= snprintf(filename
, sizeof(smallname
), "._%s", basename
);
4696 if (len
>= sizeof(smallname
)) {
4697 len
++; /* snprintf result doesn't include '\0' */
4698 MALLOC(filename
, char *, len
, M_TEMP
, M_WAITOK
);
4699 len
= snprintf(filename
, len
, "._%s", basename
);
4701 NDINIT(&nd
, DELETE
, OP_UNLINK
, WANTPARENT
| LOCKLEAF
| NOFOLLOW
| USEDVP
, UIO_SYSSPACE
,
4702 CAST_USER_ADDR_T(filename
), ctx
);
4704 if (namei(&nd
) != 0)
4709 if (xvp
->v_type
!= VREG
)
4713 * When creating a new object and a "._" file already
4714 * exists, check to see if its a stale "._" file.
4718 struct vnode_attr va
;
4721 VATTR_WANTED(&va
, va_data_size
);
4722 VATTR_WANTED(&va
, va_modify_time
);
4723 if (VNOP_GETATTR(xvp
, &va
, ctx
) == 0 &&
4724 VATTR_IS_SUPPORTED(&va
, va_data_size
) &&
4725 VATTR_IS_SUPPORTED(&va
, va_modify_time
) &&
4726 va
.va_data_size
!= 0) {
4730 if ((tv
.tv_sec
> va
.va_modify_time
.tv_sec
) &&
4731 (tv
.tv_sec
- va
.va_modify_time
.tv_sec
) > AD_STALE_SECS
) {
4732 force
= 1; /* must be stale */
4739 error
= VNOP_REMOVE(dvp
, xvp
, &nd
.ni_cnd
, 0, ctx
);
4741 vnode_setneedinactive(xvp
);
4743 post_event_if_success(xvp
, error
, NOTE_DELETE
);
4744 post_event_if_success(dvp
, error
, NOTE_WRITE
);
4751 if (filename
&& filename
!= &smallname
[0]) {
4752 FREE(filename
, M_TEMP
);
4757 * Shadow uid/gid/mod to a ._ AppleDouble file
4760 xattrfile_setattr(vnode_t dvp
, const char * basename
, struct vnode_attr
* vap
,
4764 struct nameidata nd
;
4766 char *filename
= NULL
;
4769 if ((dvp
== NULLVP
) ||
4770 (basename
== NULL
) || (basename
[0] == '\0') ||
4771 (basename
[0] == '.' && basename
[1] == '_')) {
4774 filename
= &smallname
[0];
4775 len
= snprintf(filename
, sizeof(smallname
), "._%s", basename
);
4776 if (len
>= sizeof(smallname
)) {
4777 len
++; /* snprintf result doesn't include '\0' */
4778 MALLOC(filename
, char *, len
, M_TEMP
, M_WAITOK
);
4779 len
= snprintf(filename
, len
, "._%s", basename
);
4781 NDINIT(&nd
, LOOKUP
, OP_SETATTR
, NOFOLLOW
| USEDVP
, UIO_SYSSPACE
,
4782 CAST_USER_ADDR_T(filename
), ctx
);
4784 if (namei(&nd
) != 0)
4790 if (xvp
->v_type
== VREG
) {
4791 struct vnop_setattr_args a
;
4793 a
.a_desc
= &vnop_setattr_desc
;
4798 (void) (*xvp
->v_op
[vnop_setattr_desc
.vdesc_offset
])(&a
);
4803 if (filename
&& filename
!= &smallname
[0]) {
4804 FREE(filename
, M_TEMP
);
4807 #endif /* CONFIG_APPLEDOUBLE */
4812 *#% symlink dvp L U U
4813 *#% symlink vpp - U -
4816 struct vnop_symlink_args
{
4817 struct vnodeop_desc
*a_desc
;
4820 struct componentname
*a_cnp
;
4821 struct vnode_attr
*a_vap
;
4823 vfs_context_t a_context
;
4828 VNOP_SYMLINK(struct vnode
*dvp
, struct vnode
**vpp
, struct componentname
*cnp
,
4829 struct vnode_attr
*vap
, char *target
, vfs_context_t ctx
)
4832 struct vnop_symlink_args a
;
4834 a
.a_desc
= &vnop_symlink_desc
;
4839 a
.a_target
= target
;
4842 _err
= (*dvp
->v_op
[vnop_symlink_desc
.vdesc_offset
])(&a
);
4843 DTRACE_FSINFO(symlink
, vnode_t
, dvp
);
4844 #if CONFIG_APPLEDOUBLE
4845 if (_err
== 0 && !NATIVE_XATTR(dvp
)) {
4847 * Remove stale Apple Double file (if any). Posts its own knotes
4849 xattrfile_remove(dvp
, cnp
->cn_nameptr
, ctx
, 0);
4851 #endif /* CONFIG_APPLEDOUBLE */
4853 post_event_if_success(dvp
, _err
, NOTE_WRITE
);
4861 *#% readdir vp L L L
4864 struct vnop_readdir_args
{
4865 struct vnodeop_desc
*a_desc
;
4871 vfs_context_t a_context
;
4876 VNOP_READDIR(struct vnode
*vp
, struct uio
*uio
, int flags
, int *eofflag
,
4877 int *numdirent
, vfs_context_t ctx
)
4880 struct vnop_readdir_args a
;
4882 user_ssize_t resid
= uio_resid(uio
);
4885 a
.a_desc
= &vnop_readdir_desc
;
4889 a
.a_eofflag
= eofflag
;
4890 a
.a_numdirent
= numdirent
;
4893 _err
= (*vp
->v_op
[vnop_readdir_desc
.vdesc_offset
])(&a
);
4894 DTRACE_FSINFO_IO(readdir
,
4895 vnode_t
, vp
, user_ssize_t
, (resid
- uio_resid(uio
)));
4903 *#% readdirattr vp L L L
4906 struct vnop_readdirattr_args
{
4907 struct vnodeop_desc
*a_desc
;
4909 struct attrlist
*a_alist
;
4911 uint32_t a_maxcount
;
4913 uint32_t *a_newstate
;
4915 uint32_t *a_actualcount
;
4916 vfs_context_t a_context
;
4921 VNOP_READDIRATTR(struct vnode
*vp
, struct attrlist
*alist
, struct uio
*uio
, uint32_t maxcount
,
4922 uint32_t options
, uint32_t *newstate
, int *eofflag
, uint32_t *actualcount
, vfs_context_t ctx
)
4925 struct vnop_readdirattr_args a
;
4927 user_ssize_t resid
= uio_resid(uio
);
4930 a
.a_desc
= &vnop_readdirattr_desc
;
4934 a
.a_maxcount
= maxcount
;
4935 a
.a_options
= options
;
4936 a
.a_newstate
= newstate
;
4937 a
.a_eofflag
= eofflag
;
4938 a
.a_actualcount
= actualcount
;
4941 _err
= (*vp
->v_op
[vnop_readdirattr_desc
.vdesc_offset
])(&a
);
4942 DTRACE_FSINFO_IO(readdirattr
,
4943 vnode_t
, vp
, user_ssize_t
, (resid
- uio_resid(uio
)));
4949 struct vnop_getttrlistbulk_args
{
4950 struct vnodeop_desc
*a_desc
;
4952 struct attrlist
*a_alist
;
4953 struct vnode_attr
*a_vap
;
4958 uint32_t *a_actualcount
;
4959 vfs_context_t a_context
;
4963 VNOP_GETATTRLISTBULK(struct vnode
*vp
, struct attrlist
*alist
,
4964 struct vnode_attr
*vap
, struct uio
*uio
, void *private, uint64_t options
,
4965 int32_t *eofflag
, int32_t *actualcount
, vfs_context_t ctx
)
4968 struct vnop_getattrlistbulk_args a
;
4970 user_ssize_t resid
= uio_resid(uio
);
4973 a
.a_desc
= &vnop_getattrlistbulk_desc
;
4978 a
.a_private
= private;
4979 a
.a_options
= options
;
4980 a
.a_eofflag
= eofflag
;
4981 a
.a_actualcount
= actualcount
;
4984 _err
= (*vp
->v_op
[vnop_getattrlistbulk_desc
.vdesc_offset
])(&a
);
4985 DTRACE_FSINFO_IO(getattrlistbulk
,
4986 vnode_t
, vp
, user_ssize_t
, (resid
- uio_resid(uio
)));
4994 *#% readlink vp L L L
4997 struct vnop_readlink_args
{
4998 struct vnodeop_desc
*a_desc
;
5001 vfs_context_t a_context
;
5006 * Returns: 0 Success
5007 * lock_fsnode:ENOENT No such file or directory [only for VFS
5008 * that is not thread safe & vnode is
5009 * currently being/has been terminated]
5010 * <vfs_readlink>:EINVAL
5011 * <vfs_readlink>:???
5013 * Note: The return codes from the underlying VFS's readlink routine
5014 * can't be fully enumerated here, since third party VFS authors
5015 * may not limit their error returns to the ones documented here,
5016 * even though this may result in some programs functioning
5019 * The return codes documented above are those which may currently
5020 * be returned by HFS from hfs_vnop_readlink, not including
5021 * additional error code which may be propagated from underlying
5025 VNOP_READLINK(struct vnode
*vp
, struct uio
*uio
, vfs_context_t ctx
)
5028 struct vnop_readlink_args a
;
5030 user_ssize_t resid
= uio_resid(uio
);
5032 a
.a_desc
= &vnop_readlink_desc
;
5037 _err
= (*vp
->v_op
[vnop_readlink_desc
.vdesc_offset
])(&a
);
5038 DTRACE_FSINFO_IO(readlink
,
5039 vnode_t
, vp
, user_ssize_t
, (resid
- uio_resid(uio
)));
5047 *#% inactive vp L U U
5050 struct vnop_inactive_args
{
5051 struct vnodeop_desc
*a_desc
;
5053 vfs_context_t a_context
;
5057 VNOP_INACTIVE(struct vnode
*vp
, vfs_context_t ctx
)
5060 struct vnop_inactive_args a
;
5062 a
.a_desc
= &vnop_inactive_desc
;
5066 _err
= (*vp
->v_op
[vnop_inactive_desc
.vdesc_offset
])(&a
);
5067 DTRACE_FSINFO(inactive
, vnode_t
, vp
);
5070 /* For file systems that do not support namedstream natively, mark
5071 * the shadow stream file vnode to be recycled as soon as the last
5072 * reference goes away. To avoid re-entering reclaim code, do not
5073 * call recycle on terminating namedstream vnodes.
5075 if (vnode_isnamedstream(vp
) &&
5076 (vp
->v_parent
!= NULLVP
) &&
5077 vnode_isshadow(vp
) &&
5078 ((vp
->v_lflag
& VL_TERMINATE
) == 0)) {
5090 *#% reclaim vp U U U
5093 struct vnop_reclaim_args
{
5094 struct vnodeop_desc
*a_desc
;
5096 vfs_context_t a_context
;
5100 VNOP_RECLAIM(struct vnode
*vp
, vfs_context_t ctx
)
5103 struct vnop_reclaim_args a
;
5105 a
.a_desc
= &vnop_reclaim_desc
;
5109 _err
= (*vp
->v_op
[vnop_reclaim_desc
.vdesc_offset
])(&a
);
5110 DTRACE_FSINFO(reclaim
, vnode_t
, vp
);
5117 * Returns: 0 Success
5118 * lock_fsnode:ENOENT No such file or directory [only for VFS
5119 * that is not thread safe & vnode is
5120 * currently being/has been terminated]
5121 * <vnop_pathconf_desc>:??? [per FS implementation specific]
5126 *#% pathconf vp L L L
5129 struct vnop_pathconf_args
{
5130 struct vnodeop_desc
*a_desc
;
5134 vfs_context_t a_context
;
5138 VNOP_PATHCONF(struct vnode
*vp
, int name
, int32_t *retval
, vfs_context_t ctx
)
5141 struct vnop_pathconf_args a
;
5143 a
.a_desc
= &vnop_pathconf_desc
;
5146 a
.a_retval
= retval
;
5149 _err
= (*vp
->v_op
[vnop_pathconf_desc
.vdesc_offset
])(&a
);
5150 DTRACE_FSINFO(pathconf
, vnode_t
, vp
);
5156 * Returns: 0 Success
5157 * err_advlock:ENOTSUP
5159 * <vnop_advlock_desc>:???
5161 * Notes: VFS implementations of advisory locking using calls through
5162 * <vnop_advlock_desc> because lock enforcement does not occur
5163 * locally should try to limit themselves to the return codes
5164 * documented above for lf_advlock and err_advlock.
5169 *#% advlock vp U U U
5172 struct vnop_advlock_args
{
5173 struct vnodeop_desc
*a_desc
;
5179 vfs_context_t a_context
;
5183 VNOP_ADVLOCK(struct vnode
*vp
, caddr_t id
, int op
, struct flock
*fl
, int flags
, vfs_context_t ctx
, struct timespec
*timeout
)
5186 struct vnop_advlock_args a
;
5188 a
.a_desc
= &vnop_advlock_desc
;
5195 a
.a_timeout
= timeout
;
5197 /* Disallow advisory locking on non-seekable vnodes */
5198 if (vnode_isfifo(vp
)) {
5199 _err
= err_advlock(&a
);
5201 if ((vp
->v_flag
& VLOCKLOCAL
)) {
5202 /* Advisory locking done at this layer */
5203 _err
= lf_advlock(&a
);
5204 } else if (flags
& F_OFD_LOCK
) {
5205 /* Non-local locking doesn't work for OFD locks */
5206 _err
= err_advlock(&a
);
5208 /* Advisory locking done by underlying filesystem */
5209 _err
= (*vp
->v_op
[vnop_advlock_desc
.vdesc_offset
])(&a
);
5211 DTRACE_FSINFO(advlock
, vnode_t
, vp
);
5212 if (op
== F_UNLCK
&& flags
== F_FLOCK
)
5213 post_event_if_success(vp
, _err
, NOTE_FUNLOCK
);
5224 *#% allocate vp L L L
5227 struct vnop_allocate_args
{
5228 struct vnodeop_desc
*a_desc
;
5232 off_t
*a_bytesallocated
;
5234 vfs_context_t a_context
;
5239 VNOP_ALLOCATE(struct vnode
*vp
, off_t length
, u_int32_t flags
, off_t
*bytesallocated
, off_t offset
, vfs_context_t ctx
)
5242 struct vnop_allocate_args a
;
5244 a
.a_desc
= &vnop_allocate_desc
;
5246 a
.a_length
= length
;
5248 a
.a_bytesallocated
= bytesallocated
;
5249 a
.a_offset
= offset
;
5252 _err
= (*vp
->v_op
[vnop_allocate_desc
.vdesc_offset
])(&a
);
5253 DTRACE_FSINFO(allocate
, vnode_t
, vp
);
5256 add_fsevent(FSE_STAT_CHANGED
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
5269 struct vnop_pagein_args
{
5270 struct vnodeop_desc
*a_desc
;
5273 upl_offset_t a_pl_offset
;
5277 vfs_context_t a_context
;
5281 VNOP_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
)
5284 struct vnop_pagein_args a
;
5286 a
.a_desc
= &vnop_pagein_desc
;
5289 a
.a_pl_offset
= pl_offset
;
5290 a
.a_f_offset
= f_offset
;
5295 _err
= (*vp
->v_op
[vnop_pagein_desc
.vdesc_offset
])(&a
);
5296 DTRACE_FSINFO(pagein
, vnode_t
, vp
);
5304 *#% pageout vp = = =
5307 struct vnop_pageout_args
{
5308 struct vnodeop_desc
*a_desc
;
5311 upl_offset_t a_pl_offset
;
5315 vfs_context_t a_context
;
5320 VNOP_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
)
5323 struct vnop_pageout_args a
;
5325 a
.a_desc
= &vnop_pageout_desc
;
5328 a
.a_pl_offset
= pl_offset
;
5329 a
.a_f_offset
= f_offset
;
5334 _err
= (*vp
->v_op
[vnop_pageout_desc
.vdesc_offset
])(&a
);
5335 DTRACE_FSINFO(pageout
, vnode_t
, vp
);
5337 post_event_if_success(vp
, _err
, NOTE_WRITE
);
5343 vn_remove(vnode_t dvp
, vnode_t
*vpp
, struct nameidata
*ndp
, int32_t flags
, struct vnode_attr
*vap
, vfs_context_t ctx
)
5345 if (vnode_compound_remove_available(dvp
)) {
5346 return VNOP_COMPOUND_REMOVE(dvp
, vpp
, ndp
, flags
, vap
, ctx
);
5348 return VNOP_REMOVE(dvp
, *vpp
, &ndp
->ni_cnd
, flags
, ctx
);
5357 *#% searchfs vp L L L
5360 struct vnop_searchfs_args
{
5361 struct vnodeop_desc
*a_desc
;
5363 void *a_searchparams1
;
5364 void *a_searchparams2
;
5365 struct attrlist
*a_searchattrs
;
5366 uint32_t a_maxmatches
;
5367 struct timeval
*a_timelimit
;
5368 struct attrlist
*a_returnattrs
;
5369 uint32_t *a_nummatches
;
5370 uint32_t a_scriptcode
;
5373 struct searchstate
*a_searchstate
;
5374 vfs_context_t a_context
;
5379 VNOP_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
)
5382 struct vnop_searchfs_args a
;
5384 a
.a_desc
= &vnop_searchfs_desc
;
5386 a
.a_searchparams1
= searchparams1
;
5387 a
.a_searchparams2
= searchparams2
;
5388 a
.a_searchattrs
= searchattrs
;
5389 a
.a_maxmatches
= maxmatches
;
5390 a
.a_timelimit
= timelimit
;
5391 a
.a_returnattrs
= returnattrs
;
5392 a
.a_nummatches
= nummatches
;
5393 a
.a_scriptcode
= scriptcode
;
5394 a
.a_options
= options
;
5396 a
.a_searchstate
= searchstate
;
5399 _err
= (*vp
->v_op
[vnop_searchfs_desc
.vdesc_offset
])(&a
);
5400 DTRACE_FSINFO(searchfs
, vnode_t
, vp
);
5404 #endif /* CONFIG_SEARCHFS */
5409 *#% copyfile fvp U U U
5410 *#% copyfile tdvp L U U
5411 *#% copyfile tvp X U U
5414 struct vnop_copyfile_args
{
5415 struct vnodeop_desc
*a_desc
;
5419 struct componentname
*a_tcnp
;
5422 vfs_context_t a_context
;
5426 VNOP_COPYFILE(struct vnode
*fvp
, struct vnode
*tdvp
, struct vnode
*tvp
, struct componentname
*tcnp
,
5427 int mode
, int flags
, vfs_context_t ctx
)
5430 struct vnop_copyfile_args a
;
5431 a
.a_desc
= &vnop_copyfile_desc
;
5439 _err
= (*fvp
->v_op
[vnop_copyfile_desc
.vdesc_offset
])(&a
);
5440 DTRACE_FSINFO(copyfile
, vnode_t
, fvp
);
5445 struct vnop_clonefile_args
{
5446 struct vnodeop_desc
*a_desc
;
5450 struct componentname
*a_cnp
;
5451 struct vnode_attr
*a_vap
;
5453 vfs_context_t a_context
;
5454 int (*a_dir_clone_authorizer
)( /* Authorization callback */
5455 struct vnode_attr
*vap
, /* attribute to be authorized */
5456 kauth_action_t action
, /* action for which attribute is to be authorized */
5457 struct vnode_attr
*dvap
, /* target directory attributes */
5458 vnode_t sdvp
, /* source directory vnode pointer (optional) */
5459 mount_t mp
, /* mount point of filesystem */
5460 dir_clone_authorizer_op_t vattr_op
, /* specific operation requested : setup, authorization or cleanup */
5461 uint32_t flags
; /* value passed in a_flags to the VNOP */
5462 vfs_context_t ctx
, /* As passed to VNOP */
5463 void *reserved
); /* Always NULL */
5464 void *a_reserved
; /* Currently unused */
5469 VNOP_CLONEFILE(vnode_t fvp
, vnode_t dvp
, vnode_t
*vpp
,
5470 struct componentname
*cnp
, struct vnode_attr
*vap
, uint32_t flags
,
5474 struct vnop_clonefile_args a
;
5475 a
.a_desc
= &vnop_clonefile_desc
;
5484 if (vnode_vtype(fvp
) == VDIR
)
5485 a
.a_dir_clone_authorizer
= vnode_attr_authorize_dir_clone
;
5487 a
.a_dir_clone_authorizer
= NULL
;
5489 _err
= (*dvp
->v_op
[vnop_clonefile_desc
.vdesc_offset
])(&a
);
5491 if (_err
== 0 && *vpp
) {
5492 DTRACE_FSINFO(clonefile
, vnode_t
, *vpp
);
5494 kdebug_lookup(*vpp
, cnp
);
5497 post_event_if_success(dvp
, _err
, NOTE_WRITE
);
5503 VNOP_GETXATTR(vnode_t vp
, const char *name
, uio_t uio
, size_t *size
, int options
, vfs_context_t ctx
)
5505 struct vnop_getxattr_args a
;
5508 a
.a_desc
= &vnop_getxattr_desc
;
5513 a
.a_options
= options
;
5516 error
= (*vp
->v_op
[vnop_getxattr_desc
.vdesc_offset
])(&a
);
5517 DTRACE_FSINFO(getxattr
, vnode_t
, vp
);
5523 VNOP_SETXATTR(vnode_t vp
, const char *name
, uio_t uio
, int options
, vfs_context_t ctx
)
5525 struct vnop_setxattr_args a
;
5528 a
.a_desc
= &vnop_setxattr_desc
;
5532 a
.a_options
= options
;
5535 error
= (*vp
->v_op
[vnop_setxattr_desc
.vdesc_offset
])(&a
);
5536 DTRACE_FSINFO(setxattr
, vnode_t
, vp
);
5539 vnode_uncache_authorized_action(vp
, KAUTH_INVALIDATE_CACHED_RIGHTS
);
5541 post_event_if_success(vp
, error
, NOTE_ATTRIB
);
5547 VNOP_REMOVEXATTR(vnode_t vp
, const char *name
, int options
, vfs_context_t ctx
)
5549 struct vnop_removexattr_args a
;
5552 a
.a_desc
= &vnop_removexattr_desc
;
5555 a
.a_options
= options
;
5558 error
= (*vp
->v_op
[vnop_removexattr_desc
.vdesc_offset
])(&a
);
5559 DTRACE_FSINFO(removexattr
, vnode_t
, vp
);
5561 post_event_if_success(vp
, error
, NOTE_ATTRIB
);
5567 VNOP_LISTXATTR(vnode_t vp
, uio_t uio
, size_t *size
, int options
, vfs_context_t ctx
)
5569 struct vnop_listxattr_args a
;
5572 a
.a_desc
= &vnop_listxattr_desc
;
5576 a
.a_options
= options
;
5579 error
= (*vp
->v_op
[vnop_listxattr_desc
.vdesc_offset
])(&a
);
5580 DTRACE_FSINFO(listxattr
, vnode_t
, vp
);
5589 *#% blktooff vp = = =
5592 struct vnop_blktooff_args
{
5593 struct vnodeop_desc
*a_desc
;
5600 VNOP_BLKTOOFF(struct vnode
*vp
, daddr64_t lblkno
, off_t
*offset
)
5603 struct vnop_blktooff_args a
;
5605 a
.a_desc
= &vnop_blktooff_desc
;
5607 a
.a_lblkno
= lblkno
;
5608 a
.a_offset
= offset
;
5610 _err
= (*vp
->v_op
[vnop_blktooff_desc
.vdesc_offset
])(&a
);
5611 DTRACE_FSINFO(blktooff
, vnode_t
, vp
);
5619 *#% offtoblk vp = = =
5622 struct vnop_offtoblk_args
{
5623 struct vnodeop_desc
*a_desc
;
5626 daddr64_t
*a_lblkno
;
5630 VNOP_OFFTOBLK(struct vnode
*vp
, off_t offset
, daddr64_t
*lblkno
)
5633 struct vnop_offtoblk_args a
;
5635 a
.a_desc
= &vnop_offtoblk_desc
;
5637 a
.a_offset
= offset
;
5638 a
.a_lblkno
= lblkno
;
5640 _err
= (*vp
->v_op
[vnop_offtoblk_desc
.vdesc_offset
])(&a
);
5641 DTRACE_FSINFO(offtoblk
, vnode_t
, vp
);
5649 *#% blockmap vp L L L
5652 struct vnop_blockmap_args
{
5653 struct vnodeop_desc
*a_desc
;
5661 vfs_context_t a_context
;
5665 VNOP_BLOCKMAP(struct vnode
*vp
, off_t foffset
, size_t size
, daddr64_t
*bpn
, size_t *run
, void *poff
, int flags
, vfs_context_t ctx
)
5668 struct vnop_blockmap_args a
;
5669 size_t localrun
= 0;
5672 ctx
= vfs_context_current();
5674 a
.a_desc
= &vnop_blockmap_desc
;
5676 a
.a_foffset
= foffset
;
5679 a
.a_run
= &localrun
;
5684 _err
= (*vp
->v_op
[vnop_blockmap_desc
.vdesc_offset
])(&a
);
5685 DTRACE_FSINFO(blockmap
, vnode_t
, vp
);
5688 * We used a local variable to request information from the underlying
5689 * filesystem about the length of the I/O run in question. If
5690 * we get malformed output from the filesystem, we cap it to the length
5691 * requested, at most. Update 'run' on the way out.
5694 if (localrun
> size
) {
5707 struct vnop_strategy_args
{
5708 struct vnodeop_desc
*a_desc
;
5714 VNOP_STRATEGY(struct buf
*bp
)
5717 struct vnop_strategy_args a
;
5718 vnode_t vp
= buf_vnode(bp
);
5719 a
.a_desc
= &vnop_strategy_desc
;
5721 _err
= (*vp
->v_op
[vnop_strategy_desc
.vdesc_offset
])(&a
);
5722 DTRACE_FSINFO(strategy
, vnode_t
, vp
);
5727 struct vnop_bwrite_args
{
5728 struct vnodeop_desc
*a_desc
;
5733 VNOP_BWRITE(struct buf
*bp
)
5736 struct vnop_bwrite_args a
;
5737 vnode_t vp
= buf_vnode(bp
);
5738 a
.a_desc
= &vnop_bwrite_desc
;
5740 _err
= (*vp
->v_op
[vnop_bwrite_desc
.vdesc_offset
])(&a
);
5741 DTRACE_FSINFO(bwrite
, vnode_t
, vp
);
5746 struct vnop_kqfilt_add_args
{
5747 struct vnodeop_desc
*a_desc
;
5750 vfs_context_t a_context
;
5754 VNOP_KQFILT_ADD(struct vnode
*vp
, struct knote
*kn
, vfs_context_t ctx
)
5757 struct vnop_kqfilt_add_args a
;
5759 a
.a_desc
= VDESC(vnop_kqfilt_add
);
5764 _err
= (*vp
->v_op
[vnop_kqfilt_add_desc
.vdesc_offset
])(&a
);
5765 DTRACE_FSINFO(kqfilt_add
, vnode_t
, vp
);
5771 struct vnop_kqfilt_remove_args
{
5772 struct vnodeop_desc
*a_desc
;
5775 vfs_context_t a_context
;
5779 VNOP_KQFILT_REMOVE(struct vnode
*vp
, uintptr_t ident
, vfs_context_t ctx
)
5782 struct vnop_kqfilt_remove_args a
;
5784 a
.a_desc
= VDESC(vnop_kqfilt_remove
);
5789 _err
= (*vp
->v_op
[vnop_kqfilt_remove_desc
.vdesc_offset
])(&a
);
5790 DTRACE_FSINFO(kqfilt_remove
, vnode_t
, vp
);
5796 VNOP_MONITOR(vnode_t vp
, uint32_t events
, uint32_t flags
, void *handle
, vfs_context_t ctx
)
5799 struct vnop_monitor_args a
;
5801 a
.a_desc
= VDESC(vnop_monitor
);
5803 a
.a_events
= events
;
5805 a
.a_handle
= handle
;
5808 _err
= (*vp
->v_op
[vnop_monitor_desc
.vdesc_offset
])(&a
);
5809 DTRACE_FSINFO(monitor
, vnode_t
, vp
);
5815 struct vnop_setlabel_args
{
5816 struct vnodeop_desc
*a_desc
;
5819 vfs_context_t a_context
;
5823 VNOP_SETLABEL(struct vnode
*vp
, struct label
*label
, vfs_context_t ctx
)
5826 struct vnop_setlabel_args a
;
5828 a
.a_desc
= VDESC(vnop_setlabel
);
5833 _err
= (*vp
->v_op
[vnop_setlabel_desc
.vdesc_offset
])(&a
);
5834 DTRACE_FSINFO(setlabel
, vnode_t
, vp
);
5842 * Get a named streamed
5845 VNOP_GETNAMEDSTREAM(vnode_t vp
, vnode_t
*svpp
, const char *name
, enum nsoperation operation
, int flags
, vfs_context_t ctx
)
5848 struct vnop_getnamedstream_args a
;
5850 a
.a_desc
= &vnop_getnamedstream_desc
;
5854 a
.a_operation
= operation
;
5858 _err
= (*vp
->v_op
[vnop_getnamedstream_desc
.vdesc_offset
])(&a
);
5859 DTRACE_FSINFO(getnamedstream
, vnode_t
, vp
);
5864 * Create a named streamed
5867 VNOP_MAKENAMEDSTREAM(vnode_t vp
, vnode_t
*svpp
, const char *name
, int flags
, vfs_context_t ctx
)
5870 struct vnop_makenamedstream_args a
;
5872 a
.a_desc
= &vnop_makenamedstream_desc
;
5879 _err
= (*vp
->v_op
[vnop_makenamedstream_desc
.vdesc_offset
])(&a
);
5880 DTRACE_FSINFO(makenamedstream
, vnode_t
, vp
);
5886 * Remove a named streamed
5889 VNOP_REMOVENAMEDSTREAM(vnode_t vp
, vnode_t svp
, const char *name
, int flags
, vfs_context_t ctx
)
5892 struct vnop_removenamedstream_args a
;
5894 a
.a_desc
= &vnop_removenamedstream_desc
;
5901 _err
= (*vp
->v_op
[vnop_removenamedstream_desc
.vdesc_offset
])(&a
);
5902 DTRACE_FSINFO(removenamedstream
, vnode_t
, vp
);