2 * Copyright (c) 1995-2012 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@
29 * Copyright (c) 1989, 1993
30 * The Regents of the University of California. All rights reserved.
31 * (c) UNIX System Laboratories, Inc.
32 * All or some portions of this file are derived from material licensed
33 * to the University of California by American Telephone and Telegraph
34 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
35 * the permission of UNIX System Laboratories, Inc.
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by the University of
48 * California, Berkeley and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 * @(#)vfs_syscalls.c 8.41 (Berkeley) 6/15/95
68 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
69 * support for mandatory and extensible security protections. This notice
70 * is included in support of clause 2.2 (b) of the Apple Public License,
74 #include <sys/param.h>
75 #include <sys/systm.h>
76 #include <sys/namei.h>
77 #include <sys/filedesc.h>
78 #include <sys/kernel.h>
79 #include <sys/file_internal.h>
81 #include <sys/vnode_internal.h>
82 #include <sys/mount_internal.h>
83 #include <sys/proc_internal.h>
84 #include <sys/kauth.h>
85 #include <sys/uio_internal.h>
86 #include <sys/malloc.h>
88 #include <sys/dirent.h>
90 #include <sys/sysctl.h>
92 #include <sys/quota.h>
93 #include <sys/kdebug.h>
94 #include <sys/fsevents.h>
95 #include <sys/imgsrc.h>
96 #include <sys/sysproto.h>
97 #include <sys/xattr.h>
98 #include <sys/fcntl.h>
99 #include <sys/fsctl.h>
100 #include <sys/ubc_internal.h>
101 #include <sys/disk.h>
102 #include <machine/cons.h>
103 #include <machine/limits.h>
104 #include <miscfs/specfs/specdev.h>
106 #include <security/audit/audit.h>
107 #include <bsm/audit_kevents.h>
109 #include <mach/mach_types.h>
110 #include <kern/kern_types.h>
111 #include <kern/kalloc.h>
112 #include <kern/task.h>
114 #include <vm/vm_pageout.h>
116 #include <libkern/OSAtomic.h>
117 #include <pexpert/pexpert.h>
120 #include <security/mac.h>
121 #include <security/mac_framework.h>
125 #define GET_PATH(x) \
126 (x) = get_pathbuff();
127 #define RELEASE_PATH(x) \
130 #define GET_PATH(x) \
131 MALLOC_ZONE((x), char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
132 #define RELEASE_PATH(x) \
133 FREE_ZONE((x), MAXPATHLEN, M_NAMEI);
134 #endif /* CONFIG_FSE */
136 /* struct for checkdirs iteration */
141 /* callback for checkdirs iteration */
142 static int checkdirs_callback(proc_t p
, void * arg
);
144 static int change_dir(struct nameidata
*ndp
, vfs_context_t ctx
);
145 static int checkdirs(vnode_t olddp
, vfs_context_t ctx
);
146 void enablequotas(struct mount
*mp
, vfs_context_t ctx
);
147 static int getfsstat_callback(mount_t mp
, void * arg
);
148 static int getutimes(user_addr_t usrtvp
, struct timespec
*tsp
);
149 static int setutimes(vfs_context_t ctx
, vnode_t vp
, const struct timespec
*ts
, int nullflag
);
150 static int sync_callback(mount_t
, void *);
151 static int munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
152 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
153 boolean_t partial_copy
);
154 static int statfs64_common(struct mount
*mp
, struct vfsstatfs
*sfsp
,
156 static int fsync_common(proc_t p
, struct fsync_args
*uap
, int flags
);
157 static int mount_common(char *fstypename
, vnode_t pvp
, vnode_t vp
,
158 struct componentname
*cnp
, user_addr_t fsmountargs
,
159 int flags
, uint32_t internal_flags
, char *labelstr
, boolean_t kernelmount
,
161 void vfs_notify_mount(vnode_t pdvp
);
163 int prepare_coveredvp(vnode_t vp
, vfs_context_t ctx
, struct componentname
*cnp
, const char *fsname
, boolean_t skip_auth
);
165 #ifdef CONFIG_IMGSRC_ACCESS
166 static int authorize_devpath_and_update_mntfromname(mount_t mp
, user_addr_t devpath
, vnode_t
*devvpp
, vfs_context_t ctx
);
167 static int place_mount_and_checkdirs(mount_t mp
, vnode_t vp
, vfs_context_t ctx
);
168 static void undo_place_on_covered_vp(mount_t mp
, vnode_t vp
);
169 static int mount_begin_update(mount_t mp
, vfs_context_t ctx
, int flags
);
170 static void mount_end_update(mount_t mp
);
171 static int relocate_imageboot_source(vnode_t pvp
, vnode_t vp
, struct componentname
*cnp
, const char *fsname
, vfs_context_t ctx
, boolean_t is64bit
, user_addr_t fsmountargs
, boolean_t by_index
);
172 #endif /* CONFIG_IMGSRC_ACCESS */
174 int (*union_dircheckp
)(struct vnode
**, struct fileproc
*, vfs_context_t
);
177 int sync_internal(void);
180 int open1(vfs_context_t
, struct nameidata
*, int, struct vnode_attr
*, int32_t *);
183 int unlink1(vfs_context_t
, struct nameidata
*, int);
186 * incremented each time a mount or unmount operation occurs
187 * used to invalidate the cached value of the rootvp in the
188 * mount structure utilized by cache_lookup_path
190 uint32_t mount_generation
= 0;
192 /* counts number of mount and unmount operations */
193 unsigned int vfs_nummntops
=0;
195 extern struct fileops vnops
;
196 extern errno_t
rmdir_remove_orphaned_appleDouble(vnode_t
, vfs_context_t
, int *);
200 * Virtual File System System Calls
205 * Private in-kernel mounting spi (NFS only, not exported)
209 vfs_iskernelmount(mount_t mp
)
211 return ((mp
->mnt_kern_flag
& MNTK_KERNEL_MOUNT
) ? TRUE
: FALSE
);
216 kernel_mount(char *fstype
, vnode_t pvp
, vnode_t vp
, const char *path
,
217 void *data
, __unused
size_t datalen
, int syscall_flags
, __unused
uint32_t kern_flags
, vfs_context_t ctx
)
223 NDINIT(&nd
, LOOKUP
, OP_MOUNT
, FOLLOW
| AUDITVNPATH1
| WANTPARENT
,
224 UIO_SYSSPACE
, CAST_USER_ADDR_T(path
), ctx
);
227 * Get the vnode to be covered if it's not supplied
237 char *pnbuf
= CAST_DOWN(char *, path
);
239 nd
.ni_cnd
.cn_pnbuf
= pnbuf
;
240 nd
.ni_cnd
.cn_pnlen
= strlen(pnbuf
) + 1;
244 error
= mount_common(fstype
, pvp
, vp
, &nd
.ni_cnd
, CAST_USER_ADDR_T(data
),
245 syscall_flags
, kern_flags
, NULL
, TRUE
, ctx
);
255 #endif /* NFSCLIENT */
258 * Mount a file system.
262 mount(proc_t p
, struct mount_args
*uap
, __unused
int32_t *retval
)
264 struct __mac_mount_args muap
;
266 muap
.type
= uap
->type
;
267 muap
.path
= uap
->path
;
268 muap
.flags
= uap
->flags
;
269 muap
.data
= uap
->data
;
270 muap
.mac_p
= USER_ADDR_NULL
;
271 return (__mac_mount(p
, &muap
, retval
));
275 vfs_notify_mount(vnode_t pdvp
)
277 vfs_event_signal(NULL
, VQ_MOUNT
, (intptr_t)NULL
);
278 lock_vnode_and_post(pdvp
, NOTE_WRITE
);
283 * Mount a file system taking into account MAC label behavior.
284 * See mount(2) man page for more information
286 * Parameters: p Process requesting the mount
287 * uap User argument descriptor (see below)
290 * Indirect: uap->type Filesystem type
291 * uap->path Path to mount
292 * uap->data Mount arguments
293 * uap->mac_p MAC info
294 * uap->flags Mount flags
300 boolean_t root_fs_upgrade_try
= FALSE
;
303 __mac_mount(struct proc
*p
, register struct __mac_mount_args
*uap
, __unused
int32_t *retval
)
306 vfs_context_t ctx
= vfs_context_current();
307 char fstypename
[MFSNAMELEN
];
310 char *labelstr
= NULL
;
311 int flags
= uap
->flags
;
313 boolean_t is_64bit
= IS_64BIT_PROCESS(p
);
316 * Get the fs type name from user space
318 error
= copyinstr(uap
->type
, fstypename
, MFSNAMELEN
, &dummy
);
323 * Get the vnode to be covered
325 NDINIT(&nd
, LOOKUP
, OP_MOUNT
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
| WANTPARENT
,
326 UIO_USERSPACE
, uap
->path
, ctx
);
333 #ifdef CONFIG_IMGSRC_ACCESS
334 /* Mounting image source cannot be batched with other operations */
335 if (flags
== MNT_IMGSRC_BY_INDEX
) {
336 error
= relocate_imageboot_source(pvp
, vp
, &nd
.ni_cnd
, fstypename
,
337 ctx
, is_64bit
, uap
->data
, (flags
== MNT_IMGSRC_BY_INDEX
));
340 #endif /* CONFIG_IMGSRC_ACCESS */
344 * Get the label string (if any) from user space
346 if (uap
->mac_p
!= USER_ADDR_NULL
) {
351 struct user64_mac mac64
;
352 error
= copyin(uap
->mac_p
, &mac64
, sizeof(mac64
));
353 mac
.m_buflen
= mac64
.m_buflen
;
354 mac
.m_string
= mac64
.m_string
;
356 struct user32_mac mac32
;
357 error
= copyin(uap
->mac_p
, &mac32
, sizeof(mac32
));
358 mac
.m_buflen
= mac32
.m_buflen
;
359 mac
.m_string
= mac32
.m_string
;
363 if ((mac
.m_buflen
> MAC_MAX_LABEL_BUF_LEN
) ||
364 (mac
.m_buflen
< 2)) {
368 MALLOC(labelstr
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
369 error
= copyinstr(mac
.m_string
, labelstr
, mac
.m_buflen
, &ulen
);
373 AUDIT_ARG(mac_string
, labelstr
);
375 #endif /* CONFIG_MACF */
377 AUDIT_ARG(fflags
, flags
);
379 if ((vp
->v_flag
& VROOT
) &&
380 (vp
->v_mount
->mnt_flag
& MNT_ROOTFS
)) {
383 * See 7392553 for more details on why this check exists.
384 * Suffice to say: If this check is ON and something tries
385 * to mount the rootFS RW, we'll turn off the codesign
386 * bitmap optimization.
388 #if CHECK_CS_VALIDATION_BITMAP
389 if ( !(flags
& MNT_RDONLY
) ) {
390 root_fs_upgrade_try
= TRUE
;
395 error
= mount_common(fstypename
, pvp
, vp
, &nd
.ni_cnd
, uap
->data
, flags
, 0,
396 labelstr
, FALSE
, ctx
);
400 FREE(labelstr
, M_MACTEMP
);
401 #endif /* CONFIG_MACF */
411 * common mount implementation (final stage of mounting)
414 * fstypename file system type (ie it's vfs name)
415 * pvp parent of covered vnode
417 * cnp component name (ie path) of covered vnode
418 * flags generic mount flags
419 * fsmountargs file system specific data
420 * labelstr optional MAC label
421 * kernelmount TRUE for mounts initiated from inside the kernel
422 * ctx caller's context
425 mount_common(char *fstypename
, vnode_t pvp
, vnode_t vp
,
426 struct componentname
*cnp
, user_addr_t fsmountargs
, int flags
, uint32_t internal_flags
,
427 char *labelstr
, boolean_t kernelmount
, vfs_context_t ctx
)
429 struct vnode
*devvp
= NULLVP
;
430 struct vnode
*device_vnode
= NULLVP
;
435 struct vfstable
*vfsp
= (struct vfstable
*)0;
436 struct proc
*p
= vfs_context_proc(ctx
);
438 user_addr_t devpath
= USER_ADDR_NULL
;
441 boolean_t vfsp_ref
= FALSE
;
442 boolean_t is_rwlock_locked
= FALSE
;
443 boolean_t did_rele
= FALSE
;
444 boolean_t have_usecount
= FALSE
;
447 * Process an update for an existing mount
449 if (flags
& MNT_UPDATE
) {
450 if ((vp
->v_flag
& VROOT
) == 0) {
456 /* unmount in progress return error */
458 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
464 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
465 is_rwlock_locked
= TRUE
;
467 * We only allow the filesystem to be reloaded if it
468 * is currently mounted read-only.
470 if ((flags
& MNT_RELOAD
) &&
471 ((mp
->mnt_flag
& MNT_RDONLY
) == 0)) {
477 * If content protection is enabled, update mounts are not
478 * allowed to turn it off.
480 if ((mp
->mnt_flag
& MNT_CPROTECT
) &&
481 ((flags
& MNT_CPROTECT
) == 0)) {
486 #ifdef CONFIG_IMGSRC_ACCESS
487 /* Can't downgrade the backer of the root FS */
488 if ((mp
->mnt_kern_flag
& MNTK_BACKS_ROOT
) &&
489 (!vfs_isrdonly(mp
)) && (flags
& MNT_RDONLY
)) {
493 #endif /* CONFIG_IMGSRC_ACCESS */
496 * Only root, or the user that did the original mount is
497 * permitted to update it.
499 if (mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(vfs_context_ucred(ctx
)) &&
500 (error
= suser(vfs_context_ucred(ctx
), &p
->p_acflag
))) {
504 error
= mac_mount_check_remount(ctx
, mp
);
510 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV,
511 * and MNT_NOEXEC if mount point is already MNT_NOEXEC.
513 if ((!kernelmount
) && suser(vfs_context_ucred(ctx
), NULL
)) {
514 flags
|= MNT_NOSUID
| MNT_NODEV
;
515 if (mp
->mnt_flag
& MNT_NOEXEC
)
522 mp
->mnt_flag
|= flags
& (MNT_RELOAD
| MNT_FORCE
| MNT_UPDATE
);
524 vfsp
= mp
->mnt_vtable
;
528 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV, and
529 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
531 if ((!kernelmount
) && suser(vfs_context_ucred(ctx
), NULL
)) {
532 flags
|= MNT_NOSUID
| MNT_NODEV
;
533 if (vp
->v_mount
->mnt_flag
& MNT_NOEXEC
)
537 /* XXXAUDIT: Should we capture the type on the error path as well? */
538 AUDIT_ARG(text
, fstypename
);
540 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
541 if (!strncmp(vfsp
->vfc_name
, fstypename
, MFSNAMELEN
)) {
542 vfsp
->vfc_refcount
++;
553 * VFC_VFSLOCALARGS is not currently supported for kernel mounts
555 if (kernelmount
&& (vfsp
->vfc_vfsflags
& VFC_VFSLOCALARGS
)) {
556 error
= EINVAL
; /* unsupported request */
560 error
= prepare_coveredvp(vp
, ctx
, cnp
, fstypename
, ((internal_flags
& KERNEL_MOUNT_NOAUTH
) != 0));
566 * Allocate and initialize the filesystem (mount_t)
568 MALLOC_ZONE(mp
, struct mount
*, (u_int32_t
)sizeof(struct mount
),
570 bzero((char *)mp
, (u_int32_t
)sizeof(struct mount
));
573 /* Initialize the default IO constraints */
574 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
575 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
576 mp
->mnt_maxsegreadsize
= mp
->mnt_maxreadcnt
;
577 mp
->mnt_maxsegwritesize
= mp
->mnt_maxwritecnt
;
578 mp
->mnt_devblocksize
= DEV_BSIZE
;
579 mp
->mnt_alignmentmask
= PAGE_MASK
;
580 mp
->mnt_ioqueue_depth
= MNT_DEFAULT_IOQUEUE_DEPTH
;
583 mp
->mnt_realrootvp
= NULLVP
;
584 mp
->mnt_authcache_ttl
= CACHED_LOOKUP_RIGHT_TTL
;
586 TAILQ_INIT(&mp
->mnt_vnodelist
);
587 TAILQ_INIT(&mp
->mnt_workerqueue
);
588 TAILQ_INIT(&mp
->mnt_newvnodes
);
590 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
591 is_rwlock_locked
= TRUE
;
592 mp
->mnt_op
= vfsp
->vfc_vfsops
;
593 mp
->mnt_vtable
= vfsp
;
594 //mp->mnt_stat.f_type = vfsp->vfc_typenum;
595 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
596 strncpy(mp
->mnt_vfsstat
.f_fstypename
, vfsp
->vfc_name
, MFSTYPENAMELEN
);
597 strncpy(mp
->mnt_vfsstat
.f_mntonname
, cnp
->cn_pnbuf
, MAXPATHLEN
);
598 mp
->mnt_vnodecovered
= vp
;
599 mp
->mnt_vfsstat
.f_owner
= kauth_cred_getuid(vfs_context_ucred(ctx
));
600 mp
->mnt_throttle_mask
= LOWPRI_MAX_NUM_DEV
- 1;
601 mp
->mnt_devbsdunit
= 0;
603 /* XXX 3762912 hack to support HFS filesystem 'owner' - filesystem may update later */
604 vfs_setowner(mp
, KAUTH_UID_NONE
, KAUTH_GID_NONE
);
608 mp
->mnt_kern_flag
|= MNTK_KERNEL_MOUNT
;
609 if ((internal_flags
& KERNEL_MOUNT_PERMIT_UNMOUNT
) != 0)
610 mp
->mnt_kern_flag
|= MNTK_PERMIT_UNMOUNT
;
611 #endif /* NFSCLIENT */
615 * Set the mount level flags.
617 if (flags
& MNT_RDONLY
)
618 mp
->mnt_flag
|= MNT_RDONLY
;
619 else if (mp
->mnt_flag
& MNT_RDONLY
) {
620 // disallow read/write upgrades of file systems that
621 // had the TYPENAME_OVERRIDE feature set.
622 if (mp
->mnt_kern_flag
& MNTK_TYPENAME_OVERRIDE
) {
626 mp
->mnt_kern_flag
|= MNTK_WANTRDWR
;
628 mp
->mnt_flag
&= ~(MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
629 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
630 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
|
631 MNT_AUTOMOUNTED
| MNT_DEFWRITE
| MNT_NOATIME
|
632 MNT_QUARANTINE
| MNT_CPROTECT
);
633 mp
->mnt_flag
|= flags
& (MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
634 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
635 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
|
636 MNT_AUTOMOUNTED
| MNT_DEFWRITE
| MNT_NOATIME
|
637 MNT_QUARANTINE
| MNT_CPROTECT
);
640 if (flags
& MNT_MULTILABEL
) {
641 if (vfsp
->vfc_vfsflags
& VFC_VFSNOMACLABEL
) {
645 mp
->mnt_flag
|= MNT_MULTILABEL
;
649 * Process device path for local file systems if requested
651 if (vfsp
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
652 if (vfs_context_is64bit(ctx
)) {
653 if ( (error
= copyin(fsmountargs
, (caddr_t
)&devpath
, sizeof(devpath
))) )
655 fsmountargs
+= sizeof(devpath
);
658 if ( (error
= copyin(fsmountargs
, (caddr_t
)&tmp
, sizeof(tmp
))) )
660 /* munge into LP64 addr */
661 devpath
= CAST_USER_ADDR_T(tmp
);
662 fsmountargs
+= sizeof(tmp
);
665 /* Lookup device and authorize access to it */
669 NDINIT(&nd
, LOOKUP
, OP_MOUNT
, FOLLOW
, UIO_USERSPACE
, devpath
, ctx
);
670 if ( (error
= namei(&nd
)) )
673 strncpy(mp
->mnt_vfsstat
.f_mntfromname
, nd
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
678 if (devvp
->v_type
!= VBLK
) {
682 if (major(devvp
->v_rdev
) >= nblkdev
) {
687 * If mount by non-root, then verify that user has necessary
688 * permissions on the device.
690 if (suser(vfs_context_ucred(ctx
), NULL
) != 0) {
691 mode_t accessmode
= KAUTH_VNODE_READ_DATA
;
693 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
694 accessmode
|= KAUTH_VNODE_WRITE_DATA
;
695 if ((error
= vnode_authorize(devvp
, NULL
, accessmode
, ctx
)) != 0)
699 /* On first mount, preflight and open device */
700 if (devpath
&& ((flags
& MNT_UPDATE
) == 0)) {
701 if ( (error
= vnode_ref(devvp
)) )
704 * Disallow multiple mounts of the same device.
705 * Disallow mounting of a device that is currently in use
706 * (except for root, which might share swap device for miniroot).
707 * Flush out any old buffers remaining from a previous use.
709 if ( (error
= vfs_mountedon(devvp
)) )
712 if (vcount(devvp
) > 1 && !(vfs_flags(mp
) & MNT_ROOTFS
)) {
716 if ( (error
= VNOP_FSYNC(devvp
, MNT_WAIT
, ctx
)) ) {
720 if ( (error
= buf_invalidateblks(devvp
, BUF_WRITE_DATA
, 0, 0)) )
723 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
725 error
= mac_vnode_check_open(ctx
,
727 ronly
? FREAD
: FREAD
|FWRITE
);
731 if ( (error
= VNOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, ctx
)) )
734 mp
->mnt_devvp
= devvp
;
735 device_vnode
= devvp
;
737 } else if ((mp
->mnt_flag
& MNT_RDONLY
) &&
738 (mp
->mnt_kern_flag
& MNTK_WANTRDWR
) &&
739 (device_vnode
= mp
->mnt_devvp
)) {
743 * If upgrade to read-write by non-root, then verify
744 * that user has necessary permissions on the device.
746 vnode_getalways(device_vnode
);
748 if (suser(vfs_context_ucred(ctx
), NULL
) &&
749 (error
= vnode_authorize(device_vnode
, NULL
,
750 KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
,
752 vnode_put(device_vnode
);
756 /* Tell the device that we're upgrading */
757 dev
= (dev_t
)device_vnode
->v_rdev
;
760 if ((u_int
)maj
>= (u_int
)nblkdev
)
761 panic("Volume mounted on a device with invalid major number.");
763 error
= bdevsw
[maj
].d_open(dev
, FREAD
| FWRITE
, S_IFBLK
, p
);
764 vnode_put(device_vnode
);
765 device_vnode
= NULLVP
;
772 if ((flags
& MNT_UPDATE
) == 0) {
773 mac_mount_label_init(mp
);
774 mac_mount_label_associate(ctx
, mp
);
777 if ((flags
& MNT_UPDATE
) != 0) {
778 error
= mac_mount_check_label_update(ctx
, mp
);
785 * Mount the filesystem.
787 error
= VFS_MOUNT(mp
, device_vnode
, fsmountargs
, ctx
);
789 if (flags
& MNT_UPDATE
) {
790 if (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)
791 mp
->mnt_flag
&= ~MNT_RDONLY
;
793 (MNT_UPDATE
| MNT_RELOAD
| MNT_FORCE
);
794 mp
->mnt_kern_flag
&=~ MNTK_WANTRDWR
;
796 mp
->mnt_flag
= flag
; /* restore flag value */
797 vfs_event_signal(NULL
, VQ_UPDATE
, (intptr_t)NULL
);
798 lck_rw_done(&mp
->mnt_rwlock
);
799 is_rwlock_locked
= FALSE
;
801 enablequotas(mp
, ctx
);
806 * Put the new filesystem on the mount list after root.
809 struct vfs_attr vfsattr
;
811 if (vfs_flags(mp
) & MNT_MULTILABEL
) {
812 error
= VFS_ROOT(mp
, &rvp
, ctx
);
814 printf("%s() VFS_ROOT returned %d\n", __func__
, error
);
817 error
= vnode_label(mp
, NULL
, rvp
, NULL
, 0, ctx
);
819 * drop reference provided by VFS_ROOT
829 CLR(vp
->v_flag
, VMOUNT
);
830 vp
->v_mountedhere
= mp
;
834 * taking the name_cache_lock exclusively will
835 * insure that everyone is out of the fast path who
836 * might be trying to use a now stale copy of
837 * vp->v_mountedhere->mnt_realrootvp
838 * bumping mount_generation causes the cached values
845 error
= vnode_ref(vp
);
850 have_usecount
= TRUE
;
852 error
= checkdirs(vp
, ctx
);
854 /* Unmount the filesystem as cdir/rdirs cannot be updated */
858 * there is no cleanup code here so I have made it void
859 * we need to revisit this
861 (void)VFS_START(mp
, 0, ctx
);
863 if (mount_list_add(mp
) != 0) {
865 * The system is shutting down trying to umount
866 * everything, so fail with a plausible errno.
871 lck_rw_done(&mp
->mnt_rwlock
);
872 is_rwlock_locked
= FALSE
;
874 /* Check if this mounted file system supports EAs or named streams. */
875 /* Skip WebDAV file systems for now since they hang in VFS_GETATTR here. */
876 VFSATTR_INIT(&vfsattr
);
877 VFSATTR_WANTED(&vfsattr
, f_capabilities
);
878 if (strncmp(mp
->mnt_vfsstat
.f_fstypename
, "webdav", sizeof("webdav")) != 0 &&
879 vfs_getattr(mp
, &vfsattr
, ctx
) == 0 &&
880 VFSATTR_IS_SUPPORTED(&vfsattr
, f_capabilities
)) {
881 if ((vfsattr
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] & VOL_CAP_INT_EXTENDED_ATTR
) &&
882 (vfsattr
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] & VOL_CAP_INT_EXTENDED_ATTR
)) {
883 mp
->mnt_kern_flag
|= MNTK_EXTENDED_ATTRS
;
886 if ((vfsattr
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] & VOL_CAP_INT_NAMEDSTREAMS
) &&
887 (vfsattr
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] & VOL_CAP_INT_NAMEDSTREAMS
)) {
888 mp
->mnt_kern_flag
|= MNTK_NAMED_STREAMS
;
891 /* Check if this file system supports path from id lookups. */
892 if ((vfsattr
.f_capabilities
.capabilities
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_PATH_FROM_ID
) &&
893 (vfsattr
.f_capabilities
.valid
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_PATH_FROM_ID
)) {
894 mp
->mnt_kern_flag
|= MNTK_PATH_FROM_ID
;
895 } else if (mp
->mnt_flag
& MNT_DOVOLFS
) {
896 /* Legacy MNT_DOVOLFS flag also implies path from id lookups. */
897 mp
->mnt_kern_flag
|= MNTK_PATH_FROM_ID
;
900 if (mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSNATIVEXATTR
) {
901 mp
->mnt_kern_flag
|= MNTK_EXTENDED_ATTRS
;
903 if (mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSPREFLIGHT
) {
904 mp
->mnt_kern_flag
|= MNTK_UNMOUNT_PREFLIGHT
;
906 /* increment the operations count */
907 OSAddAtomic(1, &vfs_nummntops
);
908 enablequotas(mp
, ctx
);
911 device_vnode
->v_specflags
|= SI_MOUNTEDON
;
914 * cache the IO attributes for the underlying physical media...
915 * an error return indicates the underlying driver doesn't
916 * support all the queries necessary... however, reasonable
917 * defaults will have been set, so no reason to bail or care
919 vfs_init_io_attributes(device_vnode
, mp
);
922 /* Now that mount is setup, notify the listeners */
923 vfs_notify_mount(pvp
);
925 /* If we fail a fresh mount, there should be no vnodes left hooked into the mountpoint. */
926 if (mp
->mnt_vnodelist
.tqh_first
!= NULL
) {
927 panic("mount_common(): mount of %s filesystem failed with %d, but vnode list is not empty.",
928 mp
->mnt_vtable
->vfc_name
, error
);
932 CLR(vp
->v_flag
, VMOUNT
);
935 mp
->mnt_vtable
->vfc_refcount
--;
939 vnode_rele(device_vnode
);
940 VNOP_CLOSE(device_vnode
, ronly
? FREAD
: FREAD
|FWRITE
, ctx
);
942 lck_rw_done(&mp
->mnt_rwlock
);
943 is_rwlock_locked
= FALSE
;
946 * if we get here, we have a mount structure that needs to be freed,
947 * but since the coveredvp hasn't yet been updated to point at it,
948 * no need to worry about other threads holding a crossref on this mp
949 * so it's ok to just free it
951 mount_lock_destroy(mp
);
953 mac_mount_label_destroy(mp
);
955 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
959 * drop I/O count on the device vp if there was one
961 if (devpath
&& devvp
)
966 /* Error condition exits */
968 (void)VFS_UNMOUNT(mp
, MNT_FORCE
, ctx
);
971 * If the mount has been placed on the covered vp,
972 * it may have been discovered by now, so we have
973 * to treat this just like an unmount
976 mp
->mnt_lflag
|= MNT_LDEAD
;
979 if (device_vnode
!= NULLVP
) {
980 vnode_rele(device_vnode
);
981 VNOP_CLOSE(device_vnode
, mp
->mnt_flag
& MNT_RDONLY
? FREAD
: FREAD
|FWRITE
,
989 vp
->v_mountedhere
= (mount_t
) 0;
997 if (devpath
&& ((flags
& MNT_UPDATE
) == 0) && (!did_rele
))
1000 if (devpath
&& devvp
)
1003 /* Release mnt_rwlock only when it was taken */
1004 if (is_rwlock_locked
== TRUE
) {
1005 lck_rw_done(&mp
->mnt_rwlock
);
1009 if (mp
->mnt_crossref
)
1010 mount_dropcrossref(mp
, vp
, 0);
1012 mount_lock_destroy(mp
);
1014 mac_mount_label_destroy(mp
);
1016 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
1021 vfsp
->vfc_refcount
--;
1022 mount_list_unlock();
1029 * Flush in-core data, check for competing mount attempts,
1033 prepare_coveredvp(vnode_t vp
, vfs_context_t ctx
, struct componentname
*cnp
, const char *fsname
, boolean_t skip_auth
)
1035 struct vnode_attr va
;
1040 * If the user is not root, ensure that they own the directory
1041 * onto which we are attempting to mount.
1044 VATTR_WANTED(&va
, va_uid
);
1045 if ((error
= vnode_getattr(vp
, &va
, ctx
)) ||
1046 (va
.va_uid
!= kauth_cred_getuid(vfs_context_ucred(ctx
)) &&
1047 (!vfs_context_issuser(ctx
)))) {
1053 if ( (error
= VNOP_FSYNC(vp
, MNT_WAIT
, ctx
)) )
1056 if ( (error
= buf_invalidateblks(vp
, BUF_WRITE_DATA
, 0, 0)) )
1059 if (vp
->v_type
!= VDIR
) {
1064 if (ISSET(vp
->v_flag
, VMOUNT
) && (vp
->v_mountedhere
!= NULL
)) {
1070 error
= mac_mount_check_mount(ctx
, vp
,
1076 vnode_lock_spin(vp
);
1077 SET(vp
->v_flag
, VMOUNT
);
1084 #if CONFIG_IMGSRC_ACCESS
1087 #define IMGSRC_DEBUG(args...) printf(args)
1089 #define IMGSRC_DEBUG(args...) do { } while(0)
1093 authorize_devpath_and_update_mntfromname(mount_t mp
, user_addr_t devpath
, vnode_t
*devvpp
, vfs_context_t ctx
)
1095 struct nameidata nd
;
1096 vnode_t vp
, realdevvp
;
1100 NDINIT(&nd
, LOOKUP
, OP_LOOKUP
, FOLLOW
, UIO_USERSPACE
, devpath
, ctx
);
1101 if ( (error
= namei(&nd
)) ) {
1102 IMGSRC_DEBUG("namei() failed with %d\n", error
);
1108 if (!vnode_isblk(vp
)) {
1109 IMGSRC_DEBUG("Not block device.\n");
1114 realdevvp
= mp
->mnt_devvp
;
1115 if (realdevvp
== NULLVP
) {
1116 IMGSRC_DEBUG("No device backs the mount.\n");
1121 error
= vnode_getwithref(realdevvp
);
1123 IMGSRC_DEBUG("Coudn't get iocount on device.\n");
1127 if (vnode_specrdev(vp
) != vnode_specrdev(realdevvp
)) {
1128 IMGSRC_DEBUG("Wrong dev_t.\n");
1133 strlcpy(mp
->mnt_vfsstat
.f_mntfromname
, nd
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
1136 * If mount by non-root, then verify that user has necessary
1137 * permissions on the device.
1139 if (!vfs_context_issuser(ctx
)) {
1140 accessmode
= KAUTH_VNODE_READ_DATA
;
1141 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
1142 accessmode
|= KAUTH_VNODE_WRITE_DATA
;
1143 if ((error
= vnode_authorize(vp
, NULL
, accessmode
, ctx
)) != 0) {
1144 IMGSRC_DEBUG("Access denied.\n");
1152 vnode_put(realdevvp
);
1163 * Clear VMOUNT, set v_mountedhere, and mnt_vnodecovered, ref the vnode,
1164 * and call checkdirs()
1167 place_mount_and_checkdirs(mount_t mp
, vnode_t vp
, vfs_context_t ctx
)
1171 mp
->mnt_vnodecovered
= vp
; /* XXX This is normally only set at init-time ... */
1173 vnode_lock_spin(vp
);
1174 CLR(vp
->v_flag
, VMOUNT
);
1175 vp
->v_mountedhere
= mp
;
1179 * taking the name_cache_lock exclusively will
1180 * insure that everyone is out of the fast path who
1181 * might be trying to use a now stale copy of
1182 * vp->v_mountedhere->mnt_realrootvp
1183 * bumping mount_generation causes the cached values
1188 name_cache_unlock();
1190 error
= vnode_ref(vp
);
1195 error
= checkdirs(vp
, ctx
);
1197 /* Unmount the filesystem as cdir/rdirs cannot be updated */
1204 mp
->mnt_vnodecovered
= NULLVP
;
1210 undo_place_on_covered_vp(mount_t mp
, vnode_t vp
)
1213 vnode_lock_spin(vp
);
1214 vp
->v_mountedhere
= (mount_t
)NULL
;
1217 mp
->mnt_vnodecovered
= NULLVP
;
1221 mount_begin_update(mount_t mp
, vfs_context_t ctx
, int flags
)
1225 /* unmount in progress return error */
1226 mount_lock_spin(mp
);
1227 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
1232 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
1235 * We only allow the filesystem to be reloaded if it
1236 * is currently mounted read-only.
1238 if ((flags
& MNT_RELOAD
) &&
1239 ((mp
->mnt_flag
& MNT_RDONLY
) == 0)) {
1245 * Only root, or the user that did the original mount is
1246 * permitted to update it.
1248 if (mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(vfs_context_ucred(ctx
)) &&
1249 (!vfs_context_issuser(ctx
))) {
1254 error
= mac_mount_check_remount(ctx
, mp
);
1262 lck_rw_done(&mp
->mnt_rwlock
);
1269 mount_end_update(mount_t mp
)
1271 lck_rw_done(&mp
->mnt_rwlock
);
1275 get_imgsrc_rootvnode(uint32_t height
, vnode_t
*rvpp
)
1279 if (height
>= MAX_IMAGEBOOT_NESTING
) {
1283 vp
= imgsrc_rootvnodes
[height
];
1284 if ((vp
!= NULLVP
) && (vnode_get(vp
) == 0)) {
1293 relocate_imageboot_source(vnode_t pvp
, vnode_t vp
, struct componentname
*cnp
,
1294 const char *fsname
, vfs_context_t ctx
,
1295 boolean_t is64bit
, user_addr_t fsmountargs
, boolean_t by_index
)
1299 boolean_t placed
= FALSE
;
1300 vnode_t devvp
= NULLVP
;
1301 struct vfstable
*vfsp
;
1302 user_addr_t devpath
;
1303 char *old_mntonname
;
1308 /* If we didn't imageboot, nothing to move */
1309 if (imgsrc_rootvnodes
[0] == NULLVP
) {
1313 /* Only root can do this */
1314 if (!vfs_context_issuser(ctx
)) {
1318 IMGSRC_DEBUG("looking for root vnode.\n");
1321 * Get root vnode of filesystem we're moving.
1325 struct user64_mnt_imgsrc_args mia64
;
1326 error
= copyin(fsmountargs
, &mia64
, sizeof(mia64
));
1328 IMGSRC_DEBUG("Failed to copy in arguments.\n");
1332 height
= mia64
.mi_height
;
1333 flags
= mia64
.mi_flags
;
1334 devpath
= mia64
.mi_devpath
;
1336 struct user32_mnt_imgsrc_args mia32
;
1337 error
= copyin(fsmountargs
, &mia32
, sizeof(mia32
));
1339 IMGSRC_DEBUG("Failed to copy in arguments.\n");
1343 height
= mia32
.mi_height
;
1344 flags
= mia32
.mi_flags
;
1345 devpath
= mia32
.mi_devpath
;
1349 * For binary compatibility--assumes one level of nesting.
1352 if ( (error
= copyin(fsmountargs
, (caddr_t
)&devpath
, sizeof(devpath
))) )
1356 if ( (error
= copyin(fsmountargs
, (caddr_t
)&tmp
, sizeof(tmp
))) )
1359 /* munge into LP64 addr */
1360 devpath
= CAST_USER_ADDR_T(tmp
);
1368 IMGSRC_DEBUG("%s: Got nonzero flags.\n", __FUNCTION__
);
1372 error
= get_imgsrc_rootvnode(height
, &rvp
);
1374 IMGSRC_DEBUG("getting root vnode failed with %d\n", error
);
1378 IMGSRC_DEBUG("got root vnode.\n");
1380 MALLOC(old_mntonname
, char*, MAXPATHLEN
, M_TEMP
, M_WAITOK
);
1382 /* Can only move once */
1383 mp
= vnode_mount(rvp
);
1384 if ((mp
->mnt_kern_flag
& MNTK_HAS_MOVED
) == MNTK_HAS_MOVED
) {
1385 IMGSRC_DEBUG("Already moved.\n");
1390 IMGSRC_DEBUG("Starting updated.\n");
1392 /* Get exclusive rwlock on mount, authorize update on mp */
1393 error
= mount_begin_update(mp
, ctx
, 0);
1395 IMGSRC_DEBUG("Starting updated failed with %d\n", error
);
1400 * It can only be moved once. Flag is set under the rwlock,
1401 * so we're now safe to proceed.
1403 if ((mp
->mnt_kern_flag
& MNTK_HAS_MOVED
) == MNTK_HAS_MOVED
) {
1404 IMGSRC_DEBUG("Already moved [2]\n");
1409 IMGSRC_DEBUG("Preparing coveredvp.\n");
1411 /* Mark covered vnode as mount in progress, authorize placing mount on top */
1412 error
= prepare_coveredvp(vp
, ctx
, cnp
, fsname
, FALSE
);
1414 IMGSRC_DEBUG("Preparing coveredvp failed with %d.\n", error
);
1418 IMGSRC_DEBUG("Covered vp OK.\n");
1420 /* Sanity check the name caller has provided */
1421 vfsp
= mp
->mnt_vtable
;
1422 if (strncmp(vfsp
->vfc_name
, fsname
, MFSNAMELEN
) != 0) {
1423 IMGSRC_DEBUG("Wrong fs name.\n");
1428 /* Check the device vnode and update mount-from name, for local filesystems */
1429 if (vfsp
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
1430 IMGSRC_DEBUG("Local, doing device validation.\n");
1432 if (devpath
!= USER_ADDR_NULL
) {
1433 error
= authorize_devpath_and_update_mntfromname(mp
, devpath
, &devvp
, ctx
);
1435 IMGSRC_DEBUG("authorize_devpath_and_update_mntfromname() failed.\n");
1444 * Place mp on top of vnode, ref the vnode, call checkdirs(),
1445 * and increment the name cache's mount generation
1448 IMGSRC_DEBUG("About to call place_mount_and_checkdirs().\n");
1449 error
= place_mount_and_checkdirs(mp
, vp
, ctx
);
1456 strncpy(old_mntonname
, mp
->mnt_vfsstat
.f_mntonname
, MAXPATHLEN
);
1457 strncpy(mp
->mnt_vfsstat
.f_mntonname
, cnp
->cn_pnbuf
, MAXPATHLEN
);
1459 /* Forbid future moves */
1461 mp
->mnt_kern_flag
|= MNTK_HAS_MOVED
;
1464 /* Finally, add to mount list, completely ready to go */
1465 if (mount_list_add(mp
) != 0) {
1467 * The system is shutting down trying to umount
1468 * everything, so fail with a plausible errno.
1474 mount_end_update(mp
);
1476 FREE(old_mntonname
, M_TEMP
);
1478 vfs_notify_mount(pvp
);
1482 strncpy(mp
->mnt_vfsstat
.f_mntonname
, old_mntonname
, MAXPATHLEN
);
1485 mp
->mnt_kern_flag
&= ~(MNTK_HAS_MOVED
);
1490 * Placing the mp on the vnode clears VMOUNT,
1491 * so cleanup is different after that point
1494 /* Rele the vp, clear VMOUNT and v_mountedhere */
1495 undo_place_on_covered_vp(mp
, vp
);
1497 vnode_lock_spin(vp
);
1498 CLR(vp
->v_flag
, VMOUNT
);
1502 mount_end_update(mp
);
1506 FREE(old_mntonname
, M_TEMP
);
1510 #endif /* CONFIG_IMGSRC_ACCESS */
1513 enablequotas(struct mount
*mp
, vfs_context_t ctx
)
1515 struct nameidata qnd
;
1517 char qfpath
[MAXPATHLEN
];
1518 const char *qfname
= QUOTAFILENAME
;
1519 const char *qfopsname
= QUOTAOPSNAME
;
1520 const char *qfextension
[] = INITQFNAMES
;
1522 /* XXX Shoulkd be an MNTK_ flag, instead of strncmp()'s */
1523 if (strncmp(mp
->mnt_vfsstat
.f_fstypename
, "hfs", sizeof("hfs")) != 0 ) {
1527 * Enable filesystem disk quotas if necessary.
1528 * We ignore errors as this should not interfere with final mount
1530 for (type
=0; type
< MAXQUOTAS
; type
++) {
1531 snprintf(qfpath
, sizeof(qfpath
), "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfopsname
, qfextension
[type
]);
1532 NDINIT(&qnd
, LOOKUP
, OP_MOUNT
, FOLLOW
, UIO_SYSSPACE
,
1533 CAST_USER_ADDR_T(qfpath
), ctx
);
1534 if (namei(&qnd
) != 0)
1535 continue; /* option file to trigger quotas is not present */
1536 vnode_put(qnd
.ni_vp
);
1538 snprintf(qfpath
, sizeof(qfpath
), "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfname
, qfextension
[type
]);
1540 (void) VFS_QUOTACTL(mp
, QCMD(Q_QUOTAON
, type
), 0, qfpath
, ctx
);
1547 checkdirs_callback(proc_t p
, void * arg
)
1549 struct cdirargs
* cdrp
= (struct cdirargs
* )arg
;
1550 vnode_t olddp
= cdrp
->olddp
;
1551 vnode_t newdp
= cdrp
->newdp
;
1552 struct filedesc
*fdp
;
1556 int cdir_changed
= 0;
1557 int rdir_changed
= 0;
1560 * XXX Also needs to iterate each thread in the process to see if it
1561 * XXX is using a per-thread current working directory, and, if so,
1562 * XXX update that as well.
1567 if (fdp
== (struct filedesc
*)0) {
1569 return(PROC_RETURNED
);
1571 fdp_cvp
= fdp
->fd_cdir
;
1572 fdp_rvp
= fdp
->fd_rdir
;
1575 if (fdp_cvp
== olddp
) {
1582 if (fdp_rvp
== olddp
) {
1589 if (cdir_changed
|| rdir_changed
) {
1591 fdp
->fd_cdir
= fdp_cvp
;
1592 fdp
->fd_rdir
= fdp_rvp
;
1595 return(PROC_RETURNED
);
1601 * Scan all active processes to see if any of them have a current
1602 * or root directory onto which the new filesystem has just been
1603 * mounted. If so, replace them with the new mount point.
1606 checkdirs(vnode_t olddp
, vfs_context_t ctx
)
1611 struct cdirargs cdr
;
1612 struct uthread
* uth
= get_bsdthread_info(current_thread());
1614 if (olddp
->v_usecount
== 1)
1616 if (uth
!= (struct uthread
*)0)
1617 uth
->uu_notrigger
= 1;
1618 err
= VFS_ROOT(olddp
->v_mountedhere
, &newdp
, ctx
);
1619 if (uth
!= (struct uthread
*)0)
1620 uth
->uu_notrigger
= 0;
1624 panic("mount: lost mount: error %d", err
);
1631 /* do not block for exec/fork trans as the vp in cwd & rootdir are not changing */
1632 proc_iterate(PROC_ALLPROCLIST
| PROC_NOWAITTRANS
, checkdirs_callback
, (void *)&cdr
, NULL
, NULL
);
1634 if (rootvnode
== olddp
) {
1646 * Unmount a file system.
1648 * Note: unmount takes a path to the vnode mounted on as argument,
1649 * not special file (as before).
1653 unmount(__unused proc_t p
, struct unmount_args
*uap
, __unused
int32_t *retval
)
1658 struct nameidata nd
;
1659 vfs_context_t ctx
= vfs_context_current();
1661 NDINIT(&nd
, LOOKUP
, OP_UNMOUNT
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
1662 UIO_USERSPACE
, uap
->path
, ctx
);
1671 error
= mac_mount_check_umount(ctx
, mp
);
1678 * Must be the root of the filesystem
1680 if ((vp
->v_flag
& VROOT
) == 0) {
1686 /* safedounmount consumes the mount ref */
1687 return (safedounmount(mp
, uap
->flags
, ctx
));
1691 vfs_unmountbyfsid(fsid_t
* fsid
, int flags
, vfs_context_t ctx
)
1695 mp
= mount_list_lookupby_fsid(fsid
, 0, 1);
1696 if (mp
== (mount_t
)0) {
1701 /* safedounmount consumes the mount ref */
1702 return(safedounmount(mp
, flags
, ctx
));
1707 * The mount struct comes with a mount ref which will be consumed.
1708 * Do the actual file system unmount, prevent some common foot shooting.
1711 safedounmount(struct mount
*mp
, int flags
, vfs_context_t ctx
)
1714 proc_t p
= vfs_context_proc(ctx
);
1717 * If the file system is not responding and MNT_NOBLOCK
1718 * is set and not a forced unmount then return EBUSY.
1720 if ((mp
->mnt_kern_flag
& MNT_LNOTRESP
) &&
1721 (flags
& MNT_NOBLOCK
) && ((flags
& MNT_FORCE
) == 0)) {
1727 * Skip authorization if the mount is tagged as permissive and
1728 * this is not a forced-unmount attempt.
1730 if (!(((mp
->mnt_kern_flag
& MNTK_PERMIT_UNMOUNT
) != 0) && ((flags
& MNT_FORCE
) == 0))) {
1732 * Only root, or the user that did the original mount is
1733 * permitted to unmount this filesystem.
1735 if ((mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(kauth_cred_get())) &&
1736 (error
= suser(kauth_cred_get(), &p
->p_acflag
)))
1740 * Don't allow unmounting the root file system.
1742 if (mp
->mnt_flag
& MNT_ROOTFS
) {
1743 error
= EBUSY
; /* the root is always busy */
1747 #ifdef CONFIG_IMGSRC_ACCESS
1748 if (mp
->mnt_kern_flag
& MNTK_BACKS_ROOT
) {
1752 #endif /* CONFIG_IMGSRC_ACCESS */
1754 return (dounmount(mp
, flags
, 1, ctx
));
1762 * Do the actual file system unmount.
1765 dounmount(struct mount
*mp
, int flags
, int withref
, vfs_context_t ctx
)
1767 vnode_t coveredvp
= (vnode_t
)0;
1770 int forcedunmount
= 0;
1772 struct vnode
*devvp
= NULLVP
;
1775 #endif /* CONFIG_TRIGGERS */
1777 if (flags
& MNT_FORCE
)
1781 /* XXX post jaguar fix LK_DRAIN - then clean this up */
1782 if ((flags
& MNT_FORCE
)) {
1783 mp
->mnt_kern_flag
|= MNTK_FRCUNMOUNT
;
1784 mp
->mnt_lflag
|= MNT_LFORCE
;
1786 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
1787 mp
->mnt_lflag
|= MNT_LWAIT
;
1790 msleep((caddr_t
)mp
, &mp
->mnt_mlock
, (PVFS
| PDROP
), "dounmount", NULL
);
1792 * The prior unmount attempt has probably succeeded.
1793 * Do not dereference mp here - returning EBUSY is safest.
1797 mp
->mnt_kern_flag
|= MNTK_UNMOUNT
;
1798 mp
->mnt_lflag
|= MNT_LUNMOUNT
;
1799 mp
->mnt_flag
&=~ MNT_ASYNC
;
1801 * anyone currently in the fast path that
1802 * trips over the cached rootvp will be
1803 * dumped out and forced into the slow path
1804 * to regenerate a new cached value
1806 mp
->mnt_realrootvp
= NULLVP
;
1810 * taking the name_cache_lock exclusively will
1811 * insure that everyone is out of the fast path who
1812 * might be trying to use a now stale copy of
1813 * vp->v_mountedhere->mnt_realrootvp
1814 * bumping mount_generation causes the cached values
1819 name_cache_unlock();
1822 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
1826 fsevent_unmount(mp
); /* has to come first! */
1829 if (forcedunmount
== 0) {
1830 ubc_umount(mp
); /* release cached vnodes */
1831 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
1832 error
= VFS_SYNC(mp
, MNT_WAIT
, ctx
);
1835 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
1836 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
1837 mp
->mnt_lflag
&= ~MNT_LFORCE
;
1844 vfs_nested_trigger_unmounts(mp
, flags
, ctx
);
1848 lflags
|= FORCECLOSE
;
1849 error
= vflush(mp
, NULLVP
, SKIPSWAP
| SKIPSYSTEM
| SKIPROOT
| lflags
);
1850 if ((forcedunmount
== 0) && error
) {
1852 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
1853 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
1854 mp
->mnt_lflag
&= ~MNT_LFORCE
;
1858 /* make sure there are no one in the mount iterations or lookup */
1859 mount_iterdrain(mp
);
1861 error
= VFS_UNMOUNT(mp
, flags
, ctx
);
1863 mount_iterreset(mp
);
1865 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
1866 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
1867 mp
->mnt_lflag
&= ~MNT_LFORCE
;
1871 /* increment the operations count */
1873 OSAddAtomic(1, &vfs_nummntops
);
1875 if ( mp
->mnt_devvp
&& mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
1876 /* hold an io reference and drop the usecount before close */
1877 devvp
= mp
->mnt_devvp
;
1878 vnode_getalways(devvp
);
1880 VNOP_CLOSE(devvp
, mp
->mnt_flag
& MNT_RDONLY
? FREAD
: FREAD
|FWRITE
,
1882 vnode_clearmountedon(devvp
);
1885 lck_rw_done(&mp
->mnt_rwlock
);
1886 mount_list_remove(mp
);
1887 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
1889 /* mark the mount point hook in the vp but not drop the ref yet */
1890 if ((coveredvp
= mp
->mnt_vnodecovered
) != NULLVP
) {
1891 vnode_getwithref(coveredvp
);
1892 vnode_lock_spin(coveredvp
);
1895 coveredvp
->v_mountedhere
= (struct mount
*)0;
1897 vnode_unlock(coveredvp
);
1898 vnode_put(coveredvp
);
1902 mp
->mnt_vtable
->vfc_refcount
--;
1903 mount_list_unlock();
1905 cache_purgevfs(mp
); /* remove cache entries for this file sys */
1906 vfs_event_signal(NULL
, VQ_UNMOUNT
, (intptr_t)NULL
);
1908 mp
->mnt_lflag
|= MNT_LDEAD
;
1910 if (mp
->mnt_lflag
& MNT_LWAIT
) {
1912 * do the wakeup here
1913 * in case we block in mount_refdrain
1914 * which will drop the mount lock
1915 * and allow anyone blocked in vfs_busy
1916 * to wakeup and see the LDEAD state
1918 mp
->mnt_lflag
&= ~MNT_LWAIT
;
1919 wakeup((caddr_t
)mp
);
1923 if (mp
->mnt_lflag
& MNT_LWAIT
) {
1924 mp
->mnt_lflag
&= ~MNT_LWAIT
;
1931 * Callback and context are set together under the mount lock, and
1932 * never cleared, so we're safe to examine them here, drop the lock,
1935 if (mp
->mnt_triggercallback
!= NULL
) {
1938 mp
->mnt_triggercallback(mp
, VTC_RELEASE
, mp
->mnt_triggerdata
, ctx
);
1939 } else if (did_vflush
) {
1940 mp
->mnt_triggercallback(mp
, VTC_REPLACE
, mp
->mnt_triggerdata
, ctx
);
1947 #endif /* CONFIG_TRIGGERS */
1949 lck_rw_done(&mp
->mnt_rwlock
);
1952 wakeup((caddr_t
)mp
);
1955 if ((coveredvp
!= NULLVP
)) {
1958 vnode_getwithref(coveredvp
);
1959 pvp
= vnode_getparent(coveredvp
);
1960 vnode_rele(coveredvp
);
1962 mount_dropcrossref(mp
, coveredvp
, 0);
1964 if (coveredvp
->v_resolve
)
1965 vnode_trigger_rearm(coveredvp
, ctx
);
1967 vnode_put(coveredvp
);
1970 lock_vnode_and_post(pvp
, NOTE_WRITE
);
1973 } else if (mp
->mnt_flag
& MNT_ROOTFS
) {
1974 mount_lock_destroy(mp
);
1976 mac_mount_label_destroy(mp
);
1978 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
1980 panic("dounmount: no coveredvp");
1986 mount_dropcrossref(mount_t mp
, vnode_t dp
, int need_put
)
1991 if (mp
->mnt_crossref
< 0)
1992 panic("mount cross refs -ve");
1994 if ((mp
!= dp
->v_mountedhere
) && (mp
->mnt_crossref
== 0)) {
1997 vnode_put_locked(dp
);
2000 mount_lock_destroy(mp
);
2002 mac_mount_label_destroy(mp
);
2004 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
2008 vnode_put_locked(dp
);
2014 * Sync each mounted filesystem.
2018 struct ctldebug debug0
= { "syncprt", &syncprt
};
2021 int print_vmpage_stat
=0;
2024 sync_callback(mount_t mp
, void * arg
)
2028 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
2029 asyncflag
= mp
->mnt_flag
& MNT_ASYNC
;
2030 mp
->mnt_flag
&= ~MNT_ASYNC
;
2031 VFS_SYNC(mp
, arg
? MNT_WAIT
: MNT_NOWAIT
, vfs_context_current());
2033 mp
->mnt_flag
|= MNT_ASYNC
;
2035 return(VFS_RETURNED
);
2039 #include <kern/clock.h>
2041 clock_sec_t sync_wait_time
= 0;
2045 sync(__unused proc_t p
, __unused
struct sync_args
*uap
, __unused
int32_t *retval
)
2049 vfs_iterate(LK_NOWAIT
, sync_callback
, (void *)0);
2052 static fsid_t fsid
= { { 0, 0 } };
2054 clock_get_calendar_microtime(&sync_wait_time
, &nsecs
);
2055 vfs_event_signal(&fsid
, VQ_SYNCEVENT
, (intptr_t)NULL
);
2056 wakeup((caddr_t
)&sync_wait_time
);
2060 if(print_vmpage_stat
) {
2061 vm_countdirtypages();
2067 #endif /* DIAGNOSTIC */
2072 * Change filesystem quotas.
2075 static int quotactl_funneled(proc_t p
, struct quotactl_args
*uap
, int32_t *retval
);
2078 quotactl(proc_t p
, struct quotactl_args
*uap
, int32_t *retval
)
2080 boolean_t funnel_state
;
2083 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
2084 error
= quotactl_funneled(p
, uap
, retval
);
2085 thread_funnel_set(kernel_flock
, funnel_state
);
2090 quotactl_funneled(proc_t p
, struct quotactl_args
*uap
, __unused
int32_t *retval
)
2093 int error
, quota_cmd
, quota_status
;
2096 struct nameidata nd
;
2097 vfs_context_t ctx
= vfs_context_current();
2098 struct dqblk my_dqblk
;
2100 AUDIT_ARG(uid
, uap
->uid
);
2101 AUDIT_ARG(cmd
, uap
->cmd
);
2102 NDINIT(&nd
, LOOKUP
, OP_LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
,
2107 mp
= nd
.ni_vp
->v_mount
;
2108 vnode_put(nd
.ni_vp
);
2111 /* copyin any data we will need for downstream code */
2112 quota_cmd
= uap
->cmd
>> SUBCMDSHIFT
;
2114 switch (quota_cmd
) {
2116 /* uap->arg specifies a file from which to take the quotas */
2117 fnamelen
= MAXPATHLEN
;
2118 datap
= kalloc(MAXPATHLEN
);
2119 error
= copyinstr(uap
->arg
, datap
, MAXPATHLEN
, &fnamelen
);
2122 /* uap->arg is a pointer to a dqblk structure. */
2123 datap
= (caddr_t
) &my_dqblk
;
2127 /* uap->arg is a pointer to a dqblk structure. */
2128 datap
= (caddr_t
) &my_dqblk
;
2129 if (proc_is64bit(p
)) {
2130 struct user_dqblk my_dqblk64
;
2131 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk64
, sizeof (my_dqblk64
));
2133 munge_dqblk(&my_dqblk
, &my_dqblk64
, FALSE
);
2137 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk
, sizeof (my_dqblk
));
2141 /* uap->arg is a pointer to an integer */
2142 datap
= (caddr_t
) "a_status
;
2150 error
= VFS_QUOTACTL(mp
, uap
->cmd
, uap
->uid
, datap
, ctx
);
2153 switch (quota_cmd
) {
2156 kfree(datap
, MAXPATHLEN
);
2159 /* uap->arg is a pointer to a dqblk structure we need to copy out to */
2161 if (proc_is64bit(p
)) {
2162 struct user_dqblk my_dqblk64
;
2163 munge_dqblk(&my_dqblk
, &my_dqblk64
, TRUE
);
2164 error
= copyout((caddr_t
)&my_dqblk64
, uap
->arg
, sizeof (my_dqblk64
));
2167 error
= copyout(datap
, uap
->arg
, sizeof (struct dqblk
));
2172 /* uap->arg is a pointer to an integer */
2174 error
= copyout(datap
, uap
->arg
, sizeof(quota_status
));
2185 quotactl(__unused proc_t p
, __unused
struct quotactl_args
*uap
, __unused
int32_t *retval
)
2187 return (EOPNOTSUPP
);
2192 * Get filesystem statistics.
2194 * Returns: 0 Success
2196 * vfs_update_vfsstat:???
2197 * munge_statfs:EFAULT
2201 statfs(__unused proc_t p
, struct statfs_args
*uap
, __unused
int32_t *retval
)
2204 struct vfsstatfs
*sp
;
2206 struct nameidata nd
;
2207 vfs_context_t ctx
= vfs_context_current();
2210 NDINIT(&nd
, LOOKUP
, OP_STATFS
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
2211 UIO_USERSPACE
, uap
->path
, ctx
);
2217 sp
= &mp
->mnt_vfsstat
;
2220 error
= vfs_update_vfsstat(mp
, ctx
, VFS_USER_EVENT
);
2225 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
2230 * Get filesystem statistics.
2234 fstatfs(__unused proc_t p
, struct fstatfs_args
*uap
, __unused
int32_t *retval
)
2238 struct vfsstatfs
*sp
;
2241 AUDIT_ARG(fd
, uap
->fd
);
2243 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
2246 error
= vnode_getwithref(vp
);
2252 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
2259 sp
= &mp
->mnt_vfsstat
;
2260 if ((error
= vfs_update_vfsstat(mp
,vfs_context_current(),VFS_USER_EVENT
)) != 0) {
2264 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
2274 * Common routine to handle copying of statfs64 data to user space
2277 statfs64_common(struct mount
*mp
, struct vfsstatfs
*sfsp
, user_addr_t bufp
)
2280 struct statfs64 sfs
;
2282 bzero(&sfs
, sizeof(sfs
));
2284 sfs
.f_bsize
= sfsp
->f_bsize
;
2285 sfs
.f_iosize
= (int32_t)sfsp
->f_iosize
;
2286 sfs
.f_blocks
= sfsp
->f_blocks
;
2287 sfs
.f_bfree
= sfsp
->f_bfree
;
2288 sfs
.f_bavail
= sfsp
->f_bavail
;
2289 sfs
.f_files
= sfsp
->f_files
;
2290 sfs
.f_ffree
= sfsp
->f_ffree
;
2291 sfs
.f_fsid
= sfsp
->f_fsid
;
2292 sfs
.f_owner
= sfsp
->f_owner
;
2293 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
2294 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
2295 sfs
.f_fssubtype
= sfsp
->f_fssubtype
;
2296 if (mp
->mnt_kern_flag
& MNTK_TYPENAME_OVERRIDE
) {
2297 strlcpy(&sfs
.f_fstypename
[0], &mp
->fstypename_override
[0], MFSTYPENAMELEN
);
2299 strlcpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSTYPENAMELEN
);
2301 strlcpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MAXPATHLEN
);
2302 strlcpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MAXPATHLEN
);
2304 error
= copyout((caddr_t
)&sfs
, bufp
, sizeof(sfs
));
2310 * Get file system statistics in 64-bit mode
2313 statfs64(__unused
struct proc
*p
, struct statfs64_args
*uap
, __unused
int32_t *retval
)
2316 struct vfsstatfs
*sp
;
2318 struct nameidata nd
;
2319 vfs_context_t ctxp
= vfs_context_current();
2322 NDINIT(&nd
, LOOKUP
, OP_STATFS
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
2323 UIO_USERSPACE
, uap
->path
, ctxp
);
2329 sp
= &mp
->mnt_vfsstat
;
2332 error
= vfs_update_vfsstat(mp
, ctxp
, VFS_USER_EVENT
);
2337 error
= statfs64_common(mp
, sp
, uap
->buf
);
2343 * Get file system statistics in 64-bit mode
2346 fstatfs64(__unused
struct proc
*p
, struct fstatfs64_args
*uap
, __unused
int32_t *retval
)
2350 struct vfsstatfs
*sp
;
2353 AUDIT_ARG(fd
, uap
->fd
);
2355 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
2358 error
= vnode_getwithref(vp
);
2364 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
2371 sp
= &mp
->mnt_vfsstat
;
2372 if ((error
= vfs_update_vfsstat(mp
, vfs_context_current(), VFS_USER_EVENT
)) != 0) {
2376 error
= statfs64_common(mp
, sp
, uap
->buf
);
2385 struct getfsstat_struct
{
2396 getfsstat_callback(mount_t mp
, void * arg
)
2399 struct getfsstat_struct
*fstp
= (struct getfsstat_struct
*)arg
;
2400 struct vfsstatfs
*sp
;
2402 vfs_context_t ctx
= vfs_context_current();
2404 if (fstp
->sfsp
&& fstp
->count
< fstp
->maxcount
) {
2405 sp
= &mp
->mnt_vfsstat
;
2407 * If MNT_NOWAIT is specified, do not refresh the
2408 * fsstat cache. MNT_WAIT/MNT_DWAIT overrides MNT_NOWAIT.
2410 if (((fstp
->flags
& MNT_NOWAIT
) == 0 || (fstp
->flags
& (MNT_WAIT
| MNT_DWAIT
))) &&
2411 (error
= vfs_update_vfsstat(mp
, ctx
,
2413 KAUTH_DEBUG("vfs_update_vfsstat returned %d", error
);
2414 return(VFS_RETURNED
);
2418 * Need to handle LP64 version of struct statfs
2420 error
= munge_statfs(mp
, sp
, fstp
->sfsp
, &my_size
, IS_64BIT_PROCESS(vfs_context_proc(ctx
)), FALSE
);
2422 fstp
->error
= error
;
2423 return(VFS_RETURNED_DONE
);
2425 fstp
->sfsp
+= my_size
;
2428 error
= mac_mount_label_get(mp
, *fstp
->mp
);
2430 fstp
->error
= error
;
2431 return(VFS_RETURNED_DONE
);
2437 return(VFS_RETURNED
);
2441 * Get statistics on all filesystems.
2444 getfsstat(__unused proc_t p
, struct getfsstat_args
*uap
, int *retval
)
2446 struct __mac_getfsstat_args muap
;
2448 muap
.buf
= uap
->buf
;
2449 muap
.bufsize
= uap
->bufsize
;
2450 muap
.mac
= USER_ADDR_NULL
;
2452 muap
.flags
= uap
->flags
;
2454 return (__mac_getfsstat(p
, &muap
, retval
));
2458 * __mac_getfsstat: Get MAC-related file system statistics
2460 * Parameters: p (ignored)
2461 * uap User argument descriptor (see below)
2462 * retval Count of file system statistics (N stats)
2464 * Indirect: uap->bufsize Buffer size
2465 * uap->macsize MAC info size
2466 * uap->buf Buffer where information will be returned
2468 * uap->flags File system flags
2471 * Returns: 0 Success
2476 __mac_getfsstat(__unused proc_t p
, struct __mac_getfsstat_args
*uap
, int *retval
)
2480 size_t count
, maxcount
, bufsize
, macsize
;
2481 struct getfsstat_struct fst
;
2483 bufsize
= (size_t) uap
->bufsize
;
2484 macsize
= (size_t) uap
->macsize
;
2486 if (IS_64BIT_PROCESS(p
)) {
2487 maxcount
= bufsize
/ sizeof(struct user64_statfs
);
2490 maxcount
= bufsize
/ sizeof(struct user32_statfs
);
2498 if (uap
->mac
!= USER_ADDR_NULL
) {
2503 count
= (macsize
/ (IS_64BIT_PROCESS(p
) ? 8 : 4));
2504 if (count
!= maxcount
)
2507 /* Copy in the array */
2508 MALLOC(mp0
, u_int32_t
*, macsize
, M_MACTEMP
, M_WAITOK
);
2513 error
= copyin(uap
->mac
, mp0
, macsize
);
2515 FREE(mp0
, M_MACTEMP
);
2519 /* Normalize to an array of user_addr_t */
2520 MALLOC(mp
, user_addr_t
*, count
* sizeof(user_addr_t
), M_MACTEMP
, M_WAITOK
);
2522 FREE(mp0
, M_MACTEMP
);
2526 for (i
= 0; i
< count
; i
++) {
2527 if (IS_64BIT_PROCESS(p
))
2528 mp
[i
] = ((user_addr_t
*)mp0
)[i
];
2530 mp
[i
] = (user_addr_t
)mp0
[i
];
2532 FREE(mp0
, M_MACTEMP
);
2539 fst
.flags
= uap
->flags
;
2542 fst
.maxcount
= maxcount
;
2545 vfs_iterate(0, getfsstat_callback
, &fst
);
2548 FREE(mp
, M_MACTEMP
);
2551 KAUTH_DEBUG("ERROR - %s gets %d", p
->p_comm
, fst
.error
);
2555 if (fst
.sfsp
&& fst
.count
> fst
.maxcount
)
2556 *retval
= fst
.maxcount
;
2558 *retval
= fst
.count
;
2563 getfsstat64_callback(mount_t mp
, void * arg
)
2565 struct getfsstat_struct
*fstp
= (struct getfsstat_struct
*)arg
;
2566 struct vfsstatfs
*sp
;
2569 if (fstp
->sfsp
&& fstp
->count
< fstp
->maxcount
) {
2570 sp
= &mp
->mnt_vfsstat
;
2572 * If MNT_NOWAIT is specified, do not refresh the fsstat
2573 * cache. MNT_WAIT overrides MNT_NOWAIT.
2575 * We treat MNT_DWAIT as MNT_WAIT for all instances of
2576 * getfsstat, since the constants are out of the same
2579 if (((fstp
->flags
& MNT_NOWAIT
) == 0 ||
2580 (fstp
->flags
& (MNT_WAIT
| MNT_DWAIT
))) &&
2581 (error
= vfs_update_vfsstat(mp
, vfs_context_current(), VFS_USER_EVENT
))) {
2582 KAUTH_DEBUG("vfs_update_vfsstat returned %d", error
);
2583 return(VFS_RETURNED
);
2586 error
= statfs64_common(mp
, sp
, fstp
->sfsp
);
2588 fstp
->error
= error
;
2589 return(VFS_RETURNED_DONE
);
2591 fstp
->sfsp
+= sizeof(struct statfs64
);
2594 return(VFS_RETURNED
);
2598 * Get statistics on all file systems in 64 bit mode.
2601 getfsstat64(__unused proc_t p
, struct getfsstat64_args
*uap
, int *retval
)
2604 int count
, maxcount
;
2605 struct getfsstat_struct fst
;
2607 maxcount
= uap
->bufsize
/ sizeof(struct statfs64
);
2613 fst
.flags
= uap
->flags
;
2616 fst
.maxcount
= maxcount
;
2618 vfs_iterate(0, getfsstat64_callback
, &fst
);
2621 KAUTH_DEBUG("ERROR - %s gets %d", p
->p_comm
, fst
.error
);
2625 if (fst
.sfsp
&& fst
.count
> fst
.maxcount
)
2626 *retval
= fst
.maxcount
;
2628 *retval
= fst
.count
;
2634 * Change current working directory to a given file descriptor.
2638 common_fchdir(proc_t p
, struct fchdir_args
*uap
, int per_thread
)
2640 struct filedesc
*fdp
= p
->p_fd
;
2646 vfs_context_t ctx
= vfs_context_current();
2648 AUDIT_ARG(fd
, uap
->fd
);
2649 if (per_thread
&& uap
->fd
== -1) {
2651 * Switching back from per-thread to per process CWD; verify we
2652 * in fact have one before proceeding. The only success case
2653 * for this code path is to return 0 preemptively after zapping
2654 * the thread structure contents.
2656 thread_t th
= vfs_context_thread(ctx
);
2658 uthread_t uth
= get_bsdthread_info(th
);
2660 uth
->uu_cdir
= NULLVP
;
2661 if (tvp
!= NULLVP
) {
2669 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
2671 if ( (error
= vnode_getwithref(vp
)) ) {
2676 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2678 if (vp
->v_type
!= VDIR
) {
2684 error
= mac_vnode_check_chdir(ctx
, vp
);
2688 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, ctx
);
2692 while (!error
&& (mp
= vp
->v_mountedhere
) != NULL
) {
2693 if (vfs_busy(mp
, LK_NOWAIT
)) {
2697 error
= VFS_ROOT(mp
, &tdp
, ctx
);
2706 if ( (error
= vnode_ref(vp
)) )
2711 thread_t th
= vfs_context_thread(ctx
);
2713 uthread_t uth
= get_bsdthread_info(th
);
2716 OSBitOrAtomic(P_THCWD
, &p
->p_flag
);
2741 fchdir(proc_t p
, struct fchdir_args
*uap
, __unused
int32_t *retval
)
2743 return common_fchdir(p
, uap
, 0);
2747 __pthread_fchdir(proc_t p
, struct __pthread_fchdir_args
*uap
, __unused
int32_t *retval
)
2749 return common_fchdir(p
, (void *)uap
, 1);
2753 * Change current working directory (".").
2755 * Returns: 0 Success
2756 * change_dir:ENOTDIR
2758 * vnode_ref:ENOENT No such file or directory
2762 common_chdir(proc_t p
, struct chdir_args
*uap
, int per_thread
)
2764 struct filedesc
*fdp
= p
->p_fd
;
2766 struct nameidata nd
;
2768 vfs_context_t ctx
= vfs_context_current();
2770 NDINIT(&nd
, LOOKUP
, OP_CHDIR
, FOLLOW
| AUDITVNPATH1
,
2771 UIO_USERSPACE
, uap
->path
, ctx
);
2772 error
= change_dir(&nd
, ctx
);
2775 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
2776 vnode_put(nd
.ni_vp
);
2780 * drop the iocount we picked up in change_dir
2782 vnode_put(nd
.ni_vp
);
2785 thread_t th
= vfs_context_thread(ctx
);
2787 uthread_t uth
= get_bsdthread_info(th
);
2789 uth
->uu_cdir
= nd
.ni_vp
;
2790 OSBitOrAtomic(P_THCWD
, &p
->p_flag
);
2792 vnode_rele(nd
.ni_vp
);
2798 fdp
->fd_cdir
= nd
.ni_vp
;
2812 * Change current working directory (".") for the entire process
2814 * Parameters: p Process requesting the call
2815 * uap User argument descriptor (see below)
2818 * Indirect parameters: uap->path Directory path
2820 * Returns: 0 Success
2821 * common_chdir: ENOTDIR
2822 * common_chdir: ENOENT No such file or directory
2827 chdir(proc_t p
, struct chdir_args
*uap
, __unused
int32_t *retval
)
2829 return common_chdir(p
, (void *)uap
, 0);
2835 * Change current working directory (".") for a single thread
2837 * Parameters: p Process requesting the call
2838 * uap User argument descriptor (see below)
2841 * Indirect parameters: uap->path Directory path
2843 * Returns: 0 Success
2844 * common_chdir: ENOTDIR
2845 * common_chdir: ENOENT No such file or directory
2850 __pthread_chdir(proc_t p
, struct __pthread_chdir_args
*uap
, __unused
int32_t *retval
)
2852 return common_chdir(p
, (void *)uap
, 1);
2857 * Change notion of root (``/'') directory.
2861 chroot(proc_t p
, struct chroot_args
*uap
, __unused
int32_t *retval
)
2863 struct filedesc
*fdp
= p
->p_fd
;
2865 struct nameidata nd
;
2867 vfs_context_t ctx
= vfs_context_current();
2869 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
2872 NDINIT(&nd
, LOOKUP
, OP_CHROOT
, FOLLOW
| AUDITVNPATH1
,
2873 UIO_USERSPACE
, uap
->path
, ctx
);
2874 error
= change_dir(&nd
, ctx
);
2879 error
= mac_vnode_check_chroot(ctx
, nd
.ni_vp
,
2882 vnode_put(nd
.ni_vp
);
2887 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
2888 vnode_put(nd
.ni_vp
);
2891 vnode_put(nd
.ni_vp
);
2895 fdp
->fd_rdir
= nd
.ni_vp
;
2896 fdp
->fd_flags
|= FD_CHROOT
;
2906 * Common routine for chroot and chdir.
2908 * Returns: 0 Success
2909 * ENOTDIR Not a directory
2910 * namei:??? [anything namei can return]
2911 * vnode_authorize:??? [anything vnode_authorize can return]
2914 change_dir(struct nameidata
*ndp
, vfs_context_t ctx
)
2919 if ((error
= namei(ndp
)))
2924 if (vp
->v_type
!= VDIR
) {
2930 error
= mac_vnode_check_chdir(ctx
, vp
);
2937 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, ctx
);
2947 * Check permissions, allocate an open file structure,
2948 * and call the device open routine if any.
2950 * Returns: 0 Success
2961 * XXX Need to implement uid, gid
2964 open1(vfs_context_t ctx
, struct nameidata
*ndp
, int uflags
, struct vnode_attr
*vap
, int32_t *retval
)
2966 proc_t p
= vfs_context_proc(ctx
);
2967 uthread_t uu
= get_bsdthread_info(vfs_context_thread(ctx
));
2968 struct filedesc
*fdp
= p
->p_fd
;
2969 struct fileproc
*fp
;
2972 struct fileproc
*nfp
;
2973 int type
, indx
, error
;
2975 int no_controlling_tty
= 0;
2976 int deny_controlling_tty
= 0;
2977 struct session
*sessp
= SESSION_NULL
;
2978 struct vfs_context context
= *vfs_context_current(); /* local copy */
2982 if ((oflags
& O_ACCMODE
) == O_ACCMODE
)
2984 flags
= FFLAGS(uflags
);
2986 AUDIT_ARG(fflags
, oflags
);
2987 AUDIT_ARG(mode
, vap
->va_mode
);
2989 if ( (error
= falloc(p
, &nfp
, &indx
, ctx
)) ) {
2993 uu
->uu_dupfd
= -indx
- 1;
2995 if (!(p
->p_flag
& P_CONTROLT
)) {
2996 sessp
= proc_session(p
);
2997 no_controlling_tty
= 1;
2999 * If conditions would warrant getting a controlling tty if
3000 * the device being opened is a tty (see ttyopen in tty.c),
3001 * but the open flags deny it, set a flag in the session to
3004 if (SESS_LEADER(p
, sessp
) &&
3005 sessp
->s_ttyvp
== NULL
&&
3006 (flags
& O_NOCTTY
)) {
3007 session_lock(sessp
);
3008 sessp
->s_flags
|= S_NOCTTY
;
3009 session_unlock(sessp
);
3010 deny_controlling_tty
= 1;
3014 if ((error
= vn_open_auth(ndp
, &flags
, vap
))) {
3015 if ((error
== ENODEV
|| error
== ENXIO
) && (uu
->uu_dupfd
>= 0)){ /* XXX from fdopen */
3016 if ((error
= dupfdopen(fdp
, indx
, uu
->uu_dupfd
, flags
, error
)) == 0) {
3017 fp_drop(p
, indx
, NULL
, 0);
3019 if (deny_controlling_tty
) {
3020 session_lock(sessp
);
3021 sessp
->s_flags
&= ~S_NOCTTY
;
3022 session_unlock(sessp
);
3024 if (sessp
!= SESSION_NULL
)
3025 session_rele(sessp
);
3029 if (error
== ERESTART
)
3031 fp_free(p
, indx
, fp
);
3033 if (deny_controlling_tty
) {
3034 session_lock(sessp
);
3035 sessp
->s_flags
&= ~S_NOCTTY
;
3036 session_unlock(sessp
);
3038 if (sessp
!= SESSION_NULL
)
3039 session_rele(sessp
);
3045 fp
->f_fglob
->fg_flag
= flags
& (FMASK
| O_EVTONLY
);
3046 fp
->f_fglob
->fg_type
= DTYPE_VNODE
;
3047 fp
->f_fglob
->fg_ops
= &vnops
;
3048 fp
->f_fglob
->fg_data
= (caddr_t
)vp
;
3051 if (VATTR_IS_ACTIVE (vap
, va_dataprotect_flags
)) {
3052 if (vap
->va_dataprotect_flags
& VA_DP_RAWENCRYPTED
) {
3053 fp
->f_fglob
->fg_flag
|= FENCRYPTED
;
3058 if (flags
& (O_EXLOCK
| O_SHLOCK
)) {
3059 lf
.l_whence
= SEEK_SET
;
3062 if (flags
& O_EXLOCK
)
3063 lf
.l_type
= F_WRLCK
;
3065 lf
.l_type
= F_RDLCK
;
3067 if ((flags
& FNONBLOCK
) == 0)
3070 error
= mac_file_check_lock(vfs_context_ucred(ctx
), fp
->f_fglob
,
3075 if ((error
= VNOP_ADVLOCK(vp
, (caddr_t
)fp
->f_fglob
, F_SETLK
, &lf
, type
, ctx
)))
3077 fp
->f_fglob
->fg_flag
|= FHASLOCK
;
3080 /* try to truncate by setting the size attribute */
3081 if ((flags
& O_TRUNC
) && ((error
= vnode_setsize(vp
, (off_t
)0, 0, ctx
)) != 0))
3085 * If the open flags denied the acquisition of a controlling tty,
3086 * clear the flag in the session structure that prevented the lower
3087 * level code from assigning one.
3089 if (deny_controlling_tty
) {
3090 session_lock(sessp
);
3091 sessp
->s_flags
&= ~S_NOCTTY
;
3092 session_unlock(sessp
);
3096 * If a controlling tty was set by the tty line discipline, then we
3097 * want to set the vp of the tty into the session structure. We have
3098 * a race here because we can't get to the vp for the tp in ttyopen,
3099 * because it's not passed as a parameter in the open path.
3101 if (no_controlling_tty
&& (p
->p_flag
& P_CONTROLT
)) {
3105 * We already have a ref from vn_open_auth(), so we can demand another reference.
3107 error
= vnode_ref_ext(vp
, 0, VNODE_REF_FORCE
);
3109 panic("vnode_ref_ext() with VNODE_REF_FORCE failed?!");
3112 session_lock(sessp
);
3113 ttyvp
= sessp
->s_ttyvp
;
3114 sessp
->s_ttyvp
= vp
;
3115 sessp
->s_ttyvid
= vnode_vid(vp
);
3116 session_unlock(sessp
);
3117 if (ttyvp
!= NULLVP
)
3124 if (flags
& O_CLOEXEC
)
3125 *fdflags(p
, indx
) |= UF_EXCLOSE
;
3126 procfdtbl_releasefd(p
, indx
, NULL
);
3127 fp_drop(p
, indx
, fp
, 1);
3132 if (sessp
!= SESSION_NULL
)
3133 session_rele(sessp
);
3136 if (deny_controlling_tty
) {
3137 session_lock(sessp
);
3138 sessp
->s_flags
&= ~S_NOCTTY
;
3139 session_unlock(sessp
);
3141 if (sessp
!= SESSION_NULL
)
3142 session_rele(sessp
);
3144 /* Modify local copy (to not damage thread copy) */
3145 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
3147 vn_close(vp
, fp
->f_fglob
->fg_flag
, &context
);
3149 fp_free(p
, indx
, fp
);
3156 * open_extended: open a file given a path name; with extended argument list (including extended security (ACL)).
3158 * Parameters: p Process requesting the open
3159 * uap User argument descriptor (see below)
3160 * retval Pointer to an area to receive the
3161 * return calue from the system call
3163 * Indirect: uap->path Path to open (same as 'open')
3164 * uap->flags Flags to open (same as 'open'
3165 * uap->uid UID to set, if creating
3166 * uap->gid GID to set, if creating
3167 * uap->mode File mode, if creating (same as 'open')
3168 * uap->xsecurity ACL to set, if creating
3170 * Returns: 0 Success
3173 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
3175 * XXX: We should enummerate the possible errno values here, and where
3176 * in the code they originated.
3179 open_extended(proc_t p
, struct open_extended_args
*uap
, int32_t *retval
)
3181 struct filedesc
*fdp
= p
->p_fd
;
3183 kauth_filesec_t xsecdst
;
3184 struct vnode_attr va
;
3185 struct nameidata nd
;
3188 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
3191 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
3192 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
3196 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
3197 VATTR_SET(&va
, va_mode
, cmode
);
3198 if (uap
->uid
!= KAUTH_UID_NONE
)
3199 VATTR_SET(&va
, va_uid
, uap
->uid
);
3200 if (uap
->gid
!= KAUTH_GID_NONE
)
3201 VATTR_SET(&va
, va_gid
, uap
->gid
);
3202 if (xsecdst
!= NULL
)
3203 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
3205 NDINIT(&nd
, LOOKUP
, OP_OPEN
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
,
3206 uap
->path
, vfs_context_current());
3208 ciferror
= open1(vfs_context_current(), &nd
, uap
->flags
, &va
, retval
);
3209 if (xsecdst
!= NULL
)
3210 kauth_filesec_free(xsecdst
);
3216 * Go through the data-protected atomically controlled open (2)
3218 * int open_dprotected_np(user_addr_t path, int flags, int class, int dpflags, int mode)
3220 int open_dprotected_np (__unused proc_t p
, struct open_dprotected_np_args
*uap
, int32_t *retval
) {
3221 int flags
= uap
->flags
;
3222 int class = uap
->class;
3223 int dpflags
= uap
->dpflags
;
3226 * Follow the same path as normal open(2)
3227 * Look up the item if it exists, and acquire the vnode.
3229 struct filedesc
*fdp
= p
->p_fd
;
3230 struct vnode_attr va
;
3231 struct nameidata nd
;
3236 /* Mask off all but regular access permissions */
3237 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
3238 VATTR_SET(&va
, va_mode
, cmode
& ACCESSPERMS
);
3240 NDINIT(&nd
, LOOKUP
, OP_OPEN
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
,
3241 uap
->path
, vfs_context_current());
3244 * Initialize the extra fields in vnode_attr to pass down our
3246 * 1. target cprotect class.
3247 * 2. set a flag to mark it as requiring open-raw-encrypted semantics.
3249 if (flags
& O_CREAT
) {
3250 VATTR_SET(&va
, va_dataprotect_class
, class);
3253 if (dpflags
& O_DP_GETRAWENCRYPTED
) {
3254 if ( flags
& (O_RDWR
| O_WRONLY
)) {
3255 /* Not allowed to write raw encrypted bytes */
3258 VATTR_SET(&va
, va_dataprotect_flags
, VA_DP_RAWENCRYPTED
);
3261 error
= open1(vfs_context_current(), &nd
, uap
->flags
, &va
, retval
);
3268 open(proc_t p
, struct open_args
*uap
, int32_t *retval
)
3270 __pthread_testcancel(1);
3271 return(open_nocancel(p
, (struct open_nocancel_args
*)uap
, retval
));
3275 open_nocancel(proc_t p
, struct open_nocancel_args
*uap
, int32_t *retval
)
3277 struct filedesc
*fdp
= p
->p_fd
;
3278 struct vnode_attr va
;
3279 struct nameidata nd
;
3283 /* Mask off all but regular access permissions */
3284 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
3285 VATTR_SET(&va
, va_mode
, cmode
& ACCESSPERMS
);
3287 NDINIT(&nd
, LOOKUP
, OP_OPEN
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
,
3288 uap
->path
, vfs_context_current());
3290 return(open1(vfs_context_current(), &nd
, uap
->flags
, &va
, retval
));
3295 * Create a special file.
3297 static int mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
);
3300 mknod(proc_t p
, struct mknod_args
*uap
, __unused
int32_t *retval
)
3302 struct vnode_attr va
;
3303 vfs_context_t ctx
= vfs_context_current();
3305 struct nameidata nd
;
3309 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
3310 VATTR_SET(&va
, va_rdev
, uap
->dev
);
3312 /* If it's a mknod() of a FIFO, call mkfifo1() instead */
3313 if ((uap
->mode
& S_IFMT
) == S_IFIFO
)
3314 return(mkfifo1(ctx
, uap
->path
, &va
));
3316 AUDIT_ARG(mode
, uap
->mode
);
3317 AUDIT_ARG(value32
, uap
->dev
);
3319 if ((error
= suser(vfs_context_ucred(ctx
), &p
->p_acflag
)))
3321 NDINIT(&nd
, CREATE
, OP_MKNOD
, LOCKPARENT
| AUDITVNPATH1
,
3322 UIO_USERSPACE
, uap
->path
, ctx
);
3334 switch (uap
->mode
& S_IFMT
) {
3335 case S_IFMT
: /* used by badsect to flag bad sectors */
3336 VATTR_SET(&va
, va_type
, VBAD
);
3339 VATTR_SET(&va
, va_type
, VCHR
);
3342 VATTR_SET(&va
, va_type
, VBLK
);
3350 error
= mac_vnode_check_create(ctx
,
3351 nd
.ni_dvp
, &nd
.ni_cnd
, &va
);
3356 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
3359 if ((error
= vn_create(dvp
, &vp
, &nd
, &va
, 0, 0, NULL
, ctx
)) != 0)
3363 int update_flags
= 0;
3365 // Make sure the name & parent pointers are hooked up
3366 if (vp
->v_name
== NULL
)
3367 update_flags
|= VNODE_UPDATE_NAME
;
3368 if (vp
->v_parent
== NULLVP
)
3369 update_flags
|= VNODE_UPDATE_PARENT
;
3372 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
3375 add_fsevent(FSE_CREATE_FILE
, ctx
,
3383 * nameidone has to happen before we vnode_put(dvp)
3384 * since it may need to release the fs_nodelock on the dvp
3396 * Create a named pipe.
3398 * Returns: 0 Success
3401 * vnode_authorize:???
3405 mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
)
3409 struct nameidata nd
;
3411 NDINIT(&nd
, CREATE
, OP_MKFIFO
, LOCKPARENT
| AUDITVNPATH1
,
3412 UIO_USERSPACE
, upath
, ctx
);
3419 /* check that this is a new file and authorize addition */
3424 VATTR_SET(vap
, va_type
, VFIFO
);
3426 if ((error
= vn_authorize_create(dvp
, &nd
.ni_cnd
, vap
, ctx
, NULL
)) != 0)
3429 error
= vn_create(dvp
, &vp
, &nd
, vap
, 0, 0, NULL
, ctx
);
3432 * nameidone has to happen before we vnode_put(dvp)
3433 * since it may need to release the fs_nodelock on the dvp
3446 * mkfifo_extended: Create a named pipe; with extended argument list (including extended security (ACL)).
3448 * Parameters: p Process requesting the open
3449 * uap User argument descriptor (see below)
3452 * Indirect: uap->path Path to fifo (same as 'mkfifo')
3453 * uap->uid UID to set
3454 * uap->gid GID to set
3455 * uap->mode File mode to set (same as 'mkfifo')
3456 * uap->xsecurity ACL to set, if creating
3458 * Returns: 0 Success
3461 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
3463 * XXX: We should enummerate the possible errno values here, and where
3464 * in the code they originated.
3467 mkfifo_extended(proc_t p
, struct mkfifo_extended_args
*uap
, __unused
int32_t *retval
)
3470 kauth_filesec_t xsecdst
;
3471 struct vnode_attr va
;
3473 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
3475 xsecdst
= KAUTH_FILESEC_NONE
;
3476 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
3477 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
3482 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
3483 if (uap
->uid
!= KAUTH_UID_NONE
)
3484 VATTR_SET(&va
, va_uid
, uap
->uid
);
3485 if (uap
->gid
!= KAUTH_GID_NONE
)
3486 VATTR_SET(&va
, va_gid
, uap
->gid
);
3487 if (xsecdst
!= KAUTH_FILESEC_NONE
)
3488 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
3490 ciferror
= mkfifo1(vfs_context_current(), uap
->path
, &va
);
3492 if (xsecdst
!= KAUTH_FILESEC_NONE
)
3493 kauth_filesec_free(xsecdst
);
3499 mkfifo(proc_t p
, struct mkfifo_args
*uap
, __unused
int32_t *retval
)
3501 struct vnode_attr va
;
3504 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
3506 return(mkfifo1(vfs_context_current(), uap
->path
, &va
));
3511 my_strrchr(char *p
, int ch
)
3515 for (save
= NULL
;; ++p
) {
3524 extern int safe_getpath(struct vnode
*dvp
, char *leafname
, char *path
, int _len
, int *truncated_path
);
3527 safe_getpath(struct vnode
*dvp
, char *leafname
, char *path
, int _len
, int *truncated_path
)
3529 int ret
, len
= _len
;
3531 *truncated_path
= 0;
3532 ret
= vn_getpath(dvp
, path
, &len
);
3533 if (ret
== 0 && len
< (MAXPATHLEN
- 1)) {
3536 len
+= strlcpy(&path
[len
], leafname
, MAXPATHLEN
-len
) + 1;
3537 if (len
> MAXPATHLEN
) {
3540 // the string got truncated!
3541 *truncated_path
= 1;
3542 ptr
= my_strrchr(path
, '/');
3544 *ptr
= '\0'; // chop off the string at the last directory component
3546 len
= strlen(path
) + 1;
3549 } else if (ret
== 0) {
3550 *truncated_path
= 1;
3551 } else if (ret
!= 0) {
3552 struct vnode
*mydvp
=dvp
;
3554 if (ret
!= ENOSPC
) {
3555 printf("safe_getpath: failed to get the path for vp %p (%s) : err %d\n",
3556 dvp
, dvp
->v_name
? dvp
->v_name
: "no-name", ret
);
3558 *truncated_path
= 1;
3561 if (mydvp
->v_parent
!= NULL
) {
3562 mydvp
= mydvp
->v_parent
;
3563 } else if (mydvp
->v_mount
) {
3564 strlcpy(path
, mydvp
->v_mount
->mnt_vfsstat
.f_mntonname
, _len
);
3567 // no parent and no mount point? only thing is to punt and say "/" changed
3568 strlcpy(path
, "/", _len
);
3573 if (mydvp
== NULL
) {
3578 ret
= vn_getpath(mydvp
, path
, &len
);
3579 } while (ret
== ENOSPC
);
3587 * Make a hard file link.
3589 * Returns: 0 Success
3594 * vnode_authorize:???
3599 link(__unused proc_t p
, struct link_args
*uap
, __unused
int32_t *retval
)
3601 vnode_t vp
, dvp
, lvp
;
3602 struct nameidata nd
;
3603 vfs_context_t ctx
= vfs_context_current();
3608 int need_event
, has_listeners
;
3609 char *target_path
= NULL
;
3612 vp
= dvp
= lvp
= NULLVP
;
3614 /* look up the object we are linking to */
3615 NDINIT(&nd
, LOOKUP
, OP_LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3616 UIO_USERSPACE
, uap
->path
, ctx
);
3625 * Normally, linking to directories is not supported.
3626 * However, some file systems may have limited support.
3628 if (vp
->v_type
== VDIR
) {
3629 if (!(vp
->v_mount
->mnt_vtable
->vfc_vfsflags
& VFC_VFSDIRLINKS
)) {
3630 error
= EPERM
; /* POSIX */
3633 /* Linking to a directory requires ownership. */
3634 if (!kauth_cred_issuser(vfs_context_ucred(ctx
))) {
3635 struct vnode_attr dva
;
3638 VATTR_WANTED(&dva
, va_uid
);
3639 if (vnode_getattr(vp
, &dva
, ctx
) != 0 ||
3640 !VATTR_IS_SUPPORTED(&dva
, va_uid
) ||
3641 (dva
.va_uid
!= kauth_cred_getuid(vfs_context_ucred(ctx
)))) {
3648 /* lookup the target node */
3652 nd
.ni_cnd
.cn_nameiop
= CREATE
;
3653 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| AUDITVNPATH2
| CN_NBMOUNTLOOK
;
3654 nd
.ni_dirp
= uap
->link
;
3662 if ((error
= mac_vnode_check_link(ctx
, dvp
, vp
, &nd
.ni_cnd
)) != 0)
3666 /* or to anything that kauth doesn't want us to (eg. immutable items) */
3667 if ((error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_LINKTARGET
, ctx
)) != 0)
3670 /* target node must not exist */
3671 if (lvp
!= NULLVP
) {
3675 /* cannot link across mountpoints */
3676 if (vnode_mount(vp
) != vnode_mount(dvp
)) {
3681 /* authorize creation of the target note */
3682 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
3685 /* and finally make the link */
3686 error
= VNOP_LINK(vp
, dvp
, &nd
.ni_cnd
, ctx
);
3691 need_event
= need_fsevent(FSE_CREATE_FILE
, dvp
);
3695 has_listeners
= kauth_authorize_fileop_has_listeners();
3697 if (need_event
|| has_listeners
) {
3698 char *link_to_path
= NULL
;
3699 int len
, link_name_len
;
3701 /* build the path to the new link file */
3702 GET_PATH(target_path
);
3703 if (target_path
== NULL
) {
3708 len
= safe_getpath(dvp
, nd
.ni_cnd
.cn_nameptr
, target_path
, MAXPATHLEN
, &truncated
);
3710 if (has_listeners
) {
3711 /* build the path to file we are linking to */
3712 GET_PATH(link_to_path
);
3713 if (link_to_path
== NULL
) {
3718 link_name_len
= MAXPATHLEN
;
3719 vn_getpath(vp
, link_to_path
, &link_name_len
);
3722 * Call out to allow 3rd party notification of rename.
3723 * Ignore result of kauth_authorize_fileop call.
3725 kauth_authorize_fileop(vfs_context_ucred(ctx
), KAUTH_FILEOP_LINK
,
3726 (uintptr_t)link_to_path
, (uintptr_t)target_path
);
3727 if (link_to_path
!= NULL
) {
3728 RELEASE_PATH(link_to_path
);
3733 /* construct fsevent */
3734 if (get_fse_info(vp
, &finfo
, ctx
) == 0) {
3736 finfo
.mode
|= FSE_TRUNCATED_PATH
;
3739 // build the path to the destination of the link
3740 add_fsevent(FSE_CREATE_FILE
, ctx
,
3741 FSE_ARG_STRING
, len
, target_path
,
3742 FSE_ARG_FINFO
, &finfo
,
3746 add_fsevent(FSE_STAT_CHANGED
, ctx
,
3747 FSE_ARG_VNODE
, vp
->v_parent
,
3755 * nameidone has to happen before we vnode_put(dvp)
3756 * since it may need to release the fs_nodelock on the dvp
3759 if (target_path
!= NULL
) {
3760 RELEASE_PATH(target_path
);
3772 * Make a symbolic link.
3774 * We could add support for ACLs here too...
3778 symlink(proc_t p
, struct symlink_args
*uap
, __unused
int32_t *retval
)
3780 struct vnode_attr va
;
3783 struct nameidata nd
;
3784 vfs_context_t ctx
= vfs_context_current();
3788 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
3789 error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
);
3792 AUDIT_ARG(text
, path
); /* This is the link string */
3794 NDINIT(&nd
, CREATE
, OP_SYMLINK
, LOCKPARENT
| AUDITVNPATH1
,
3795 UIO_USERSPACE
, uap
->link
, ctx
);
3803 VATTR_SET(&va
, va_type
, VLNK
);
3804 VATTR_SET(&va
, va_mode
, ACCESSPERMS
& ~p
->p_fd
->fd_cmask
);
3806 error
= mac_vnode_check_create(ctx
,
3807 dvp
, &nd
.ni_cnd
, &va
);
3820 error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
);
3821 /* get default ownership, etc. */
3823 error
= vnode_authattr_new(dvp
, &va
, 0, ctx
);
3825 error
= VNOP_SYMLINK(dvp
, &vp
, &nd
.ni_cnd
, &va
, path
, ctx
);
3827 /* do fallback attribute handling */
3829 error
= vnode_setattr_fallback(vp
, &va
, ctx
);
3832 int update_flags
= 0;
3835 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
3837 nd
.ni_op
= OP_LOOKUP
;
3839 nd
.ni_cnd
.cn_flags
= 0;
3847 #if 0 /* XXX - kauth_todo - is KAUTH_FILEOP_SYMLINK needed? */
3848 /* call out to allow 3rd party notification of rename.
3849 * Ignore result of kauth_authorize_fileop call.
3851 if (kauth_authorize_fileop_has_listeners() &&
3853 char *new_link_path
= NULL
;
3856 /* build the path to the new link file */
3857 new_link_path
= get_pathbuff();
3859 vn_getpath(dvp
, new_link_path
, &len
);
3860 if ((len
+ 1 + nd
.ni_cnd
.cn_namelen
+ 1) < MAXPATHLEN
) {
3861 new_link_path
[len
- 1] = '/';
3862 strlcpy(&new_link_path
[len
], nd
.ni_cnd
.cn_nameptr
, MAXPATHLEN
-len
);
3865 kauth_authorize_fileop(vfs_context_ucred(ctx
), KAUTH_FILEOP_SYMLINK
,
3866 (uintptr_t)path
, (uintptr_t)new_link_path
);
3867 if (new_link_path
!= NULL
)
3868 release_pathbuff(new_link_path
);
3871 // Make sure the name & parent pointers are hooked up
3872 if (vp
->v_name
== NULL
)
3873 update_flags
|= VNODE_UPDATE_NAME
;
3874 if (vp
->v_parent
== NULLVP
)
3875 update_flags
|= VNODE_UPDATE_PARENT
;
3878 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
3881 add_fsevent(FSE_CREATE_FILE
, ctx
,
3889 * nameidone has to happen before we vnode_put(dvp)
3890 * since it may need to release the fs_nodelock on the dvp
3898 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
3904 * Delete a whiteout from the filesystem.
3905 * XXX authorization not implmented for whiteouts
3908 undelete(__unused proc_t p
, struct undelete_args
*uap
, __unused
int32_t *retval
)
3911 struct nameidata nd
;
3912 vfs_context_t ctx
= vfs_context_current();
3915 NDINIT(&nd
, DELETE
, OP_UNLINK
, LOCKPARENT
| DOWHITEOUT
| AUDITVNPATH1
,
3916 UIO_USERSPACE
, uap
->path
, ctx
);
3923 if (vp
== NULLVP
&& (nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
3924 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, DELETE
, ctx
);
3929 * nameidone has to happen before we vnode_put(dvp)
3930 * since it may need to release the fs_nodelock on the dvp
3943 * Delete a name from the filesystem.
3947 unlink1(vfs_context_t ctx
, struct nameidata
*ndp
, int unlink_flags
)
3951 struct componentname
*cnp
;
3956 struct vnode_attr va
;
3960 int has_listeners
= 0;
3961 int truncated_path
=0;
3963 struct vnode_attr
*vap
= NULL
;
3966 /* unlink or delete is allowed on rsrc forks and named streams */
3967 ndp
->ni_cnd
.cn_flags
|= CN_ALLOWRSRCFORK
;
3970 ndp
->ni_cnd
.cn_flags
|= LOCKPARENT
;
3971 ndp
->ni_flag
|= NAMEI_COMPOUNDREMOVE
;
3983 /* With Carbon delete semantics, busy files cannot be deleted */
3984 if (unlink_flags
& VNODE_REMOVE_NODELETEBUSY
) {
3985 flags
|= VNODE_REMOVE_NODELETEBUSY
;
3988 /* If we're told to, then skip any potential future upcalls */
3989 if (unlink_flags
& VNODE_REMOVE_SKIP_NAMESPACE_EVENT
) {
3990 flags
|= VNODE_REMOVE_SKIP_NAMESPACE_EVENT
;
3995 batched
= vnode_compound_remove_available(vp
);
3997 * The root of a mounted filesystem cannot be deleted.
3999 if (vp
->v_flag
& VROOT
) {
4004 error
= vn_authorize_unlink(dvp
, vp
, cnp
, ctx
, NULL
);
4012 if (!vnode_compound_remove_available(dvp
)) {
4013 panic("No vp, but no compound remove?");
4018 need_event
= need_fsevent(FSE_DELETE
, dvp
);
4021 if ((vp
->v_flag
& VISHARDLINK
) == 0) {
4022 /* XXX need to get these data in batched VNOP */
4023 get_fse_info(vp
, &finfo
, ctx
);
4026 error
= vfs_get_notify_attributes(&va
);
4035 has_listeners
= kauth_authorize_fileop_has_listeners();
4036 if (need_event
|| has_listeners
) {
4044 len
= safe_getpath(dvp
, ndp
->ni_cnd
.cn_nameptr
, path
, MAXPATHLEN
, &truncated_path
);
4048 if (ndp
->ni_cnd
.cn_flags
& CN_WANTSRSRCFORK
)
4049 error
= vnode_removenamedstream(dvp
, vp
, XATTR_RESOURCEFORK_NAME
, 0, ctx
);
4053 error
= vn_remove(dvp
, &ndp
->ni_vp
, ndp
, flags
, vap
, ctx
);
4055 if (error
== EKEEPLOOKING
) {
4057 panic("EKEEPLOOKING, but not a filesystem that supports compound VNOPs?");
4060 if ((ndp
->ni_flag
& NAMEI_CONTLOOKUP
) == 0) {
4061 panic("EKEEPLOOKING, but continue flag not set?");
4064 if (vnode_isdir(vp
)) {
4068 goto lookup_continue
;
4073 * Call out to allow 3rd party notification of delete.
4074 * Ignore result of kauth_authorize_fileop call.
4077 if (has_listeners
) {
4078 kauth_authorize_fileop(vfs_context_ucred(ctx
),
4079 KAUTH_FILEOP_DELETE
,
4084 if (vp
->v_flag
& VISHARDLINK
) {
4086 // if a hardlink gets deleted we want to blow away the
4087 // v_parent link because the path that got us to this
4088 // instance of the link is no longer valid. this will
4089 // force the next call to get the path to ask the file
4090 // system instead of just following the v_parent link.
4092 vnode_update_identity(vp
, NULL
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
4097 if (vp
->v_flag
& VISHARDLINK
) {
4098 get_fse_info(vp
, &finfo
, ctx
);
4100 vnode_get_fse_info_from_vap(vp
, &finfo
, vap
);
4102 if (truncated_path
) {
4103 finfo
.mode
|= FSE_TRUNCATED_PATH
;
4105 add_fsevent(FSE_DELETE
, ctx
,
4106 FSE_ARG_STRING
, len
, path
,
4107 FSE_ARG_FINFO
, &finfo
,
4118 /* recycle the deleted rsrc fork vnode to force a reclaim, which
4119 * will cause its shadow file to go away if necessary.
4121 if (vp
&& (vnode_isnamedstream(vp
)) &&
4122 (vp
->v_parent
!= NULLVP
) &&
4123 vnode_isshadow(vp
)) {
4128 * nameidone has to happen before we vnode_put(dvp)
4129 * since it may need to release the fs_nodelock on the dvp
4140 * Delete a name from the filesystem using POSIX semantics.
4143 unlink(__unused proc_t p
, struct unlink_args
*uap
, __unused
int32_t *retval
)
4145 struct nameidata nd
;
4146 vfs_context_t ctx
= vfs_context_current();
4148 NDINIT(&nd
, DELETE
, OP_UNLINK
, AUDITVNPATH1
, UIO_USERSPACE
,
4150 return unlink1(ctx
, &nd
, 0);
4154 * Delete a name from the filesystem using Carbon semantics.
4157 delete(__unused proc_t p
, struct delete_args
*uap
, __unused
int32_t *retval
)
4159 struct nameidata nd
;
4160 vfs_context_t ctx
= vfs_context_current();
4162 NDINIT(&nd
, DELETE
, OP_UNLINK
, AUDITVNPATH1
, UIO_USERSPACE
,
4164 return unlink1(ctx
, &nd
, VNODE_REMOVE_NODELETEBUSY
);
4168 * Reposition read/write file offset.
4171 lseek(proc_t p
, struct lseek_args
*uap
, off_t
*retval
)
4173 struct fileproc
*fp
;
4175 struct vfs_context
*ctx
;
4176 off_t offset
= uap
->offset
, file_size
;
4179 if ( (error
= fp_getfvp(p
,uap
->fd
, &fp
, &vp
)) ) {
4180 if (error
== ENOTSUP
)
4184 if (vnode_isfifo(vp
)) {
4190 ctx
= vfs_context_current();
4192 if (uap
->whence
== L_INCR
&& uap
->offset
== 0)
4193 error
= mac_file_check_get_offset(vfs_context_ucred(ctx
),
4196 error
= mac_file_check_change_offset(vfs_context_ucred(ctx
),
4203 if ( (error
= vnode_getwithref(vp
)) ) {
4208 switch (uap
->whence
) {
4210 offset
+= fp
->f_fglob
->fg_offset
;
4213 if ((error
= vnode_size(vp
, &file_size
, ctx
)) != 0)
4215 offset
+= file_size
;
4223 if (uap
->offset
> 0 && offset
< 0) {
4224 /* Incremented/relative move past max size */
4228 * Allow negative offsets on character devices, per
4229 * POSIX 1003.1-2001. Most likely for writing disk
4232 if (offset
< 0 && vp
->v_type
!= VCHR
) {
4233 /* Decremented/relative move before start */
4237 fp
->f_fglob
->fg_offset
= offset
;
4238 *retval
= fp
->f_fglob
->fg_offset
;
4244 * An lseek can affect whether data is "available to read." Use
4245 * hint of NOTE_NONE so no EVFILT_VNODE events fire
4247 post_event_if_success(vp
, error
, NOTE_NONE
);
4248 (void)vnode_put(vp
);
4255 * Check access permissions.
4257 * Returns: 0 Success
4258 * vnode_authorize:???
4261 access1(vnode_t vp
, vnode_t dvp
, int uflags
, vfs_context_t ctx
)
4263 kauth_action_t action
;
4267 * If just the regular access bits, convert them to something
4268 * that vnode_authorize will understand.
4270 if (!(uflags
& _ACCESS_EXTENDED_MASK
)) {
4273 action
|= KAUTH_VNODE_READ_DATA
; /* aka KAUTH_VNODE_LIST_DIRECTORY */
4274 if (uflags
& W_OK
) {
4275 if (vnode_isdir(vp
)) {
4276 action
|= KAUTH_VNODE_ADD_FILE
|
4277 KAUTH_VNODE_ADD_SUBDIRECTORY
;
4278 /* might want delete rights here too */
4280 action
|= KAUTH_VNODE_WRITE_DATA
;
4283 if (uflags
& X_OK
) {
4284 if (vnode_isdir(vp
)) {
4285 action
|= KAUTH_VNODE_SEARCH
;
4287 action
|= KAUTH_VNODE_EXECUTE
;
4291 /* take advantage of definition of uflags */
4292 action
= uflags
>> 8;
4296 error
= mac_vnode_check_access(ctx
, vp
, uflags
);
4301 /* action == 0 means only check for existence */
4303 error
= vnode_authorize(vp
, dvp
, action
| KAUTH_VNODE_ACCESS
, ctx
);
4314 * access_extended: Check access permissions in bulk.
4316 * Description: uap->entries Pointer to an array of accessx
4317 * descriptor structs, plus one or
4318 * more NULL terminated strings (see
4319 * "Notes" section below).
4320 * uap->size Size of the area pointed to by
4322 * uap->results Pointer to the results array.
4324 * Returns: 0 Success
4325 * ENOMEM Insufficient memory
4326 * EINVAL Invalid arguments
4327 * namei:EFAULT Bad address
4328 * namei:ENAMETOOLONG Filename too long
4329 * namei:ENOENT No such file or directory
4330 * namei:ELOOP Too many levels of symbolic links
4331 * namei:EBADF Bad file descriptor
4332 * namei:ENOTDIR Not a directory
4337 * uap->results Array contents modified
4339 * Notes: The uap->entries are structured as an arbitrary length array
4340 * of accessx descriptors, followed by one or more NULL terminated
4343 * struct accessx_descriptor[0]
4345 * struct accessx_descriptor[n]
4346 * char name_data[0];
4348 * We determine the entry count by walking the buffer containing
4349 * the uap->entries argument descriptor. For each descriptor we
4350 * see, the valid values for the offset ad_name_offset will be
4351 * in the byte range:
4353 * [ uap->entries + sizeof(struct accessx_descriptor) ]
4355 * [ uap->entries + uap->size - 2 ]
4357 * since we must have at least one string, and the string must
4358 * be at least one character plus the NULL terminator in length.
4360 * XXX: Need to support the check-as uid argument
4363 access_extended(__unused proc_t p
, struct access_extended_args
*uap
, __unused
int32_t *retval
)
4365 struct accessx_descriptor
*input
= NULL
;
4366 errno_t
*result
= NULL
;
4369 unsigned int desc_max
, desc_actual
, i
, j
;
4370 struct vfs_context context
;
4371 struct nameidata nd
;
4375 #define ACCESSX_MAX_DESCR_ON_STACK 10
4376 struct accessx_descriptor stack_input
[ACCESSX_MAX_DESCR_ON_STACK
];
4378 context
.vc_ucred
= NULL
;
4381 * Validate parameters; if valid, copy the descriptor array and string
4382 * arguments into local memory. Before proceeding, the following
4383 * conditions must have been met:
4385 * o The total size is not permitted to exceed ACCESSX_MAX_TABLESIZE
4386 * o There must be sufficient room in the request for at least one
4387 * descriptor and a one yte NUL terminated string.
4388 * o The allocation of local storage must not fail.
4390 if (uap
->size
> ACCESSX_MAX_TABLESIZE
)
4392 if (uap
->size
< (sizeof(struct accessx_descriptor
) + 2))
4394 if (uap
->size
<= sizeof (stack_input
)) {
4395 input
= stack_input
;
4397 MALLOC(input
, struct accessx_descriptor
*, uap
->size
, M_TEMP
, M_WAITOK
);
4398 if (input
== NULL
) {
4403 error
= copyin(uap
->entries
, input
, uap
->size
);
4407 AUDIT_ARG(opaque
, input
, uap
->size
);
4410 * Force NUL termination of the copyin buffer to avoid nami() running
4411 * off the end. If the caller passes us bogus data, they may get a
4414 ((char *)input
)[uap
->size
- 1] = 0;
4417 * Access is defined as checking against the process' real identity,
4418 * even if operations are checking the effective identity. This
4419 * requires that we use a local vfs context.
4421 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
4422 context
.vc_thread
= current_thread();
4425 * Find out how many entries we have, so we can allocate the result
4426 * array by walking the list and adjusting the count downward by the
4427 * earliest string offset we see.
4429 desc_max
= (uap
->size
- 2) / sizeof(struct accessx_descriptor
);
4430 desc_actual
= desc_max
;
4431 for (i
= 0; i
< desc_actual
; i
++) {
4433 * Take the offset to the name string for this entry and
4434 * convert to an input array index, which would be one off
4435 * the end of the array if this entry was the lowest-addressed
4438 j
= input
[i
].ad_name_offset
/ sizeof(struct accessx_descriptor
);
4441 * An offset greater than the max allowable offset is an error.
4442 * It is also an error for any valid entry to point
4443 * to a location prior to the end of the current entry, if
4444 * it's not a reference to the string of the previous entry.
4446 if (j
> desc_max
|| (j
!= 0 && j
<= i
)) {
4452 * An offset of 0 means use the previous descriptor's offset;
4453 * this is used to chain multiple requests for the same file
4454 * to avoid multiple lookups.
4457 /* This is not valid for the first entry */
4466 * If the offset of the string for this descriptor is before
4467 * what we believe is the current actual last descriptor,
4468 * then we need to adjust our estimate downward; this permits
4469 * the string table following the last descriptor to be out
4470 * of order relative to the descriptor list.
4472 if (j
< desc_actual
)
4477 * We limit the actual number of descriptors we are willing to process
4478 * to a hard maximum of ACCESSX_MAX_DESCRIPTORS. If the number being
4479 * requested does not exceed this limit,
4481 if (desc_actual
> ACCESSX_MAX_DESCRIPTORS
) {
4485 MALLOC(result
, errno_t
*, desc_actual
* sizeof(errno_t
), M_TEMP
, M_WAITOK
);
4486 if (result
== NULL
) {
4492 * Do the work by iterating over the descriptor entries we know to
4493 * at least appear to contain valid data.
4496 for (i
= 0; i
< desc_actual
; i
++) {
4498 * If the ad_name_offset is 0, then we use the previous
4499 * results to make the check; otherwise, we are looking up
4502 if (input
[i
].ad_name_offset
!= 0) {
4503 /* discard old vnodes */
4514 * Scan forward in the descriptor list to see if we
4515 * need the parent vnode. We will need it if we are
4516 * deleting, since we must have rights to remove
4517 * entries in the parent directory, as well as the
4518 * rights to delete the object itself.
4520 wantdelete
= input
[i
].ad_flags
& _DELETE_OK
;
4521 for (j
= i
+ 1; (j
< desc_actual
) && (input
[j
].ad_name_offset
== 0); j
++)
4522 if (input
[j
].ad_flags
& _DELETE_OK
)
4525 niopts
= FOLLOW
| AUDITVNPATH1
;
4527 /* need parent for vnode_authorize for deletion test */
4529 niopts
|= WANTPARENT
;
4532 NDINIT(&nd
, LOOKUP
, OP_ACCESS
, niopts
, UIO_SYSSPACE
,
4533 CAST_USER_ADDR_T(((const char *)input
) + input
[i
].ad_name_offset
),
4545 * Handle lookup errors.
4555 /* run this access check */
4556 result
[i
] = access1(vp
, dvp
, input
[i
].ad_flags
, &context
);
4559 /* fatal lookup error */
4565 AUDIT_ARG(data
, result
, sizeof(errno_t
), desc_actual
);
4567 /* copy out results */
4568 error
= copyout(result
, uap
->results
, desc_actual
* sizeof(errno_t
));
4571 if (input
&& input
!= stack_input
)
4572 FREE(input
, M_TEMP
);
4574 FREE(result
, M_TEMP
);
4579 if (IS_VALID_CRED(context
.vc_ucred
))
4580 kauth_cred_unref(&context
.vc_ucred
);
4586 * Returns: 0 Success
4587 * namei:EFAULT Bad address
4588 * namei:ENAMETOOLONG Filename too long
4589 * namei:ENOENT No such file or directory
4590 * namei:ELOOP Too many levels of symbolic links
4591 * namei:EBADF Bad file descriptor
4592 * namei:ENOTDIR Not a directory
4597 access(__unused proc_t p
, struct access_args
*uap
, __unused
int32_t *retval
)
4600 struct nameidata nd
;
4602 struct vfs_context context
;
4604 int is_namedstream
= 0;
4608 * Access is defined as checking against the process'
4609 * real identity, even if operations are checking the
4610 * effective identity. So we need to tweak the credential
4613 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
4614 context
.vc_thread
= current_thread();
4616 niopts
= FOLLOW
| AUDITVNPATH1
;
4617 /* need parent for vnode_authorize for deletion test */
4618 if (uap
->flags
& _DELETE_OK
)
4619 niopts
|= WANTPARENT
;
4620 NDINIT(&nd
, LOOKUP
, OP_ACCESS
, niopts
, UIO_USERSPACE
,
4621 uap
->path
, &context
);
4624 /* access(F_OK) calls are allowed for resource forks. */
4625 if (uap
->flags
== F_OK
)
4626 nd
.ni_cnd
.cn_flags
|= CN_ALLOWRSRCFORK
;
4633 /* Grab reference on the shadow stream file vnode to
4634 * force an inactive on release which will mark it
4637 if (vnode_isnamedstream(nd
.ni_vp
) &&
4638 (nd
.ni_vp
->v_parent
!= NULLVP
) &&
4639 vnode_isshadow(nd
.ni_vp
)) {
4641 vnode_ref(nd
.ni_vp
);
4645 error
= access1(nd
.ni_vp
, nd
.ni_dvp
, uap
->flags
, &context
);
4648 if (is_namedstream
) {
4649 vnode_rele(nd
.ni_vp
);
4653 vnode_put(nd
.ni_vp
);
4654 if (uap
->flags
& _DELETE_OK
)
4655 vnode_put(nd
.ni_dvp
);
4659 kauth_cred_unref(&context
.vc_ucred
);
4665 * Returns: 0 Success
4672 stat2(vfs_context_t ctx
, struct nameidata
*ndp
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
, int isstat64
)
4679 struct user64_stat user64_sb
;
4680 struct user32_stat user32_sb
;
4681 struct user64_stat64 user64_sb64
;
4682 struct user32_stat64 user32_sb64
;
4686 kauth_filesec_t fsec
;
4687 size_t xsecurity_bufsize
;
4691 int is_namedstream
= 0;
4692 /* stat calls are allowed for resource forks. */
4693 ndp
->ni_cnd
.cn_flags
|= CN_ALLOWRSRCFORK
;
4698 fsec
= KAUTH_FILESEC_NONE
;
4700 statptr
= (void *)&source
;
4703 /* Grab reference on the shadow stream file vnode to
4704 * force an inactive on release which will mark it
4707 if (vnode_isnamedstream(ndp
->ni_vp
) &&
4708 (ndp
->ni_vp
->v_parent
!= NULLVP
) &&
4709 vnode_isshadow(ndp
->ni_vp
)) {
4711 vnode_ref(ndp
->ni_vp
);
4715 error
= vn_stat(ndp
->ni_vp
, statptr
, (xsecurity
!= USER_ADDR_NULL
? &fsec
: NULL
), isstat64
, ctx
);
4718 if (is_namedstream
) {
4719 vnode_rele(ndp
->ni_vp
);
4722 vnode_put(ndp
->ni_vp
);
4727 /* Zap spare fields */
4728 if (isstat64
!= 0) {
4729 source
.sb64
.st_lspare
= 0;
4730 source
.sb64
.st_qspare
[0] = 0LL;
4731 source
.sb64
.st_qspare
[1] = 0LL;
4732 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
4733 munge_user64_stat64(&source
.sb64
, &dest
.user64_sb64
);
4734 my_size
= sizeof(dest
.user64_sb64
);
4735 sbp
= (caddr_t
)&dest
.user64_sb64
;
4737 munge_user32_stat64(&source
.sb64
, &dest
.user32_sb64
);
4738 my_size
= sizeof(dest
.user32_sb64
);
4739 sbp
= (caddr_t
)&dest
.user32_sb64
;
4742 * Check if we raced (post lookup) against the last unlink of a file.
4744 if ((source
.sb64
.st_nlink
== 0) && S_ISREG(source
.sb64
.st_mode
)) {
4745 source
.sb64
.st_nlink
= 1;
4748 source
.sb
.st_lspare
= 0;
4749 source
.sb
.st_qspare
[0] = 0LL;
4750 source
.sb
.st_qspare
[1] = 0LL;
4751 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
4752 munge_user64_stat(&source
.sb
, &dest
.user64_sb
);
4753 my_size
= sizeof(dest
.user64_sb
);
4754 sbp
= (caddr_t
)&dest
.user64_sb
;
4756 munge_user32_stat(&source
.sb
, &dest
.user32_sb
);
4757 my_size
= sizeof(dest
.user32_sb
);
4758 sbp
= (caddr_t
)&dest
.user32_sb
;
4762 * Check if we raced (post lookup) against the last unlink of a file.
4764 if ((source
.sb
.st_nlink
== 0) && S_ISREG(source
.sb
.st_mode
)) {
4765 source
.sb
.st_nlink
= 1;
4768 if ((error
= copyout(sbp
, ub
, my_size
)) != 0)
4771 /* caller wants extended security information? */
4772 if (xsecurity
!= USER_ADDR_NULL
) {
4774 /* did we get any? */
4775 if (fsec
== KAUTH_FILESEC_NONE
) {
4776 if (susize(xsecurity_size
, 0) != 0) {
4781 /* find the user buffer size */
4782 xsecurity_bufsize
= fusize(xsecurity_size
);
4784 /* copy out the actual data size */
4785 if (susize(xsecurity_size
, KAUTH_FILESEC_COPYSIZE(fsec
)) != 0) {
4790 /* if the caller supplied enough room, copy out to it */
4791 if (xsecurity_bufsize
>= KAUTH_FILESEC_COPYSIZE(fsec
))
4792 error
= copyout(fsec
, xsecurity
, KAUTH_FILESEC_COPYSIZE(fsec
));
4796 if (fsec
!= KAUTH_FILESEC_NONE
)
4797 kauth_filesec_free(fsec
);
4802 * Get file status; this version follows links.
4804 * Returns: 0 Success
4805 * stat2:??? [see stat2() in this file]
4808 stat1(user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
, int isstat64
)
4810 struct nameidata nd
;
4811 vfs_context_t ctx
= vfs_context_current();
4813 NDINIT(&nd
, LOOKUP
, OP_GETATTR
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
4814 UIO_USERSPACE
, path
, ctx
);
4815 return(stat2(ctx
, &nd
, ub
, xsecurity
, xsecurity_size
, isstat64
));
4819 * stat_extended: Get file status; with extended security (ACL).
4821 * Parameters: p (ignored)
4822 * uap User argument descriptor (see below)
4825 * Indirect: uap->path Path of file to get status from
4826 * uap->ub User buffer (holds file status info)
4827 * uap->xsecurity ACL to get (extended security)
4828 * uap->xsecurity_size Size of ACL
4830 * Returns: 0 Success
4835 stat_extended(__unused proc_t p
, struct stat_extended_args
*uap
, __unused
int32_t *retval
)
4837 return (stat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 0));
4841 * Returns: 0 Success
4842 * stat1:??? [see stat1() in this file]
4845 stat(__unused proc_t p
, struct stat_args
*uap
, __unused
int32_t *retval
)
4847 return(stat1(uap
->path
, uap
->ub
, 0, 0, 0));
4851 stat64(__unused proc_t p
, struct stat64_args
*uap
, __unused
int32_t *retval
)
4853 return(stat1(uap
->path
, uap
->ub
, 0, 0, 1));
4857 * stat64_extended: Get file status; can handle large inode numbers; with extended security (ACL).
4859 * Parameters: p (ignored)
4860 * uap User argument descriptor (see below)
4863 * Indirect: uap->path Path of file to get status from
4864 * uap->ub User buffer (holds file status info)
4865 * uap->xsecurity ACL to get (extended security)
4866 * uap->xsecurity_size Size of ACL
4868 * Returns: 0 Success
4873 stat64_extended(__unused proc_t p
, struct stat64_extended_args
*uap
, __unused
int32_t *retval
)
4875 return (stat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 1));
4878 * Get file status; this version does not follow links.
4881 lstat1(user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
, int isstat64
)
4883 struct nameidata nd
;
4884 vfs_context_t ctx
= vfs_context_current();
4886 NDINIT(&nd
, LOOKUP
, OP_GETATTR
, NOTRIGGER
| NOFOLLOW
| AUDITVNPATH1
,
4887 UIO_USERSPACE
, path
, ctx
);
4889 return(stat2(ctx
, &nd
, ub
, xsecurity
, xsecurity_size
, isstat64
));
4893 * lstat_extended: Get file status; does not follow links; with extended security (ACL).
4895 * Parameters: p (ignored)
4896 * uap User argument descriptor (see below)
4899 * Indirect: uap->path Path of file to get status from
4900 * uap->ub User buffer (holds file status info)
4901 * uap->xsecurity ACL to get (extended security)
4902 * uap->xsecurity_size Size of ACL
4904 * Returns: 0 Success
4909 lstat_extended(__unused proc_t p
, struct lstat_extended_args
*uap
, __unused
int32_t *retval
)
4911 return (lstat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 0));
4915 lstat(__unused proc_t p
, struct lstat_args
*uap
, __unused
int32_t *retval
)
4917 return(lstat1(uap
->path
, uap
->ub
, 0, 0, 0));
4921 lstat64(__unused proc_t p
, struct lstat64_args
*uap
, __unused
int32_t *retval
)
4923 return(lstat1(uap
->path
, uap
->ub
, 0, 0, 1));
4927 * lstat64_extended: Get file status; can handle large inode numbers; does not
4928 * follow links; with extended security (ACL).
4930 * Parameters: p (ignored)
4931 * uap User argument descriptor (see below)
4934 * Indirect: uap->path Path of file to get status from
4935 * uap->ub User buffer (holds file status info)
4936 * uap->xsecurity ACL to get (extended security)
4937 * uap->xsecurity_size Size of ACL
4939 * Returns: 0 Success
4944 lstat64_extended(__unused proc_t p
, struct lstat64_extended_args
*uap
, __unused
int32_t *retval
)
4946 return (lstat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 1));
4950 * Get configurable pathname variables.
4952 * Returns: 0 Success
4956 * Notes: Global implementation constants are intended to be
4957 * implemented in this function directly; all other constants
4958 * are per-FS implementation, and therefore must be handled in
4959 * each respective FS, instead.
4961 * XXX We implement some things globally right now that should actually be
4962 * XXX per-FS; we will need to deal with this at some point.
4966 pathconf(__unused proc_t p
, struct pathconf_args
*uap
, int32_t *retval
)
4969 struct nameidata nd
;
4970 vfs_context_t ctx
= vfs_context_current();
4972 NDINIT(&nd
, LOOKUP
, OP_PATHCONF
, FOLLOW
| AUDITVNPATH1
,
4973 UIO_USERSPACE
, uap
->path
, ctx
);
4978 error
= vn_pathconf(nd
.ni_vp
, uap
->name
, retval
, ctx
);
4980 vnode_put(nd
.ni_vp
);
4986 * Return target name of a symbolic link.
4990 readlink(proc_t p
, struct readlink_args
*uap
, int32_t *retval
)
4994 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4996 struct nameidata nd
;
4997 vfs_context_t ctx
= vfs_context_current();
4998 char uio_buf
[ UIO_SIZEOF(1) ];
5000 NDINIT(&nd
, LOOKUP
, OP_READLINK
, NOFOLLOW
| AUDITVNPATH1
,
5001 UIO_USERSPACE
, uap
->path
, ctx
);
5009 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
5010 &uio_buf
[0], sizeof(uio_buf
));
5011 uio_addiov(auio
, uap
->buf
, uap
->count
);
5012 if (vp
->v_type
!= VLNK
)
5016 error
= mac_vnode_check_readlink(ctx
,
5020 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, ctx
);
5022 error
= VNOP_READLINK(vp
, auio
, ctx
);
5026 /* Safe: uio_resid() is bounded above by "count", and "count" is an int */
5027 *retval
= uap
->count
- (int)uio_resid(auio
);
5032 * Change file flags.
5035 chflags1(vnode_t vp
, int flags
, vfs_context_t ctx
)
5037 struct vnode_attr va
;
5038 kauth_action_t action
;
5042 VATTR_SET(&va
, va_flags
, flags
);
5045 error
= mac_vnode_check_setflags(ctx
, vp
, flags
);
5050 /* request authorisation, disregard immutability */
5051 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
5054 * Request that the auth layer disregard those file flags it's allowed to when
5055 * authorizing this operation; we need to do this in order to be able to
5056 * clear immutable flags.
5058 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
| KAUTH_VNODE_NOIMMUTABLE
, ctx
)) != 0))
5060 error
= vnode_setattr(vp
, &va
, ctx
);
5062 if ((error
== 0) && !VATTR_IS_SUPPORTED(&va
, va_flags
)) {
5071 * Change flags of a file given a path name.
5075 chflags(__unused proc_t p
, struct chflags_args
*uap
, __unused
int32_t *retval
)
5078 vfs_context_t ctx
= vfs_context_current();
5080 struct nameidata nd
;
5082 AUDIT_ARG(fflags
, uap
->flags
);
5083 NDINIT(&nd
, LOOKUP
, OP_SETATTR
, FOLLOW
| AUDITVNPATH1
,
5084 UIO_USERSPACE
, uap
->path
, ctx
);
5091 error
= chflags1(vp
, uap
->flags
, ctx
);
5097 * Change flags of a file given a file descriptor.
5101 fchflags(__unused proc_t p
, struct fchflags_args
*uap
, __unused
int32_t *retval
)
5106 AUDIT_ARG(fd
, uap
->fd
);
5107 AUDIT_ARG(fflags
, uap
->flags
);
5108 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
5111 if ((error
= vnode_getwithref(vp
))) {
5116 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
5118 error
= chflags1(vp
, uap
->flags
, vfs_context_current());
5125 * Change security information on a filesystem object.
5127 * Returns: 0 Success
5128 * EPERM Operation not permitted
5129 * vnode_authattr:??? [anything vnode_authattr can return]
5130 * vnode_authorize:??? [anything vnode_authorize can return]
5131 * vnode_setattr:??? [anything vnode_setattr can return]
5133 * Notes: If vnode_authattr or vnode_authorize return EACCES, it will be
5134 * translated to EPERM before being returned.
5137 chmod2(vfs_context_t ctx
, vnode_t vp
, struct vnode_attr
*vap
)
5139 kauth_action_t action
;
5142 AUDIT_ARG(mode
, vap
->va_mode
);
5143 /* XXX audit new args */
5146 /* chmod calls are not allowed for resource forks. */
5147 if (vp
->v_flag
& VISNAMEDSTREAM
) {
5153 if (VATTR_IS_ACTIVE(vap
, va_mode
) &&
5154 (error
= mac_vnode_check_setmode(ctx
, vp
, (mode_t
)vap
->va_mode
)) != 0)
5158 /* make sure that the caller is allowed to set this security information */
5159 if (((error
= vnode_authattr(vp
, vap
, &action
, ctx
)) != 0) ||
5160 ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
5161 if (error
== EACCES
)
5166 error
= vnode_setattr(vp
, vap
, ctx
);
5173 * Change mode of a file given a path name.
5175 * Returns: 0 Success
5176 * namei:??? [anything namei can return]
5177 * chmod2:??? [anything chmod2 can return]
5180 chmod1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
5182 struct nameidata nd
;
5185 NDINIT(&nd
, LOOKUP
, OP_SETATTR
, FOLLOW
| AUDITVNPATH1
,
5186 UIO_USERSPACE
, path
, ctx
);
5187 if ((error
= namei(&nd
)))
5189 error
= chmod2(ctx
, nd
.ni_vp
, vap
);
5190 vnode_put(nd
.ni_vp
);
5196 * chmod_extended: Change the mode of a file given a path name; with extended
5197 * argument list (including extended security (ACL)).
5199 * Parameters: p Process requesting the open
5200 * uap User argument descriptor (see below)
5203 * Indirect: uap->path Path to object (same as 'chmod')
5204 * uap->uid UID to set
5205 * uap->gid GID to set
5206 * uap->mode File mode to set (same as 'chmod')
5207 * uap->xsecurity ACL to set (or delete)
5209 * Returns: 0 Success
5212 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
5214 * XXX: We should enummerate the possible errno values here, and where
5215 * in the code they originated.
5218 chmod_extended(__unused proc_t p
, struct chmod_extended_args
*uap
, __unused
int32_t *retval
)
5221 struct vnode_attr va
;
5222 kauth_filesec_t xsecdst
;
5224 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
5227 if (uap
->mode
!= -1)
5228 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
5229 if (uap
->uid
!= KAUTH_UID_NONE
)
5230 VATTR_SET(&va
, va_uid
, uap
->uid
);
5231 if (uap
->gid
!= KAUTH_GID_NONE
)
5232 VATTR_SET(&va
, va_gid
, uap
->gid
);
5235 switch(uap
->xsecurity
) {
5236 /* explicit remove request */
5237 case CAST_USER_ADDR_T((void *)1): /* _FILESEC_REMOVE_ACL */
5238 VATTR_SET(&va
, va_acl
, NULL
);
5241 case USER_ADDR_NULL
:
5244 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
5246 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
5247 KAUTH_DEBUG("CHMOD - setting ACL with %d entries", va
.va_acl
->acl_entrycount
);
5250 error
= chmod1(vfs_context_current(), uap
->path
, &va
);
5252 if (xsecdst
!= NULL
)
5253 kauth_filesec_free(xsecdst
);
5258 * Returns: 0 Success
5259 * chmod1:??? [anything chmod1 can return]
5262 chmod(__unused proc_t p
, struct chmod_args
*uap
, __unused
int32_t *retval
)
5264 struct vnode_attr va
;
5267 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
5269 return(chmod1(vfs_context_current(), uap
->path
, &va
));
5273 * Change mode of a file given a file descriptor.
5276 fchmod1(__unused proc_t p
, int fd
, struct vnode_attr
*vap
)
5283 if ((error
= file_vnode(fd
, &vp
)) != 0)
5285 if ((error
= vnode_getwithref(vp
)) != 0) {
5289 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
5291 error
= chmod2(vfs_context_current(), vp
, vap
);
5292 (void)vnode_put(vp
);
5299 * fchmod_extended: Change mode of a file given a file descriptor; with
5300 * extended argument list (including extended security (ACL)).
5302 * Parameters: p Process requesting to change file mode
5303 * uap User argument descriptor (see below)
5306 * Indirect: uap->mode File mode to set (same as 'chmod')
5307 * uap->uid UID to set
5308 * uap->gid GID to set
5309 * uap->xsecurity ACL to set (or delete)
5310 * uap->fd File descriptor of file to change mode
5312 * Returns: 0 Success
5317 fchmod_extended(proc_t p
, struct fchmod_extended_args
*uap
, __unused
int32_t *retval
)
5320 struct vnode_attr va
;
5321 kauth_filesec_t xsecdst
;
5323 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
5326 if (uap
->mode
!= -1)
5327 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
5328 if (uap
->uid
!= KAUTH_UID_NONE
)
5329 VATTR_SET(&va
, va_uid
, uap
->uid
);
5330 if (uap
->gid
!= KAUTH_GID_NONE
)
5331 VATTR_SET(&va
, va_gid
, uap
->gid
);
5334 switch(uap
->xsecurity
) {
5335 case USER_ADDR_NULL
:
5336 VATTR_SET(&va
, va_acl
, NULL
);
5338 case CAST_USER_ADDR_T(-1):
5341 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
5343 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
5346 error
= fchmod1(p
, uap
->fd
, &va
);
5349 switch(uap
->xsecurity
) {
5350 case USER_ADDR_NULL
:
5351 case CAST_USER_ADDR_T(-1):
5354 if (xsecdst
!= NULL
)
5355 kauth_filesec_free(xsecdst
);
5361 fchmod(proc_t p
, struct fchmod_args
*uap
, __unused
int32_t *retval
)
5363 struct vnode_attr va
;
5366 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
5368 return(fchmod1(p
, uap
->fd
, &va
));
5373 * Set ownership given a path name.
5377 chown1(vfs_context_t ctx
, struct chown_args
*uap
, __unused
int32_t *retval
, int follow
)
5380 struct vnode_attr va
;
5382 struct nameidata nd
;
5383 kauth_action_t action
;
5385 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
5387 NDINIT(&nd
, LOOKUP
, OP_SETATTR
,
5388 (follow
? FOLLOW
: 0) | NOTRIGGER
| AUDITVNPATH1
,
5389 UIO_USERSPACE
, uap
->path
, ctx
);
5398 if (uap
->uid
!= VNOVAL
)
5399 VATTR_SET(&va
, va_uid
, uap
->uid
);
5400 if (uap
->gid
!= VNOVAL
)
5401 VATTR_SET(&va
, va_gid
, uap
->gid
);
5404 error
= mac_vnode_check_setowner(ctx
, vp
, uap
->uid
, uap
->gid
);
5409 /* preflight and authorize attribute changes */
5410 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
5412 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
5414 error
= vnode_setattr(vp
, &va
, ctx
);
5418 * EACCES is only allowed from namei(); permissions failure should
5419 * return EPERM, so we need to translate the error code.
5421 if (error
== EACCES
)
5429 chown(__unused proc_t p
, struct chown_args
*uap
, int32_t *retval
)
5431 return chown1(vfs_context_current(), uap
, retval
, 1);
5435 lchown(__unused proc_t p
, struct lchown_args
*uap
, int32_t *retval
)
5437 /* Argument list identical, but machine generated; cast for chown1() */
5438 return chown1(vfs_context_current(), (struct chown_args
*)uap
, retval
, 0);
5442 * Set ownership given a file descriptor.
5446 fchown(__unused proc_t p
, struct fchown_args
*uap
, __unused
int32_t *retval
)
5448 struct vnode_attr va
;
5449 vfs_context_t ctx
= vfs_context_current();
5452 kauth_action_t action
;
5454 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
5455 AUDIT_ARG(fd
, uap
->fd
);
5457 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
5460 if ( (error
= vnode_getwithref(vp
)) ) {
5464 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
5467 if (uap
->uid
!= VNOVAL
)
5468 VATTR_SET(&va
, va_uid
, uap
->uid
);
5469 if (uap
->gid
!= VNOVAL
)
5470 VATTR_SET(&va
, va_gid
, uap
->gid
);
5473 /* chown calls are not allowed for resource forks. */
5474 if (vp
->v_flag
& VISNAMEDSTREAM
) {
5481 error
= mac_vnode_check_setowner(ctx
, vp
, uap
->uid
, uap
->gid
);
5486 /* preflight and authorize attribute changes */
5487 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
5489 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
5490 if (error
== EACCES
)
5494 error
= vnode_setattr(vp
, &va
, ctx
);
5497 (void)vnode_put(vp
);
5503 getutimes(user_addr_t usrtvp
, struct timespec
*tsp
)
5507 if (usrtvp
== USER_ADDR_NULL
) {
5508 struct timeval old_tv
;
5509 /* XXX Y2038 bug because of microtime argument */
5511 TIMEVAL_TO_TIMESPEC(&old_tv
, &tsp
[0]);
5514 if (IS_64BIT_PROCESS(current_proc())) {
5515 struct user64_timeval tv
[2];
5516 error
= copyin(usrtvp
, (void *)tv
, sizeof(tv
));
5519 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
5520 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
5522 struct user32_timeval tv
[2];
5523 error
= copyin(usrtvp
, (void *)tv
, sizeof(tv
));
5526 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
5527 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
5534 setutimes(vfs_context_t ctx
, vnode_t vp
, const struct timespec
*ts
,
5538 struct vnode_attr va
;
5539 kauth_action_t action
;
5541 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
5544 VATTR_SET(&va
, va_access_time
, ts
[0]);
5545 VATTR_SET(&va
, va_modify_time
, ts
[1]);
5547 va
.va_vaflags
|= VA_UTIMES_NULL
;
5550 /* utimes calls are not allowed for resource forks. */
5551 if (vp
->v_flag
& VISNAMEDSTREAM
) {
5558 error
= mac_vnode_check_setutimes(ctx
, vp
, ts
[0], ts
[1]);
5562 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0) {
5563 if (!nullflag
&& error
== EACCES
)
5568 /* since we may not need to auth anything, check here */
5569 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
5570 if (!nullflag
&& error
== EACCES
)
5574 error
= vnode_setattr(vp
, &va
, ctx
);
5581 * Set the access and modification times of a file.
5585 utimes(__unused proc_t p
, struct utimes_args
*uap
, __unused
int32_t *retval
)
5587 struct timespec ts
[2];
5590 struct nameidata nd
;
5591 vfs_context_t ctx
= vfs_context_current();
5594 * AUDIT: Needed to change the order of operations to do the
5595 * name lookup first because auditing wants the path.
5597 NDINIT(&nd
, LOOKUP
, OP_SETATTR
, FOLLOW
| AUDITVNPATH1
,
5598 UIO_USERSPACE
, uap
->path
, ctx
);
5605 * Fetch the user-supplied time. If usrtvp is USER_ADDR_NULL, we fetch
5606 * the current time instead.
5609 if ((error
= getutimes(usrtvp
, ts
)) != 0)
5612 error
= setutimes(ctx
, nd
.ni_vp
, ts
, usrtvp
== USER_ADDR_NULL
);
5615 vnode_put(nd
.ni_vp
);
5620 * Set the access and modification times of a file.
5624 futimes(__unused proc_t p
, struct futimes_args
*uap
, __unused
int32_t *retval
)
5626 struct timespec ts
[2];
5631 AUDIT_ARG(fd
, uap
->fd
);
5633 if ((error
= getutimes(usrtvp
, ts
)) != 0)
5635 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
5637 if((error
= vnode_getwithref(vp
))) {
5642 error
= setutimes(vfs_context_current(), vp
, ts
, usrtvp
== 0);
5649 * Truncate a file given its path name.
5653 truncate(__unused proc_t p
, struct truncate_args
*uap
, __unused
int32_t *retval
)
5656 struct vnode_attr va
;
5657 vfs_context_t ctx
= vfs_context_current();
5659 struct nameidata nd
;
5660 kauth_action_t action
;
5662 if (uap
->length
< 0)
5664 NDINIT(&nd
, LOOKUP
, OP_TRUNCATE
, FOLLOW
| AUDITVNPATH1
,
5665 UIO_USERSPACE
, uap
->path
, ctx
);
5666 if ((error
= namei(&nd
)))
5673 VATTR_SET(&va
, va_data_size
, uap
->length
);
5676 error
= mac_vnode_check_truncate(ctx
, NOCRED
, vp
);
5681 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
5683 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
5685 error
= vnode_setattr(vp
, &va
, ctx
);
5692 * Truncate a file given a file descriptor.
5696 ftruncate(proc_t p
, struct ftruncate_args
*uap
, int32_t *retval
)
5698 vfs_context_t ctx
= vfs_context_current();
5699 struct vnode_attr va
;
5701 struct fileproc
*fp
;
5705 AUDIT_ARG(fd
, uap
->fd
);
5706 if (uap
->length
< 0)
5709 if ( (error
= fp_lookup(p
,fd
,&fp
,0)) ) {
5713 if (fp
->f_fglob
->fg_type
== DTYPE_PSXSHM
) {
5714 error
= pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
);
5717 if (fp
->f_fglob
->fg_type
!= DTYPE_VNODE
) {
5722 vp
= (vnode_t
)fp
->f_fglob
->fg_data
;
5724 if ((fp
->f_fglob
->fg_flag
& FWRITE
) == 0) {
5725 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
5730 if ((error
= vnode_getwithref(vp
)) != 0) {
5734 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
5737 error
= mac_vnode_check_truncate(ctx
,
5738 fp
->f_fglob
->fg_cred
, vp
);
5740 (void)vnode_put(vp
);
5745 VATTR_SET(&va
, va_data_size
, uap
->length
);
5746 error
= vnode_setattr(vp
, &va
, ctx
);
5747 (void)vnode_put(vp
);
5755 * Sync an open file with synchronized I/O _file_ integrity completion
5759 fsync(proc_t p
, struct fsync_args
*uap
, __unused
int32_t *retval
)
5761 __pthread_testcancel(1);
5762 return(fsync_common(p
, uap
, MNT_WAIT
));
5767 * Sync an open file with synchronized I/O _file_ integrity completion
5769 * Notes: This is a legacy support function that does not test for
5770 * thread cancellation points.
5774 fsync_nocancel(proc_t p
, struct fsync_nocancel_args
*uap
, __unused
int32_t *retval
)
5776 return(fsync_common(p
, (struct fsync_args
*)uap
, MNT_WAIT
));
5781 * Sync an open file with synchronized I/O _data_ integrity completion
5785 fdatasync(proc_t p
, struct fdatasync_args
*uap
, __unused
int32_t *retval
)
5787 __pthread_testcancel(1);
5788 return(fsync_common(p
, (struct fsync_args
*)uap
, MNT_DWAIT
));
5795 * Common fsync code to support both synchronized I/O file integrity completion
5796 * (normal fsync) and synchronized I/O data integrity completion (fdatasync).
5798 * If 'flags' is MNT_DWAIT, the caller is requesting data integrity, which
5799 * will only guarantee that the file data contents are retrievable. If
5800 * 'flags' is MNT_WAIT, the caller is rewuesting file integrity, which also
5801 * includes additional metadata unnecessary for retrieving the file data
5802 * contents, such as atime, mtime, ctime, etc., also be committed to stable
5805 * Parameters: p The process
5806 * uap->fd The descriptor to synchronize
5807 * flags The data integrity flags
5809 * Returns: int Success
5810 * fp_getfvp:EBADF Bad file descriptor
5811 * fp_getfvp:ENOTSUP fd does not refer to a vnode
5812 * VNOP_FSYNC:??? unspecified
5814 * Notes: We use struct fsync_args because it is a short name, and all
5815 * caller argument structures are otherwise identical.
5818 fsync_common(proc_t p
, struct fsync_args
*uap
, int flags
)
5821 struct fileproc
*fp
;
5822 vfs_context_t ctx
= vfs_context_current();
5825 AUDIT_ARG(fd
, uap
->fd
);
5827 if ( (error
= fp_getfvp(p
, uap
->fd
, &fp
, &vp
)) )
5829 if ( (error
= vnode_getwithref(vp
)) ) {
5834 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
5836 error
= VNOP_FSYNC(vp
, flags
, ctx
);
5839 /* Sync resource fork shadow file if necessary. */
5841 (vp
->v_flag
& VISNAMEDSTREAM
) &&
5842 (vp
->v_parent
!= NULLVP
) &&
5843 vnode_isshadow(vp
) &&
5844 (fp
->f_flags
& FP_WRITTEN
)) {
5845 (void) vnode_flushnamedstream(vp
->v_parent
, vp
, ctx
);
5849 (void)vnode_put(vp
);
5855 * Duplicate files. Source must be a file, target must be a file or
5858 * XXX Copyfile authorisation checking is woefully inadequate, and will not
5859 * perform inheritance correctly.
5863 copyfile(__unused proc_t p
, struct copyfile_args
*uap
, __unused
int32_t *retval
)
5865 vnode_t tvp
, fvp
, tdvp
, sdvp
;
5866 struct nameidata fromnd
, tond
;
5868 vfs_context_t ctx
= vfs_context_current();
5870 /* Check that the flags are valid. */
5872 if (uap
->flags
& ~CPF_MASK
) {
5876 NDINIT(&fromnd
, LOOKUP
, OP_COPYFILE
, SAVESTART
| AUDITVNPATH1
,
5877 UIO_USERSPACE
, uap
->from
, ctx
);
5878 if ((error
= namei(&fromnd
)))
5882 NDINIT(&tond
, CREATE
, OP_LINK
,
5883 LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
| AUDITVNPATH2
| CN_NBMOUNTLOOK
,
5884 UIO_USERSPACE
, uap
->to
, ctx
);
5885 if ((error
= namei(&tond
))) {
5892 if (!(uap
->flags
& CPF_OVERWRITE
)) {
5897 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
5902 if ((error
= vnode_authorize(tdvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
5908 * If source is the same as the destination (that is the
5909 * same inode number) then there is nothing to do.
5910 * (fixed to have POSIX semantics - CSM 3/2/98)
5915 error
= VNOP_COPYFILE(fvp
, tdvp
, tvp
, &tond
.ni_cnd
, uap
->mode
, uap
->flags
, ctx
);
5917 sdvp
= tond
.ni_startdir
;
5919 * nameidone has to happen before we vnode_put(tdvp)
5920 * since it may need to release the fs_nodelock on the tdvp
5931 if (fromnd
.ni_startdir
)
5932 vnode_put(fromnd
.ni_startdir
);
5942 * Rename files. Source and destination must either both be directories,
5943 * or both not be directories. If target is a directory, it must be empty.
5947 rename(__unused proc_t p
, struct rename_args
*uap
, __unused
int32_t *retval
)
5951 struct nameidata
*fromnd
, *tond
;
5952 vfs_context_t ctx
= vfs_context_current();
5957 const char *oname
= NULL
;
5958 char *from_name
= NULL
, *to_name
= NULL
;
5959 int from_len
=0, to_len
=0;
5960 int holding_mntlock
;
5961 mount_t locked_mp
= NULL
;
5962 vnode_t oparent
= NULLVP
;
5964 fse_info from_finfo
, to_finfo
;
5966 int from_truncated
=0, to_truncated
;
5968 struct vnode_attr
*fvap
, *tvap
;
5970 /* carving out a chunk for structs that are too big to be on stack. */
5972 struct nameidata from_node
, to_node
;
5973 struct vnode_attr fv_attr
, tv_attr
;
5975 MALLOC(__rename_data
, void *, sizeof(*__rename_data
), M_TEMP
, M_WAITOK
);
5976 fromnd
= &__rename_data
->from_node
;
5977 tond
= &__rename_data
->to_node
;
5979 holding_mntlock
= 0;
5987 NDINIT(fromnd
, DELETE
, OP_UNLINK
, WANTPARENT
| AUDITVNPATH1
,
5988 UIO_USERSPACE
, uap
->from
, ctx
);
5989 fromnd
->ni_flag
= NAMEI_COMPOUNDRENAME
;
5991 NDINIT(tond
, RENAME
, OP_RENAME
, WANTPARENT
| AUDITVNPATH2
| CN_NBMOUNTLOOK
,
5992 UIO_USERSPACE
, uap
->to
, ctx
);
5993 tond
->ni_flag
= NAMEI_COMPOUNDRENAME
;
5996 if ((fromnd
->ni_flag
& NAMEI_CONTLOOKUP
) != 0 || !continuing
) {
5997 if ( (error
= namei(fromnd
)) )
5999 fdvp
= fromnd
->ni_dvp
;
6000 fvp
= fromnd
->ni_vp
;
6002 if (fvp
&& fvp
->v_type
== VDIR
)
6003 tond
->ni_cnd
.cn_flags
|= WILLBEDIR
;
6006 if ((tond
->ni_flag
& NAMEI_CONTLOOKUP
) != 0 || !continuing
) {
6007 if ( (error
= namei(tond
)) ) {
6009 * Translate error code for rename("dir1", "dir2/.").
6011 if (error
== EISDIR
&& fvp
->v_type
== VDIR
)
6015 tdvp
= tond
->ni_dvp
;
6019 batched
= vnode_compound_rename_available(fdvp
);
6022 * Claim: this check will never reject a valid rename.
6023 * For success, either fvp must be on the same mount as tdvp, or fvp must sit atop a vnode on the same mount as tdvp.
6024 * Suppose fdvp and tdvp are not on the same mount.
6025 * If fvp is on the same mount as tdvp, then fvp is not on the same mount as fdvp, so fvp is the root of its filesystem. If fvp is the root,
6026 * then you can't move it to within another dir on the same mountpoint.
6027 * If fvp sits atop a vnode on the same mount as fdvp, then that vnode must be part of the same mount as fdvp, which is a contradiction.
6029 * If this check passes, then we are safe to pass these vnodes to the same FS.
6031 if (fdvp
->v_mount
!= tdvp
->v_mount
) {
6035 goto skipped_lookup
;
6039 error
= vn_authorize_rename(fdvp
, fvp
, &fromnd
->ni_cnd
, tdvp
, tvp
, &tond
->ni_cnd
, ctx
, NULL
);
6041 if (error
== ENOENT
) {
6043 * We encountered a race where after doing the namei, tvp stops
6044 * being valid. If so, simply re-drive the rename call from the
6054 * If the source and destination are the same (i.e. they're
6055 * links to the same vnode) and the target file system is
6056 * case sensitive, then there is nothing to do.
6058 * XXX Come back to this.
6064 * Note: if _PC_CASE_SENSITIVE selector isn't supported,
6065 * then assume that this file system is case sensitive.
6067 if (VNOP_PATHCONF(fvp
, _PC_CASE_SENSITIVE
, &pathconf_val
, ctx
) != 0 ||
6068 pathconf_val
!= 0) {
6074 * Allow the renaming of mount points.
6075 * - target must not exist
6076 * - target must reside in the same directory as source
6077 * - union mounts cannot be renamed
6078 * - "/" cannot be renamed
6080 * XXX Handle this in VFS after a continued lookup (if we missed
6081 * in the cache to start off)
6083 if ((fvp
->v_flag
& VROOT
) &&
6084 (fvp
->v_type
== VDIR
) &&
6086 (fvp
->v_mountedhere
== NULL
) &&
6088 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
6089 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
6092 /* switch fvp to the covered vnode */
6093 coveredvp
= fvp
->v_mount
->mnt_vnodecovered
;
6094 if ( (vnode_getwithref(coveredvp
)) ) {
6104 * Check for cross-device rename.
6106 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
6107 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
6113 * If source is the same as the destination (that is the
6114 * same inode number) then there is nothing to do...
6115 * EXCEPT if the underlying file system supports case
6116 * insensitivity and is case preserving. In this case
6117 * the file system needs to handle the special case of
6118 * getting the same vnode as target (fvp) and source (tvp).
6120 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
6121 * and _PC_CASE_PRESERVING can have this exception, and they need to
6122 * handle the special case of getting the same vnode as target and
6123 * source. NOTE: Then the target is unlocked going into vnop_rename,
6124 * so not to cause locking problems. There is a single reference on tvp.
6126 * NOTE - that fvp == tvp also occurs if they are hard linked and
6127 * that correct behaviour then is just to return success without doing
6130 * XXX filesystem should take care of this itself, perhaps...
6132 if (fvp
== tvp
&& fdvp
== tdvp
) {
6133 if (fromnd
->ni_cnd
.cn_namelen
== tond
->ni_cnd
.cn_namelen
&&
6134 !bcmp(fromnd
->ni_cnd
.cn_nameptr
, tond
->ni_cnd
.cn_nameptr
,
6135 fromnd
->ni_cnd
.cn_namelen
)) {
6140 if (holding_mntlock
&& fvp
->v_mount
!= locked_mp
) {
6142 * we're holding a reference and lock
6143 * on locked_mp, but it no longer matches
6144 * what we want to do... so drop our hold
6146 mount_unlock_renames(locked_mp
);
6147 mount_drop(locked_mp
, 0);
6148 holding_mntlock
= 0;
6150 if (tdvp
!= fdvp
&& fvp
->v_type
== VDIR
) {
6152 * serialize renames that re-shape
6153 * the tree... if holding_mntlock is
6154 * set, then we're ready to go...
6156 * first need to drop the iocounts
6157 * we picked up, second take the
6158 * lock to serialize the access,
6159 * then finally start the lookup
6160 * process over with the lock held
6162 if (!holding_mntlock
) {
6164 * need to grab a reference on
6165 * the mount point before we
6166 * drop all the iocounts... once
6167 * the iocounts are gone, the mount
6170 locked_mp
= fvp
->v_mount
;
6171 mount_ref(locked_mp
, 0);
6174 * nameidone has to happen before we vnode_put(tvp)
6175 * since it may need to release the fs_nodelock on the tvp
6184 * nameidone has to happen before we vnode_put(fdvp)
6185 * since it may need to release the fs_nodelock on the fvp
6192 mount_lock_renames(locked_mp
);
6193 holding_mntlock
= 1;
6199 * when we dropped the iocounts to take
6200 * the lock, we allowed the identity of
6201 * the various vnodes to change... if they did,
6202 * we may no longer be dealing with a rename
6203 * that reshapes the tree... once we're holding
6204 * the iocounts, the vnodes can't change type
6205 * so we're free to drop the lock at this point
6208 if (holding_mntlock
) {
6209 mount_unlock_renames(locked_mp
);
6210 mount_drop(locked_mp
, 0);
6211 holding_mntlock
= 0;
6215 // save these off so we can later verify that fvp is the same
6216 oname
= fvp
->v_name
;
6217 oparent
= fvp
->v_parent
;
6221 need_event
= need_fsevent(FSE_RENAME
, fdvp
);
6224 get_fse_info(fvp
, &from_finfo
, ctx
);
6226 error
= vfs_get_notify_attributes(&__rename_data
->fv_attr
);
6231 fvap
= &__rename_data
->fv_attr
;
6235 get_fse_info(tvp
, &to_finfo
, ctx
);
6236 } else if (batched
) {
6237 error
= vfs_get_notify_attributes(&__rename_data
->tv_attr
);
6242 tvap
= &__rename_data
->tv_attr
;
6247 #endif /* CONFIG_FSE */
6249 if (need_event
|| kauth_authorize_fileop_has_listeners()) {
6250 if (from_name
== NULL
) {
6251 GET_PATH(from_name
);
6252 if (from_name
== NULL
) {
6258 from_len
= safe_getpath(fdvp
, fromnd
->ni_cnd
.cn_nameptr
, from_name
, MAXPATHLEN
, &from_truncated
);
6260 if (to_name
== NULL
) {
6262 if (to_name
== NULL
) {
6268 to_len
= safe_getpath(tdvp
, tond
->ni_cnd
.cn_nameptr
, to_name
, MAXPATHLEN
, &to_truncated
);
6271 error
= vn_rename(fdvp
, &fvp
, &fromnd
->ni_cnd
, fvap
,
6272 tdvp
, &tvp
, &tond
->ni_cnd
, tvap
,
6275 if (holding_mntlock
) {
6277 * we can drop our serialization
6280 mount_unlock_renames(locked_mp
);
6281 mount_drop(locked_mp
, 0);
6282 holding_mntlock
= 0;
6285 if (error
== EKEEPLOOKING
) {
6286 if ((fromnd
->ni_flag
& NAMEI_CONTLOOKUP
) == 0) {
6287 if ((tond
->ni_flag
& NAMEI_CONTLOOKUP
) == 0) {
6288 panic("EKEEPLOOKING without NAMEI_CONTLOOKUP on either ndp?");
6292 fromnd
->ni_vp
= fvp
;
6295 goto continue_lookup
;
6299 * We may encounter a race in the VNOP where the destination didn't
6300 * exist when we did the namei, but it does by the time we go and
6301 * try to create the entry. In this case, we should re-drive this rename
6302 * call from the top again. Currently, only HFS bubbles out ERECYCLE,
6303 * but other filesystems susceptible to this race could return it, too.
6305 if (error
== ERECYCLE
) {
6312 /* call out to allow 3rd party notification of rename.
6313 * Ignore result of kauth_authorize_fileop call.
6315 kauth_authorize_fileop(vfs_context_ucred(ctx
),
6316 KAUTH_FILEOP_RENAME
,
6317 (uintptr_t)from_name
, (uintptr_t)to_name
);
6320 if (from_name
!= NULL
&& to_name
!= NULL
) {
6321 if (from_truncated
|| to_truncated
) {
6322 // set it here since only the from_finfo gets reported up to user space
6323 from_finfo
.mode
|= FSE_TRUNCATED_PATH
;
6327 vnode_get_fse_info_from_vap(tvp
, &to_finfo
, tvap
);
6330 vnode_get_fse_info_from_vap(fvp
, &from_finfo
, fvap
);
6334 add_fsevent(FSE_RENAME
, ctx
,
6335 FSE_ARG_STRING
, from_len
, from_name
,
6336 FSE_ARG_FINFO
, &from_finfo
,
6337 FSE_ARG_STRING
, to_len
, to_name
,
6338 FSE_ARG_FINFO
, &to_finfo
,
6341 add_fsevent(FSE_RENAME
, ctx
,
6342 FSE_ARG_STRING
, from_len
, from_name
,
6343 FSE_ARG_FINFO
, &from_finfo
,
6344 FSE_ARG_STRING
, to_len
, to_name
,
6348 #endif /* CONFIG_FSE */
6351 * update filesystem's mount point data
6354 char *cp
, *pathend
, *mpname
;
6360 mp
= fvp
->v_mountedhere
;
6362 if (vfs_busy(mp
, LK_NOWAIT
)) {
6366 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
6368 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
6370 /* find current mount point prefix */
6371 pathend
= &mp
->mnt_vfsstat
.f_mntonname
[0];
6372 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
6376 /* find last component of target name */
6377 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
6381 /* append name to prefix */
6382 maxlen
= MAXPATHLEN
- (pathend
- mp
->mnt_vfsstat
.f_mntonname
);
6383 bzero(pathend
, maxlen
);
6384 strlcpy(pathend
, mpname
, maxlen
);
6386 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
6391 * fix up name & parent pointers. note that we first
6392 * check that fvp has the same name/parent pointers it
6393 * had before the rename call... this is a 'weak' check
6396 * XXX oparent and oname may not be set in the compound vnop case
6398 if (batched
|| (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
)) {
6401 update_flags
= VNODE_UPDATE_NAME
;
6404 update_flags
|= VNODE_UPDATE_PARENT
;
6406 vnode_update_identity(fvp
, tdvp
, tond
->ni_cnd
.cn_nameptr
, tond
->ni_cnd
.cn_namelen
, tond
->ni_cnd
.cn_hash
, update_flags
);
6409 if (to_name
!= NULL
) {
6410 RELEASE_PATH(to_name
);
6413 if (from_name
!= NULL
) {
6414 RELEASE_PATH(from_name
);
6417 if (holding_mntlock
) {
6418 mount_unlock_renames(locked_mp
);
6419 mount_drop(locked_mp
, 0);
6420 holding_mntlock
= 0;
6424 * nameidone has to happen before we vnode_put(tdvp)
6425 * since it may need to release the fs_nodelock on the tdvp
6435 * nameidone has to happen before we vnode_put(fdvp)
6436 * since it may need to release the fs_nodelock on the fdvp
6447 * If things changed after we did the namei, then we will re-drive
6448 * this rename call from the top.
6455 FREE(__rename_data
, M_TEMP
);
6460 * Make a directory file.
6462 * Returns: 0 Success
6465 * vnode_authorize:???
6470 mkdir1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
6474 int update_flags
= 0;
6476 struct nameidata nd
;
6478 AUDIT_ARG(mode
, vap
->va_mode
);
6479 NDINIT(&nd
, CREATE
, OP_MKDIR
, LOCKPARENT
| AUDITVNPATH1
, UIO_USERSPACE
,
6481 nd
.ni_cnd
.cn_flags
|= WILLBEDIR
;
6482 nd
.ni_flag
= NAMEI_COMPOUNDMKDIR
;
6496 batched
= vnode_compound_mkdir_available(dvp
);
6498 VATTR_SET(vap
, va_type
, VDIR
);
6502 * Don't authorize in VFS for compound VNOP.... mkdir -p today assumes that it will
6503 * only get EXISTS or EISDIR for existing path components, and not that it could see
6504 * EACCESS/EPERM--so if we authorize for mkdir on "/" for "mkdir -p /tmp/foo/bar/baz"
6505 * it will fail in a spurious manner. Need to figure out if this is valid behavior.
6507 if ((error
= vn_authorize_mkdir(dvp
, &nd
.ni_cnd
, vap
, ctx
, NULL
)) != 0) {
6508 if (error
== EACCES
|| error
== EPERM
) {
6516 * Try a lookup without "NAMEI_COMPOUNDVNOP" to make sure we return EEXIST
6517 * rather than EACCESS if the target exists.
6519 NDINIT(&nd
, LOOKUP
, OP_MKDIR
, AUDITVNPATH1
, UIO_USERSPACE
,
6521 error2
= namei(&nd
);
6535 * make the directory
6537 if ((error
= vn_create(dvp
, &vp
, &nd
, vap
, 0, 0, NULL
, ctx
)) != 0) {
6538 if (error
== EKEEPLOOKING
) {
6540 goto continue_lookup
;
6546 // Make sure the name & parent pointers are hooked up
6547 if (vp
->v_name
== NULL
)
6548 update_flags
|= VNODE_UPDATE_NAME
;
6549 if (vp
->v_parent
== NULLVP
)
6550 update_flags
|= VNODE_UPDATE_PARENT
;
6553 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
6556 add_fsevent(FSE_CREATE_DIR
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
6561 * nameidone has to happen before we vnode_put(dvp)
6562 * since it may need to release the fs_nodelock on the dvp
6575 * mkdir_extended: Create a directory; with extended security (ACL).
6577 * Parameters: p Process requesting to create the directory
6578 * uap User argument descriptor (see below)
6581 * Indirect: uap->path Path of directory to create
6582 * uap->mode Access permissions to set
6583 * uap->xsecurity ACL to set
6585 * Returns: 0 Success
6590 mkdir_extended(proc_t p
, struct mkdir_extended_args
*uap
, __unused
int32_t *retval
)
6593 kauth_filesec_t xsecdst
;
6594 struct vnode_attr va
;
6596 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
6599 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
6600 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
6604 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
6605 if (xsecdst
!= NULL
)
6606 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
6608 ciferror
= mkdir1(vfs_context_current(), uap
->path
, &va
);
6609 if (xsecdst
!= NULL
)
6610 kauth_filesec_free(xsecdst
);
6615 mkdir(proc_t p
, struct mkdir_args
*uap
, __unused
int32_t *retval
)
6617 struct vnode_attr va
;
6620 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
6622 return(mkdir1(vfs_context_current(), uap
->path
, &va
));
6626 * Remove a directory file.
6630 rmdir(__unused proc_t p
, struct rmdir_args
*uap
, __unused
int32_t *retval
)
6634 struct nameidata nd
;
6637 int has_listeners
= 0;
6640 vfs_context_t ctx
= vfs_context_current();
6642 struct vnode_attr va
;
6643 #endif /* CONFIG_FSE */
6644 struct vnode_attr
*vap
= NULL
;
6650 * This loop exists to restart rmdir in the unlikely case that two
6651 * processes are simultaneously trying to remove the same directory
6652 * containing orphaned appleDouble files.
6655 NDINIT(&nd
, DELETE
, OP_RMDIR
, LOCKPARENT
| AUDITVNPATH1
,
6656 UIO_USERSPACE
, uap
->path
, ctx
);
6657 nd
.ni_flag
= NAMEI_COMPOUNDRMDIR
;
6670 batched
= vnode_compound_rmdir_available(vp
);
6672 if (vp
->v_flag
& VROOT
) {
6674 * The root of a mounted filesystem cannot be deleted.
6681 * Removed a check here; we used to abort if vp's vid
6682 * was not the same as what we'd seen the last time around.
6683 * I do not think that check was valid, because if we retry
6684 * and all dirents are gone, the directory could legitimately
6685 * be recycled but still be present in a situation where we would
6686 * have had permission to delete. Therefore, we won't make
6687 * an effort to preserve that check now that we may not have a
6692 error
= vn_authorize_rmdir(dvp
, vp
, &nd
.ni_cnd
, ctx
, NULL
);
6700 if (!vnode_compound_rmdir_available(dvp
)) {
6701 panic("No error, but no compound rmdir?");
6708 need_event
= need_fsevent(FSE_DELETE
, dvp
);
6711 get_fse_info(vp
, &finfo
, ctx
);
6713 error
= vfs_get_notify_attributes(&va
);
6722 has_listeners
= kauth_authorize_fileop_has_listeners();
6723 if (need_event
|| has_listeners
) {
6732 len
= safe_getpath(dvp
, nd
.ni_cnd
.cn_nameptr
, path
, MAXPATHLEN
, &truncated
);
6735 finfo
.mode
|= FSE_TRUNCATED_PATH
;
6740 error
= vn_rmdir(dvp
, &vp
, &nd
, vap
, ctx
);
6743 /* Couldn't find a vnode */
6747 if (error
== EKEEPLOOKING
) {
6748 goto continue_lookup
;
6752 * Special case to remove orphaned AppleDouble
6753 * files. I don't like putting this in the kernel,
6754 * but carbon does not like putting this in carbon either,
6757 if (error
== ENOTEMPTY
) {
6758 error
= rmdir_remove_orphaned_appleDouble(vp
, ctx
, &restart_flag
);
6759 if (error
== EBUSY
) {
6765 * Assuming everything went well, we will try the RMDIR again
6768 error
= vn_rmdir(dvp
, &vp
, &nd
, vap
, ctx
);
6772 * Call out to allow 3rd party notification of delete.
6773 * Ignore result of kauth_authorize_fileop call.
6776 if (has_listeners
) {
6777 kauth_authorize_fileop(vfs_context_ucred(ctx
),
6778 KAUTH_FILEOP_DELETE
,
6783 if (vp
->v_flag
& VISHARDLINK
) {
6784 // see the comment in unlink1() about why we update
6785 // the parent of a hard link when it is removed
6786 vnode_update_identity(vp
, NULL
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
6792 vnode_get_fse_info_from_vap(vp
, &finfo
, vap
);
6794 add_fsevent(FSE_DELETE
, ctx
,
6795 FSE_ARG_STRING
, len
, path
,
6796 FSE_ARG_FINFO
, &finfo
,
6808 * nameidone has to happen before we vnode_put(dvp)
6809 * since it may need to release the fs_nodelock on the dvp
6817 if (restart_flag
== 0) {
6818 wakeup_one((caddr_t
)vp
);
6821 tsleep(vp
, PVFS
, "rm AD", 1);
6823 } while (restart_flag
!= 0);
6829 /* Get direntry length padded to 8 byte alignment */
6830 #define DIRENT64_LEN(namlen) \
6831 ((sizeof(struct direntry) + (namlen) - (MAXPATHLEN-1) + 7) & ~7)
6834 vnode_readdir64(struct vnode
*vp
, struct uio
*uio
, int flags
, int *eofflag
,
6835 int *numdirent
, vfs_context_t ctxp
)
6837 /* Check if fs natively supports VNODE_READDIR_EXTENDED */
6838 if ((vp
->v_mount
->mnt_vtable
->vfc_vfsflags
& VFC_VFSREADDIR_EXTENDED
) &&
6839 ((vp
->v_mount
->mnt_kern_flag
& MNTK_DENY_READDIREXT
) == 0)) {
6840 return VNOP_READDIR(vp
, uio
, flags
, eofflag
, numdirent
, ctxp
);
6845 struct direntry entry64
;
6851 * Our kernel buffer needs to be smaller since re-packing
6852 * will expand each dirent. The worse case (when the name
6853 * length is 3) corresponds to a struct direntry size of 32
6854 * bytes (8-byte aligned) and a struct dirent size of 12 bytes
6855 * (4-byte aligned). So having a buffer that is 3/8 the size
6856 * will prevent us from reading more than we can pack.
6858 * Since this buffer is wired memory, we will limit the
6859 * buffer size to a maximum of 32K. We would really like to
6860 * use 32K in the MIN(), but we use magic number 87371 to
6861 * prevent uio_resid() * 3 / 8 from overflowing.
6863 bufsize
= 3 * MIN((user_size_t
)uio_resid(uio
), 87371u) / 8;
6864 MALLOC(bufptr
, void *, bufsize
, M_TEMP
, M_WAITOK
);
6865 if (bufptr
== NULL
) {
6869 auio
= uio_create(1, 0, UIO_SYSSPACE
, UIO_READ
);
6870 uio_addiov(auio
, (uintptr_t)bufptr
, bufsize
);
6871 auio
->uio_offset
= uio
->uio_offset
;
6873 error
= VNOP_READDIR(vp
, auio
, 0, eofflag
, numdirent
, ctxp
);
6875 dep
= (struct dirent
*)bufptr
;
6876 bytesread
= bufsize
- uio_resid(auio
);
6879 * Convert all the entries and copy them out to user's buffer.
6881 while (error
== 0 && (char *)dep
< ((char *)bufptr
+ bytesread
)) {
6882 /* Convert a dirent to a dirent64. */
6883 entry64
.d_ino
= dep
->d_ino
;
6884 entry64
.d_seekoff
= 0;
6885 entry64
.d_reclen
= DIRENT64_LEN(dep
->d_namlen
);
6886 entry64
.d_namlen
= dep
->d_namlen
;
6887 entry64
.d_type
= dep
->d_type
;
6888 bcopy(dep
->d_name
, entry64
.d_name
, dep
->d_namlen
+ 1);
6890 /* Move to next entry. */
6891 dep
= (struct dirent
*)((char *)dep
+ dep
->d_reclen
);
6893 /* Copy entry64 to user's buffer. */
6894 error
= uiomove((caddr_t
)&entry64
, entry64
.d_reclen
, uio
);
6897 /* Update the real offset using the offset we got from VNOP_READDIR. */
6899 uio
->uio_offset
= auio
->uio_offset
;
6902 FREE(bufptr
, M_TEMP
);
6908 * Read a block of directory entries in a file system independent format.
6911 getdirentries_common(int fd
, user_addr_t bufp
, user_size_t bufsize
, ssize_t
*bytesread
,
6912 off_t
*offset
, int flags
)
6915 struct vfs_context context
= *vfs_context_current(); /* local copy */
6916 struct fileproc
*fp
;
6918 int spacetype
= proc_is64bit(vfs_context_proc(&context
)) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6920 int error
, eofflag
, numdirent
;
6921 char uio_buf
[ UIO_SIZEOF(1) ];
6923 error
= fp_getfvp(vfs_context_proc(&context
), fd
, &fp
, &vp
);
6927 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
6928 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
6934 error
= mac_file_check_change_offset(vfs_context_ucred(&context
), fp
->f_fglob
);
6938 if ( (error
= vnode_getwithref(vp
)) ) {
6941 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
6944 if (vp
->v_type
!= VDIR
) {
6945 (void)vnode_put(vp
);
6951 error
= mac_vnode_check_readdir(&context
, vp
);
6953 (void)vnode_put(vp
);
6958 loff
= fp
->f_fglob
->fg_offset
;
6959 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
6960 uio_addiov(auio
, bufp
, bufsize
);
6962 if (flags
& VNODE_READDIR_EXTENDED
) {
6963 error
= vnode_readdir64(vp
, auio
, flags
, &eofflag
, &numdirent
, &context
);
6964 fp
->f_fglob
->fg_offset
= uio_offset(auio
);
6966 error
= VNOP_READDIR(vp
, auio
, 0, &eofflag
, &numdirent
, &context
);
6967 fp
->f_fglob
->fg_offset
= uio_offset(auio
);
6970 (void)vnode_put(vp
);
6974 if ((user_ssize_t
)bufsize
== uio_resid(auio
)){
6975 if (union_dircheckp
) {
6976 error
= union_dircheckp(&vp
, fp
, &context
);
6983 if ((vp
->v_flag
& VROOT
) && (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
6984 struct vnode
*tvp
= vp
;
6985 vp
= vp
->v_mount
->mnt_vnodecovered
;
6986 vnode_getwithref(vp
);
6988 fp
->f_fglob
->fg_data
= (caddr_t
) vp
;
6989 fp
->f_fglob
->fg_offset
= 0;
7001 *bytesread
= bufsize
- uio_resid(auio
);
7009 getdirentries(__unused
struct proc
*p
, struct getdirentries_args
*uap
, int32_t *retval
)
7015 AUDIT_ARG(fd
, uap
->fd
);
7016 error
= getdirentries_common(uap
->fd
, uap
->buf
, uap
->count
, &bytesread
, &offset
, 0);
7019 if (proc_is64bit(p
)) {
7020 user64_long_t base
= (user64_long_t
)offset
;
7021 error
= copyout((caddr_t
)&base
, uap
->basep
, sizeof(user64_long_t
));
7023 user32_long_t base
= (user32_long_t
)offset
;
7024 error
= copyout((caddr_t
)&base
, uap
->basep
, sizeof(user32_long_t
));
7026 *retval
= bytesread
;
7032 getdirentries64(__unused
struct proc
*p
, struct getdirentries64_args
*uap
, user_ssize_t
*retval
)
7038 AUDIT_ARG(fd
, uap
->fd
);
7039 error
= getdirentries_common(uap
->fd
, uap
->buf
, uap
->bufsize
, &bytesread
, &offset
, VNODE_READDIR_EXTENDED
);
7042 *retval
= bytesread
;
7043 error
= copyout((caddr_t
)&offset
, uap
->position
, sizeof(off_t
));
7050 * Set the mode mask for creation of filesystem nodes.
7051 * XXX implement xsecurity
7053 #define UMASK_NOXSECURITY (void *)1 /* leave existing xsecurity alone */
7055 umask1(proc_t p
, int newmask
, __unused kauth_filesec_t fsec
, int32_t *retval
)
7057 struct filedesc
*fdp
;
7059 AUDIT_ARG(mask
, newmask
);
7062 *retval
= fdp
->fd_cmask
;
7063 fdp
->fd_cmask
= newmask
& ALLPERMS
;
7069 * umask_extended: Set the mode mask for creation of filesystem nodes; with extended security (ACL).
7071 * Parameters: p Process requesting to set the umask
7072 * uap User argument descriptor (see below)
7073 * retval umask of the process (parameter p)
7075 * Indirect: uap->newmask umask to set
7076 * uap->xsecurity ACL to set
7078 * Returns: 0 Success
7083 umask_extended(proc_t p
, struct umask_extended_args
*uap
, int32_t *retval
)
7086 kauth_filesec_t xsecdst
;
7088 xsecdst
= KAUTH_FILESEC_NONE
;
7089 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
7090 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
7093 xsecdst
= KAUTH_FILESEC_NONE
;
7096 ciferror
= umask1(p
, uap
->newmask
, xsecdst
, retval
);
7098 if (xsecdst
!= KAUTH_FILESEC_NONE
)
7099 kauth_filesec_free(xsecdst
);
7104 umask(proc_t p
, struct umask_args
*uap
, int32_t *retval
)
7106 return(umask1(p
, uap
->newmask
, UMASK_NOXSECURITY
, retval
));
7110 * Void all references to file by ripping underlying filesystem
7115 revoke(proc_t p
, struct revoke_args
*uap
, __unused
int32_t *retval
)
7118 struct vnode_attr va
;
7119 vfs_context_t ctx
= vfs_context_current();
7121 struct nameidata nd
;
7123 NDINIT(&nd
, LOOKUP
, OP_REVOKE
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
,
7132 if (!(vnode_ischr(vp
) || vnode_isblk(vp
))) {
7137 if (vnode_isblk(vp
) && vnode_ismountedon(vp
)) {
7143 error
= mac_vnode_check_revoke(ctx
, vp
);
7149 VATTR_WANTED(&va
, va_uid
);
7150 if ((error
= vnode_getattr(vp
, &va
, ctx
)))
7152 if (kauth_cred_getuid(vfs_context_ucred(ctx
)) != va
.va_uid
&&
7153 (error
= suser(vfs_context_ucred(ctx
), &p
->p_acflag
)))
7155 if (vp
->v_usecount
> 0 || (vnode_isaliased(vp
)))
7156 VNOP_REVOKE(vp
, REVOKEALL
, ctx
);
7164 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
7165 * The following system calls are designed to support features
7166 * which are specific to the HFS & HFS Plus volume formats
7171 * Obtain attribute information on objects in a directory while enumerating
7172 * the directory. This call does not yet support union mounted directories.
7174 * 1.union mounted directories.
7179 getdirentriesattr (proc_t p
, struct getdirentriesattr_args
*uap
, int32_t *retval
)
7182 struct fileproc
*fp
;
7184 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
7189 struct attrlist attributelist
;
7190 vfs_context_t ctx
= vfs_context_current();
7192 char uio_buf
[ UIO_SIZEOF(1) ];
7193 kauth_action_t action
;
7197 /* Get the attributes into kernel space */
7198 if ((error
= copyin(uap
->alist
, (caddr_t
)&attributelist
, sizeof(attributelist
)))) {
7201 if ((error
= copyin(uap
->count
, (caddr_t
)&count
, sizeof(count
)))) {
7204 if ( (error
= fp_getfvp(p
, fd
, &fp
, &vp
)) ) {
7207 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
7208 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
7215 error
= mac_file_check_change_offset(vfs_context_ucred(ctx
),
7222 if ( (error
= vnode_getwithref(vp
)) )
7225 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
7227 if (vp
->v_type
!= VDIR
) {
7228 (void)vnode_put(vp
);
7234 error
= mac_vnode_check_readdir(ctx
, vp
);
7236 (void)vnode_put(vp
);
7241 /* set up the uio structure which will contain the users return buffer */
7242 loff
= fp
->f_fglob
->fg_offset
;
7243 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
7244 &uio_buf
[0], sizeof(uio_buf
));
7245 uio_addiov(auio
, uap
->buffer
, uap
->buffersize
);
7248 * If the only item requested is file names, we can let that past with
7249 * just LIST_DIRECTORY. If they want any other attributes, that means
7250 * they need SEARCH as well.
7252 action
= KAUTH_VNODE_LIST_DIRECTORY
;
7253 if ((attributelist
.commonattr
& ~ATTR_CMN_NAME
) ||
7254 attributelist
.fileattr
|| attributelist
.dirattr
)
7255 action
|= KAUTH_VNODE_SEARCH
;
7257 if ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) == 0) {
7259 /* Believe it or not, uap->options only has 32-bits of valid
7260 * info, so truncate before extending again */
7261 error
= VNOP_READDIRATTR(vp
, &attributelist
, auio
,
7263 (u_long
)(uint32_t)uap
->options
, &newstate
, &eofflag
,
7266 (void)vnode_put(vp
);
7270 fp
->f_fglob
->fg_offset
= uio_offset(auio
); /* should be multiple of dirent, not variable */
7272 if ((error
= copyout((caddr_t
) &count
, uap
->count
, sizeof(count
))))
7274 if ((error
= copyout((caddr_t
) &newstate
, uap
->newstate
, sizeof(newstate
))))
7276 if ((error
= copyout((caddr_t
) &loff
, uap
->basep
, sizeof(loff
))))
7279 *retval
= eofflag
; /* similar to getdirentries */
7283 return (error
); /* return error earlier, an retval of 0 or 1 now */
7285 } /* end of getdirentryattr system call */
7288 * Exchange data between two files
7293 exchangedata (__unused proc_t p
, struct exchangedata_args
*uap
, __unused
int32_t *retval
)
7296 struct nameidata fnd
, snd
;
7297 vfs_context_t ctx
= vfs_context_current();
7301 u_int32_t nameiflags
;
7305 int from_truncated
=0, to_truncated
=0;
7307 fse_info f_finfo
, s_finfo
;
7311 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
7313 NDINIT(&fnd
, LOOKUP
, OP_EXCHANGEDATA
, nameiflags
| AUDITVNPATH1
,
7314 UIO_USERSPACE
, uap
->path1
, ctx
);
7316 error
= namei(&fnd
);
7323 NDINIT(&snd
, LOOKUP
, OP_EXCHANGEDATA
, CN_NBMOUNTLOOK
| nameiflags
| AUDITVNPATH2
,
7324 UIO_USERSPACE
, uap
->path2
, ctx
);
7326 error
= namei(&snd
);
7335 * if the files are the same, return an inval error
7343 * if the files are on different volumes, return an error
7345 if (svp
->v_mount
!= fvp
->v_mount
) {
7351 * if the two vnodes are not files, return an error.
7353 if ( (vnode_isreg(svp
) == 0) || (vnode_isreg(fvp
) == 0) ) {
7360 error
= mac_vnode_check_exchangedata(ctx
,
7365 if (((error
= vnode_authorize(fvp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, ctx
)) != 0) ||
7366 ((error
= vnode_authorize(svp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, ctx
)) != 0))
7371 need_fsevent(FSE_EXCHANGE
, fvp
) ||
7373 kauth_authorize_fileop_has_listeners()) {
7376 if (fpath
== NULL
|| spath
== NULL
) {
7381 flen
= safe_getpath(fvp
, NULL
, fpath
, MAXPATHLEN
, &from_truncated
);
7382 slen
= safe_getpath(svp
, NULL
, spath
, MAXPATHLEN
, &to_truncated
);
7385 get_fse_info(fvp
, &f_finfo
, ctx
);
7386 get_fse_info(svp
, &s_finfo
, ctx
);
7387 if (from_truncated
|| to_truncated
) {
7388 // set it here since only the f_finfo gets reported up to user space
7389 f_finfo
.mode
|= FSE_TRUNCATED_PATH
;
7393 /* Ok, make the call */
7394 error
= VNOP_EXCHANGE(fvp
, svp
, 0, ctx
);
7397 const char *tmpname
;
7399 if (fpath
!= NULL
&& spath
!= NULL
) {
7400 /* call out to allow 3rd party notification of exchangedata.
7401 * Ignore result of kauth_authorize_fileop call.
7403 kauth_authorize_fileop(vfs_context_ucred(ctx
), KAUTH_FILEOP_EXCHANGE
,
7404 (uintptr_t)fpath
, (uintptr_t)spath
);
7408 tmpname
= fvp
->v_name
;
7409 fvp
->v_name
= svp
->v_name
;
7410 svp
->v_name
= tmpname
;
7412 if (fvp
->v_parent
!= svp
->v_parent
) {
7415 tmp
= fvp
->v_parent
;
7416 fvp
->v_parent
= svp
->v_parent
;
7417 svp
->v_parent
= tmp
;
7419 name_cache_unlock();
7422 if (fpath
!= NULL
&& spath
!= NULL
) {
7423 add_fsevent(FSE_EXCHANGE
, ctx
,
7424 FSE_ARG_STRING
, flen
, fpath
,
7425 FSE_ARG_FINFO
, &f_finfo
,
7426 FSE_ARG_STRING
, slen
, spath
,
7427 FSE_ARG_FINFO
, &s_finfo
,
7435 RELEASE_PATH(fpath
);
7437 RELEASE_PATH(spath
);
7449 searchfs(proc_t p
, struct searchfs_args
*uap
, __unused
int32_t *retval
)
7454 struct nameidata nd
;
7455 struct user64_fssearchblock searchblock
;
7456 struct searchstate
*state
;
7457 struct attrlist
*returnattrs
;
7458 struct timeval timelimit
;
7459 void *searchparams1
,*searchparams2
;
7461 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
7462 uint32_t nummatches
;
7464 uint32_t nameiflags
;
7465 vfs_context_t ctx
= vfs_context_current();
7466 char uio_buf
[ UIO_SIZEOF(1) ];
7468 /* Start by copying in fsearchblock paramater list */
7469 if (IS_64BIT_PROCESS(p
)) {
7470 error
= copyin(uap
->searchblock
, (caddr_t
) &searchblock
, sizeof(searchblock
));
7471 timelimit
.tv_sec
= searchblock
.timelimit
.tv_sec
;
7472 timelimit
.tv_usec
= searchblock
.timelimit
.tv_usec
;
7475 struct user32_fssearchblock tmp_searchblock
;
7477 error
= copyin(uap
->searchblock
, (caddr_t
) &tmp_searchblock
, sizeof(tmp_searchblock
));
7478 // munge into 64-bit version
7479 searchblock
.returnattrs
= CAST_USER_ADDR_T(tmp_searchblock
.returnattrs
);
7480 searchblock
.returnbuffer
= CAST_USER_ADDR_T(tmp_searchblock
.returnbuffer
);
7481 searchblock
.returnbuffersize
= tmp_searchblock
.returnbuffersize
;
7482 searchblock
.maxmatches
= tmp_searchblock
.maxmatches
;
7484 * These casts are safe. We will promote the tv_sec into a 64 bit long if necessary
7485 * from a 32 bit long, and tv_usec is already a signed 32 bit int.
7487 timelimit
.tv_sec
= (__darwin_time_t
) tmp_searchblock
.timelimit
.tv_sec
;
7488 timelimit
.tv_usec
= (__darwin_useconds_t
) tmp_searchblock
.timelimit
.tv_usec
;
7489 searchblock
.searchparams1
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams1
);
7490 searchblock
.sizeofsearchparams1
= tmp_searchblock
.sizeofsearchparams1
;
7491 searchblock
.searchparams2
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams2
);
7492 searchblock
.sizeofsearchparams2
= tmp_searchblock
.sizeofsearchparams2
;
7493 searchblock
.searchattrs
= tmp_searchblock
.searchattrs
;
7498 /* Do a sanity check on sizeofsearchparams1 and sizeofsearchparams2.
7500 if (searchblock
.sizeofsearchparams1
> SEARCHFS_MAX_SEARCHPARMS
||
7501 searchblock
.sizeofsearchparams2
> SEARCHFS_MAX_SEARCHPARMS
)
7504 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
7505 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
7506 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
7509 mallocsize
= searchblock
.sizeofsearchparams1
+ searchblock
.sizeofsearchparams2
+
7510 sizeof(struct attrlist
) + sizeof(struct searchstate
);
7512 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
7514 /* Now set up the various pointers to the correct place in our newly allocated memory */
7516 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
7517 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
7518 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
7520 /* Now copy in the stuff given our local variables. */
7522 if ((error
= copyin(searchblock
.searchparams1
, searchparams1
, searchblock
.sizeofsearchparams1
)))
7525 if ((error
= copyin(searchblock
.searchparams2
, searchparams2
, searchblock
.sizeofsearchparams2
)))
7528 if ((error
= copyin(searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
))))
7531 if ((error
= copyin(uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
))))
7536 * Because searchparams1 and searchparams2 may contain an ATTR_CMN_NAME search parameter,
7537 * which is passed in with an attrreference_t, we need to inspect the buffer manually here.
7538 * The KPI does not provide us the ability to pass in the length of the buffers searchparams1
7539 * and searchparams2. To obviate the need for all searchfs-supporting filesystems to
7540 * validate the user-supplied data offset of the attrreference_t, we'll do it here.
7543 if (searchblock
.searchattrs
.commonattr
& ATTR_CMN_NAME
) {
7544 attrreference_t
* string_ref
;
7545 u_int32_t
* start_length
;
7546 user64_size_t param_length
;
7548 /* validate searchparams1 */
7549 param_length
= searchblock
.sizeofsearchparams1
;
7550 /* skip the word that specifies length of the buffer */
7551 start_length
= (u_int32_t
*) searchparams1
;
7552 start_length
= start_length
+1;
7553 string_ref
= (attrreference_t
*) start_length
;
7555 /* ensure no negative offsets or too big offsets */
7556 if (string_ref
->attr_dataoffset
< 0 ) {
7560 if (string_ref
->attr_length
> MAXPATHLEN
) {
7565 /* Check for pointer overflow in the string ref */
7566 if (((char*) string_ref
+ string_ref
->attr_dataoffset
) < (char*) string_ref
) {
7571 if (((char*) string_ref
+ string_ref
->attr_dataoffset
) > ((char*)searchparams1
+ param_length
)) {
7575 if (((char*)string_ref
+ string_ref
->attr_dataoffset
+ string_ref
->attr_length
) > ((char*)searchparams1
+ param_length
)) {
7581 /* set up the uio structure which will contain the users return buffer */
7582 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
7583 &uio_buf
[0], sizeof(uio_buf
));
7584 uio_addiov(auio
, searchblock
.returnbuffer
, searchblock
.returnbuffersize
);
7587 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
7588 NDINIT(&nd
, LOOKUP
, OP_SEARCHFS
, nameiflags
| AUDITVNPATH1
,
7589 UIO_USERSPACE
, uap
->path
, ctx
);
7599 error
= mac_vnode_check_searchfs(ctx
, vp
, &searchblock
.searchattrs
);
7608 * If searchblock.maxmatches == 0, then skip the search. This has happened
7609 * before and sometimes the underlyning code doesnt deal with it well.
7611 if (searchblock
.maxmatches
== 0) {
7617 Allright, we have everything we need, so lets make that call.
7619 We keep special track of the return value from the file system:
7620 EAGAIN is an acceptable error condition that shouldn't keep us
7621 from copying out any results...
7624 fserror
= VNOP_SEARCHFS(vp
,
7627 &searchblock
.searchattrs
,
7628 (u_long
)searchblock
.maxmatches
,
7632 (u_long
)uap
->scriptcode
,
7633 (u_long
)uap
->options
,
7642 /* Now copy out the stuff that needs copying out. That means the number of matches, the
7643 search state. Everything was already put into he return buffer by the vop call. */
7645 if ((error
= copyout((caddr_t
) state
, uap
->state
, sizeof(struct searchstate
))) != 0)
7648 if ((error
= suulong(uap
->nummatches
, (uint64_t)nummatches
)) != 0)
7655 FREE(searchparams1
,M_TEMP
);
7660 } /* end of searchfs system call */
7662 #else /* CONFIG_SEARCHFS */
7665 searchfs(__unused proc_t p
, __unused
struct searchfs_args
*uap
, __unused
int32_t *retval
)
7670 #endif /* CONFIG_SEARCHFS */
7673 lck_grp_attr_t
* nspace_group_attr
;
7674 lck_attr_t
* nspace_lock_attr
;
7675 lck_grp_t
* nspace_mutex_group
;
7677 lck_mtx_t nspace_handler_lock
;
7678 lck_mtx_t nspace_handler_exclusion_lock
;
7680 time_t snapshot_timestamp
=0;
7681 int nspace_allow_virtual_devs
=0;
7683 void nspace_handler_init(void);
7685 typedef struct nspace_item_info
{
7695 #define MAX_NSPACE_ITEMS 128
7696 nspace_item_info nspace_items
[MAX_NSPACE_ITEMS
];
7697 uint32_t nspace_item_idx
=0; // also used as the sleep/wakeup rendezvous address
7698 uint32_t nspace_token_id
=0;
7699 uint32_t nspace_handler_timeout
= 15; // seconds
7701 #define NSPACE_ITEM_NEW 0x0001
7702 #define NSPACE_ITEM_PROCESSING 0x0002
7703 #define NSPACE_ITEM_DEAD 0x0004
7704 #define NSPACE_ITEM_CANCELLED 0x0008
7705 #define NSPACE_ITEM_DONE 0x0010
7706 #define NSPACE_ITEM_RESET_TIMER 0x0020
7708 #define NSPACE_ITEM_NSPACE_EVENT 0x0040
7709 #define NSPACE_ITEM_SNAPSHOT_EVENT 0x0080
7710 #define NSPACE_ITEM_TRACK_EVENT 0x0100
7712 #define NSPACE_ITEM_ALL_EVENT_TYPES (NSPACE_ITEM_NSPACE_EVENT | NSPACE_ITEM_SNAPSHOT_EVENT | NSPACE_ITEM_TRACK_EVENT)
7714 //#pragma optimization_level 0
7717 NSPACE_HANDLER_NSPACE
= 0,
7718 NSPACE_HANDLER_SNAPSHOT
= 1,
7719 NSPACE_HANDLER_TRACK
= 2,
7721 NSPACE_HANDLER_COUNT
,
7725 uint64_t handler_tid
;
7726 struct proc
*handler_proc
;
7730 nspace_handler_t nspace_handlers
[NSPACE_HANDLER_COUNT
];
7732 static inline int nspace_flags_matches_handler(uint32_t event_flags
, nspace_type_t nspace_type
)
7734 switch(nspace_type
) {
7735 case NSPACE_HANDLER_NSPACE
:
7736 return (event_flags
& NSPACE_ITEM_ALL_EVENT_TYPES
) == NSPACE_ITEM_NSPACE_EVENT
;
7737 case NSPACE_HANDLER_SNAPSHOT
:
7738 return (event_flags
& NSPACE_ITEM_ALL_EVENT_TYPES
) == NSPACE_ITEM_SNAPSHOT_EVENT
;
7739 case NSPACE_HANDLER_TRACK
:
7740 return (event_flags
& NSPACE_ITEM_ALL_EVENT_TYPES
) == NSPACE_ITEM_TRACK_EVENT
;
7742 printf("nspace_flags_matches_handler: invalid type %u\n", (int)nspace_type
);
7747 static inline int nspace_item_flags_for_type(nspace_type_t nspace_type
)
7749 switch(nspace_type
) {
7750 case NSPACE_HANDLER_NSPACE
:
7751 return NSPACE_ITEM_NSPACE_EVENT
;
7752 case NSPACE_HANDLER_SNAPSHOT
:
7753 return NSPACE_ITEM_SNAPSHOT_EVENT
;
7754 case NSPACE_HANDLER_TRACK
:
7755 return NSPACE_ITEM_TRACK_EVENT
;
7757 printf("nspace_item_flags_for_type: invalid type %u\n", (int)nspace_type
);
7762 static inline int nspace_open_flags_for_type(nspace_type_t nspace_type
)
7764 switch(nspace_type
) {
7765 case NSPACE_HANDLER_NSPACE
:
7766 return FREAD
| FWRITE
| O_EVTONLY
;
7767 case NSPACE_HANDLER_SNAPSHOT
:
7768 case NSPACE_HANDLER_TRACK
:
7769 return FREAD
| O_EVTONLY
;
7771 printf("nspace_open_flags_for_type: invalid type %u\n", (int)nspace_type
);
7776 static inline nspace_type_t
nspace_type_for_op(uint64_t op
)
7778 switch(op
& NAMESPACE_HANDLER_EVENT_TYPE_MASK
) {
7779 case NAMESPACE_HANDLER_NSPACE_EVENT
:
7780 return NSPACE_HANDLER_NSPACE
;
7781 case NAMESPACE_HANDLER_SNAPSHOT_EVENT
:
7782 return NSPACE_HANDLER_SNAPSHOT
;
7783 case NAMESPACE_HANDLER_TRACK_EVENT
:
7784 return NSPACE_HANDLER_TRACK
;
7786 printf("nspace_type_for_op: invalid op mask %llx\n", op
& NAMESPACE_HANDLER_EVENT_TYPE_MASK
);
7787 return NSPACE_HANDLER_NSPACE
;
7791 static inline int nspace_is_special_process(struct proc
*proc
)
7794 for (i
= 0; i
< NSPACE_HANDLER_COUNT
; i
++) {
7795 if (proc
== nspace_handlers
[i
].handler_proc
)
7802 nspace_handler_init(void)
7804 nspace_lock_attr
= lck_attr_alloc_init();
7805 nspace_group_attr
= lck_grp_attr_alloc_init();
7806 nspace_mutex_group
= lck_grp_alloc_init("nspace-mutex", nspace_group_attr
);
7807 lck_mtx_init(&nspace_handler_lock
, nspace_mutex_group
, nspace_lock_attr
);
7808 lck_mtx_init(&nspace_handler_exclusion_lock
, nspace_mutex_group
, nspace_lock_attr
);
7809 memset(&nspace_items
[0], 0, sizeof(nspace_items
));
7813 nspace_proc_exit(struct proc
*p
)
7815 int i
, event_mask
= 0;
7817 for (i
= 0; i
< NSPACE_HANDLER_COUNT
; i
++) {
7818 if (p
== nspace_handlers
[i
].handler_proc
) {
7819 event_mask
|= nspace_item_flags_for_type(i
);
7820 nspace_handlers
[i
].handler_tid
= 0;
7821 nspace_handlers
[i
].handler_proc
= NULL
;
7825 if (event_mask
== 0) {
7829 if (event_mask
& NSPACE_ITEM_SNAPSHOT_EVENT
) {
7830 // if this process was the snapshot handler, zero snapshot_timeout
7831 snapshot_timestamp
= 0;
7835 // unblock anyone that's waiting for the handler that died
7837 lck_mtx_lock(&nspace_handler_lock
);
7838 for(i
=0; i
< MAX_NSPACE_ITEMS
; i
++) {
7839 if (nspace_items
[i
].flags
& (NSPACE_ITEM_NEW
| NSPACE_ITEM_PROCESSING
)) {
7841 if ( nspace_items
[i
].flags
& event_mask
) {
7843 if (nspace_items
[i
].vp
&& (nspace_items
[i
].vp
->v_flag
& VNEEDSSNAPSHOT
)) {
7844 vnode_lock_spin(nspace_items
[i
].vp
);
7845 nspace_items
[i
].vp
->v_flag
&= ~VNEEDSSNAPSHOT
;
7846 vnode_unlock(nspace_items
[i
].vp
);
7848 nspace_items
[i
].vp
= NULL
;
7849 nspace_items
[i
].vid
= 0;
7850 nspace_items
[i
].flags
= NSPACE_ITEM_DONE
;
7851 nspace_items
[i
].token
= 0;
7853 wakeup((caddr_t
)&(nspace_items
[i
].vp
));
7858 wakeup((caddr_t
)&nspace_item_idx
);
7859 lck_mtx_unlock(&nspace_handler_lock
);
7864 resolve_nspace_item(struct vnode
*vp
, uint64_t op
)
7866 return resolve_nspace_item_ext(vp
, op
, NULL
);
7870 resolve_nspace_item_ext(struct vnode
*vp
, uint64_t op
, void *arg
)
7872 int i
, error
, keep_waiting
;
7874 nspace_type_t nspace_type
= nspace_type_for_op(op
);
7876 // only allow namespace events on regular files, directories and symlinks.
7877 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VDIR
&& vp
->v_type
!= VLNK
) {
7882 // if this is a snapshot event and the vnode is on a
7883 // disk image just pretend nothing happened since any
7884 // change to the disk image will cause the disk image
7885 // itself to get backed up and this avoids multi-way
7886 // deadlocks between the snapshot handler and the ever
7887 // popular diskimages-helper process. the variable
7888 // nspace_allow_virtual_devs allows this behavior to
7889 // be overridden (for use by the Mobile TimeMachine
7890 // testing infrastructure which uses disk images)
7892 if ( (op
& NAMESPACE_HANDLER_SNAPSHOT_EVENT
)
7893 && (vp
->v_mount
!= NULL
)
7894 && (vp
->v_mount
->mnt_kern_flag
& MNTK_VIRTUALDEV
)
7895 && !nspace_allow_virtual_devs
) {
7900 // if (thread_tid(current_thread()) == namespace_handler_tid) {
7901 if (nspace_handlers
[nspace_type
].handler_proc
== NULL
) {
7905 if (nspace_is_special_process(current_proc())) {
7909 lck_mtx_lock(&nspace_handler_lock
);
7912 for(i
=0; i
< MAX_NSPACE_ITEMS
; i
++) {
7913 if (vp
== nspace_items
[i
].vp
&& op
== nspace_items
[i
].op
) {
7918 if (i
>= MAX_NSPACE_ITEMS
) {
7919 for(i
=0; i
< MAX_NSPACE_ITEMS
; i
++) {
7920 if (nspace_items
[i
].flags
== 0) {
7925 nspace_items
[i
].refcount
++;
7928 if (i
>= MAX_NSPACE_ITEMS
) {
7929 ts
.tv_sec
= nspace_handler_timeout
;
7932 error
= msleep((caddr_t
)&nspace_token_id
, &nspace_handler_lock
, PVFS
|PCATCH
, "nspace-no-space", &ts
);
7934 // an entry got free'd up, go see if we can get a slot
7937 lck_mtx_unlock(&nspace_handler_lock
);
7943 // if it didn't already exist, add it. if it did exist
7944 // we'll get woken up when someone does a wakeup() on
7945 // the slot in the nspace_items table.
7947 if (vp
!= nspace_items
[i
].vp
) {
7948 nspace_items
[i
].vp
= vp
;
7949 nspace_items
[i
].arg
= arg
;
7950 nspace_items
[i
].op
= op
;
7951 nspace_items
[i
].vid
= vnode_vid(vp
);
7952 nspace_items
[i
].flags
= NSPACE_ITEM_NEW
;
7953 nspace_items
[i
].flags
|= nspace_item_flags_for_type(nspace_type
);
7954 if (nspace_items
[i
].flags
& NSPACE_ITEM_SNAPSHOT_EVENT
) {
7956 vnode_lock_spin(vp
);
7957 vp
->v_flag
|= VNEEDSSNAPSHOT
;
7962 nspace_items
[i
].token
= 0;
7963 nspace_items
[i
].refcount
= 1;
7965 wakeup((caddr_t
)&nspace_item_idx
);
7969 // Now go to sleep until the handler does a wakeup on this
7970 // slot in the nspace_items table (or we timeout).
7973 while(keep_waiting
) {
7974 ts
.tv_sec
= nspace_handler_timeout
;
7976 error
= msleep((caddr_t
)&(nspace_items
[i
].vp
), &nspace_handler_lock
, PVFS
|PCATCH
, "namespace-done", &ts
);
7978 if (nspace_items
[i
].flags
& NSPACE_ITEM_DONE
) {
7980 } else if (nspace_items
[i
].flags
& NSPACE_ITEM_CANCELLED
) {
7981 error
= nspace_items
[i
].token
;
7982 } else if (error
== EWOULDBLOCK
|| error
== ETIMEDOUT
) {
7983 if (nspace_items
[i
].flags
& NSPACE_ITEM_RESET_TIMER
) {
7984 nspace_items
[i
].flags
&= ~NSPACE_ITEM_RESET_TIMER
;
7989 } else if (error
== 0) {
7990 // hmmm, why did we get woken up?
7991 printf("woken up for token %d but it's not done, cancelled or timedout and error == 0.\n",
7992 nspace_items
[i
].token
);
7995 if (--nspace_items
[i
].refcount
== 0) {
7996 nspace_items
[i
].vp
= NULL
; // clear this so that no one will match on it again
7997 nspace_items
[i
].arg
= NULL
;
7998 nspace_items
[i
].token
= 0; // clear this so that the handler will not find it anymore
7999 nspace_items
[i
].flags
= 0; // this clears it for re-use
8001 wakeup(&nspace_token_id
);
8005 lck_mtx_unlock(&nspace_handler_lock
);
8012 get_nspace_item_status(struct vnode
*vp
, int32_t *status
)
8016 lck_mtx_lock(&nspace_handler_lock
);
8017 for(i
=0; i
< MAX_NSPACE_ITEMS
; i
++) {
8018 if (nspace_items
[i
].vp
== vp
) {
8023 if (i
>= MAX_NSPACE_ITEMS
) {
8024 lck_mtx_unlock(&nspace_handler_lock
);
8028 *status
= nspace_items
[i
].flags
;
8029 lck_mtx_unlock(&nspace_handler_lock
);
8036 build_volfs_path(struct vnode
*vp
, char *path
, int *len
)
8038 struct vnode_attr va
;
8042 VATTR_WANTED(&va
, va_fsid
);
8043 VATTR_WANTED(&va
, va_fileid
);
8045 if (vnode_getattr(vp
, &va
, vfs_context_kernel()) != 0) {
8046 *len
= snprintf(path
, *len
, "/non/existent/path/because/vnode_getattr/failed") + 1;
8049 *len
= snprintf(path
, *len
, "/.vol/%d/%lld", (dev_t
)va
.va_fsid
, va
.va_fileid
) + 1;
8058 // Note: this function does NOT check permissions on all of the
8059 // parent directories leading to this vnode. It should only be
8060 // called on behalf of a root process. Otherwise a process may
8061 // get access to a file because the file itself is readable even
8062 // though its parent directories would prevent access.
8065 vn_open_with_vp(vnode_t vp
, int fmode
, vfs_context_t ctx
)
8069 if ((error
= suser(kauth_cred_get(), &(current_proc()->p_acflag
)))) {
8074 error
= mac_vnode_check_open(ctx
, vp
, fmode
);
8079 /* compute action to be authorized */
8081 if (fmode
& FREAD
) {
8082 action
|= KAUTH_VNODE_READ_DATA
;
8084 if (fmode
& (FWRITE
| O_TRUNC
)) {
8086 * If we are writing, appending, and not truncating,
8087 * indicate that we are appending so that if the
8088 * UF_APPEND or SF_APPEND bits are set, we do not deny
8091 if ((fmode
& O_APPEND
) && !(fmode
& O_TRUNC
)) {
8092 action
|= KAUTH_VNODE_APPEND_DATA
;
8094 action
|= KAUTH_VNODE_WRITE_DATA
;
8098 if ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)
8103 // if the vnode is tagged VOPENEVT and the current process
8104 // has the P_CHECKOPENEVT flag set, then we or in the O_EVTONLY
8105 // flag to the open mode so that this open won't count against
8106 // the vnode when carbon delete() does a vnode_isinuse() to see
8107 // if a file is currently in use. this allows spotlight
8108 // importers to not interfere with carbon apps that depend on
8109 // the no-delete-if-busy semantics of carbon delete().
8111 if ((vp
->v_flag
& VOPENEVT
) && (current_proc()->p_flag
& P_CHECKOPENEVT
)) {
8115 if ( (error
= VNOP_OPEN(vp
, fmode
, ctx
)) ) {
8118 if ( (error
= vnode_ref_ext(vp
, fmode
, 0)) ) {
8119 VNOP_CLOSE(vp
, fmode
, ctx
);
8123 /* call out to allow 3rd party notification of open.
8124 * Ignore result of kauth_authorize_fileop call.
8126 kauth_authorize_fileop(vfs_context_ucred(ctx
), KAUTH_FILEOP_OPEN
,
8134 wait_for_namespace_event(namespace_handler_info_ext
*nhi
, nspace_type_t nspace_type
)
8136 int i
, error
=0, unblock
=0;
8139 lck_mtx_lock(&nspace_handler_exclusion_lock
);
8140 if (nspace_handlers
[nspace_type
].handler_busy
) {
8141 lck_mtx_unlock(&nspace_handler_exclusion_lock
);
8144 nspace_handlers
[nspace_type
].handler_busy
= 1;
8145 lck_mtx_unlock(&nspace_handler_exclusion_lock
);
8148 * Any process that gets here will be one of the namespace handlers.
8149 * As such, they should be prevented from acquiring DMG vnodes during vnode reclamation
8150 * as we can cause deadlocks to occur, because the namespace handler may prevent
8151 * VNOP_INACTIVE from proceeding. Mark the current task as a P_DEPENDENCY_CAPABLE
8154 curtask
= current_task();
8155 bsd_set_dependency_capable (curtask
);
8157 lck_mtx_lock(&nspace_handler_lock
);
8158 if (nspace_handlers
[nspace_type
].handler_proc
== NULL
) {
8159 nspace_handlers
[nspace_type
].handler_tid
= thread_tid(current_thread());
8160 nspace_handlers
[nspace_type
].handler_proc
= current_proc();
8163 while (error
== 0) {
8165 for(i
=0; i
< MAX_NSPACE_ITEMS
; i
++) {
8166 if (nspace_items
[i
].flags
& NSPACE_ITEM_NEW
) {
8167 if (!nspace_flags_matches_handler(nspace_items
[i
].flags
, nspace_type
)) {
8174 if (i
< MAX_NSPACE_ITEMS
) {
8175 nspace_items
[i
].flags
&= ~NSPACE_ITEM_NEW
;
8176 nspace_items
[i
].flags
|= NSPACE_ITEM_PROCESSING
;
8177 nspace_items
[i
].token
= ++nspace_token_id
;
8179 if (nspace_items
[i
].vp
) {
8180 struct fileproc
*fp
;
8181 int32_t indx
, fmode
;
8182 struct proc
*p
= current_proc();
8183 vfs_context_t ctx
= vfs_context_current();
8185 fmode
= nspace_open_flags_for_type(nspace_type
);
8187 error
= vnode_getwithvid(nspace_items
[i
].vp
, nspace_items
[i
].vid
);
8192 error
= vn_open_with_vp(nspace_items
[i
].vp
, fmode
, ctx
);
8195 vnode_put(nspace_items
[i
].vp
);
8199 if ((error
= falloc(p
, &fp
, &indx
, ctx
))) {
8200 vn_close(nspace_items
[i
].vp
, fmode
, ctx
);
8201 vnode_put(nspace_items
[i
].vp
);
8206 fp
->f_fglob
->fg_flag
= fmode
;
8207 fp
->f_fglob
->fg_type
= DTYPE_VNODE
;
8208 fp
->f_fglob
->fg_ops
= &vnops
;
8209 fp
->f_fglob
->fg_data
= (caddr_t
)nspace_items
[i
].vp
;
8212 procfdtbl_releasefd(p
, indx
, NULL
);
8213 fp_drop(p
, indx
, fp
, 1);
8216 error
= copyout(&nspace_items
[i
].token
, nhi
->token
, sizeof(uint32_t));
8217 error
= copyout(&nspace_items
[i
].op
, nhi
->flags
, sizeof(uint64_t));
8218 error
= copyout(&indx
, nhi
->fdptr
, sizeof(uint32_t));
8220 uio_t uio
= (uio_t
)nspace_items
[i
].arg
;
8221 uint64_t u_offset
, u_length
;
8224 u_offset
= uio_offset(uio
);
8225 u_length
= uio_resid(uio
);
8230 error
= copyout(&u_offset
, nhi
->infoptr
, sizeof(uint64_t));
8231 error
= copyout(&u_length
, nhi
->infoptr
+sizeof(uint64_t), sizeof(uint64_t));
8234 vn_close(nspace_items
[i
].vp
, fmode
, ctx
);
8235 fp_free(p
, indx
, fp
);
8239 vnode_put(nspace_items
[i
].vp
);
8243 printf("wait_for_nspace_event: failed (nspace_items[%d] == %p error %d, name %s)\n",
8244 i
, nspace_items
[i
].vp
, error
, nspace_items
[i
].vp
->v_name
);
8248 error
= msleep((caddr_t
)&nspace_item_idx
, &nspace_handler_lock
, PVFS
|PCATCH
, "namespace-items", 0);
8249 if ((nspace_type
== NSPACE_HANDLER_SNAPSHOT
) && (snapshot_timestamp
== 0 || snapshot_timestamp
== ~0)) {
8258 if (nspace_items
[i
].vp
&& (nspace_items
[i
].vp
->v_flag
& VNEEDSSNAPSHOT
)) {
8259 vnode_lock_spin(nspace_items
[i
].vp
);
8260 nspace_items
[i
].vp
->v_flag
&= ~VNEEDSSNAPSHOT
;
8261 vnode_unlock(nspace_items
[i
].vp
);
8263 nspace_items
[i
].vp
= NULL
;
8264 nspace_items
[i
].vid
= 0;
8265 nspace_items
[i
].flags
= NSPACE_ITEM_DONE
;
8266 nspace_items
[i
].token
= 0;
8268 wakeup((caddr_t
)&(nspace_items
[i
].vp
));
8271 if (nspace_type
== NSPACE_HANDLER_SNAPSHOT
) {
8272 // just go through every snapshot event and unblock it immediately.
8273 if (error
&& (snapshot_timestamp
== 0 || snapshot_timestamp
== ~0)) {
8274 for(i
=0; i
< MAX_NSPACE_ITEMS
; i
++) {
8275 if (nspace_items
[i
].flags
& NSPACE_ITEM_NEW
) {
8276 if (nspace_flags_matches_handler(nspace_items
[i
].flags
, nspace_type
)) {
8277 nspace_items
[i
].vp
= NULL
;
8278 nspace_items
[i
].vid
= 0;
8279 nspace_items
[i
].flags
= NSPACE_ITEM_DONE
;
8280 nspace_items
[i
].token
= 0;
8282 wakeup((caddr_t
)&(nspace_items
[i
].vp
));
8289 lck_mtx_unlock(&nspace_handler_lock
);
8291 lck_mtx_lock(&nspace_handler_exclusion_lock
);
8292 nspace_handlers
[nspace_type
].handler_busy
= 0;
8293 lck_mtx_unlock(&nspace_handler_exclusion_lock
);
8299 static int process_namespace_fsctl(nspace_type_t nspace_type
, int is64bit
, u_int size
, caddr_t data
)
8302 namespace_handler_info_ext nhi
;
8304 if (nspace_type
== NSPACE_HANDLER_SNAPSHOT
&& (snapshot_timestamp
== 0 || snapshot_timestamp
== ~0)) {
8308 if ((error
= suser(kauth_cred_get(), &(current_proc()->p_acflag
)))) {
8312 if ( (is64bit
&& size
!= sizeof(user64_namespace_handler_info
) && size
!= sizeof(user64_namespace_handler_info_ext
))
8313 || (is64bit
== 0 && size
!= sizeof(user32_namespace_handler_info
) && size
!= sizeof(user32_namespace_handler_info_ext
))) {
8315 // either you're 64-bit and passed a 64-bit struct or
8316 // you're 32-bit and passed a 32-bit struct. otherwise
8322 nhi
.token
= (user_addr_t
)((user64_namespace_handler_info
*)data
)->token
;
8323 nhi
.flags
= (user_addr_t
)((user64_namespace_handler_info
*)data
)->flags
;
8324 nhi
.fdptr
= (user_addr_t
)((user64_namespace_handler_info
*)data
)->fdptr
;
8325 if (size
== sizeof(user64_namespace_handler_info_ext
)) {
8326 nhi
.infoptr
= (user_addr_t
)((user64_namespace_handler_info_ext
*)data
)->infoptr
;
8331 nhi
.token
= CAST_USER_ADDR_T(((user32_namespace_handler_info
*)data
)->token
);
8332 nhi
.flags
= CAST_USER_ADDR_T(((user32_namespace_handler_info
*)data
)->flags
);
8333 nhi
.fdptr
= CAST_USER_ADDR_T(((user32_namespace_handler_info
*)data
)->fdptr
);
8334 if (size
== sizeof(user32_namespace_handler_info_ext
)) {
8335 nhi
.infoptr
= CAST_USER_ADDR_T(((user32_namespace_handler_info_ext
*)data
)->infoptr
);
8341 return wait_for_namespace_event(&nhi
, nspace_type
);
8345 * Make a filesystem-specific control call:
8349 fsctl_internal(proc_t p
, vnode_t
*arg_vp
, u_long cmd
, user_addr_t udata
, u_long options
, vfs_context_t ctx
)
8354 #define STK_PARAMS 128
8355 char stkbuf
[STK_PARAMS
];
8357 vnode_t vp
= *arg_vp
;
8359 size
= IOCPARM_LEN(cmd
);
8360 if (size
> IOCPARM_MAX
) return (EINVAL
);
8362 is64bit
= proc_is64bit(p
);
8365 if (size
> sizeof (stkbuf
)) {
8366 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
8374 error
= copyin(udata
, data
, size
);
8375 if (error
) goto FSCtl_Exit
;
8378 *(user_addr_t
*)data
= udata
;
8381 *(uint32_t *)data
= (uint32_t)udata
;
8384 } else if ((cmd
& IOC_OUT
) && size
) {
8386 * Zero the buffer so the user always
8387 * gets back something deterministic.
8390 } else if (cmd
& IOC_VOID
) {
8392 *(user_addr_t
*)data
= udata
;
8395 *(uint32_t *)data
= (uint32_t)udata
;
8399 /* Check to see if it's a generic command */
8400 if (IOCBASECMD(cmd
) == FSCTL_SYNC_VOLUME
) {
8401 mount_t mp
= vp
->v_mount
;
8402 int arg
= *(uint32_t*)data
;
8404 /* record vid of vp so we can drop it below. */
8405 uint32_t vvid
= vp
->v_id
;
8408 * Then grab mount_iterref so that we can release the vnode.
8409 * Without this, a thread may call vnode_iterate_prepare then
8410 * get into a deadlock because we've never released the root vp
8412 error
= mount_iterref (mp
, 0);
8418 /* issue the sync for this volume */
8419 (void)sync_callback(mp
, (arg
& FSCTL_SYNC_WAIT
) ? &arg
: NULL
);
8422 * Then release the mount_iterref once we're done syncing; it's not
8423 * needed for the VNOP_IOCTL below
8427 if (arg
& FSCTL_SYNC_FULLSYNC
) {
8428 /* re-obtain vnode iocount on the root vp, if possible */
8429 error
= vnode_getwithvid (vp
, vvid
);
8431 error
= VNOP_IOCTL(vp
, F_FULLFSYNC
, (caddr_t
)NULL
, 0, ctx
);
8435 /* mark the argument VP as having been released */
8438 } else if (IOCBASECMD(cmd
) == FSCTL_SET_PACKAGE_EXTS
) {
8439 user_addr_t ext_strings
;
8440 uint32_t num_entries
;
8443 if ( (is64bit
&& size
!= sizeof(user64_package_ext_info
))
8444 || (is64bit
== 0 && size
!= sizeof(user32_package_ext_info
))) {
8446 // either you're 64-bit and passed a 64-bit struct or
8447 // you're 32-bit and passed a 32-bit struct. otherwise
8454 ext_strings
= ((user64_package_ext_info
*)data
)->strings
;
8455 num_entries
= ((user64_package_ext_info
*)data
)->num_entries
;
8456 max_width
= ((user64_package_ext_info
*)data
)->max_width
;
8458 ext_strings
= CAST_USER_ADDR_T(((user32_package_ext_info
*)data
)->strings
);
8459 num_entries
= ((user32_package_ext_info
*)data
)->num_entries
;
8460 max_width
= ((user32_package_ext_info
*)data
)->max_width
;
8463 error
= set_package_extensions_table(ext_strings
, num_entries
, max_width
);
8465 } else if (IOCBASECMD(cmd
) == FSCTL_WAIT_FOR_SYNC
) {
8466 error
= tsleep((caddr_t
)&sync_wait_time
, PVFS
|PCATCH
, "sync-wait", 0);
8468 *(uint32_t *)data
= (uint32_t)sync_wait_time
;
8474 } else if (IOCBASECMD(cmd
) == FSCTL_NAMESPACE_HANDLER_GET
) {
8475 error
= process_namespace_fsctl(NSPACE_HANDLER_NSPACE
, is64bit
, size
, data
);
8476 } else if (IOCBASECMD(cmd
) == FSCTL_OLD_SNAPSHOT_HANDLER_GET
) {
8477 error
= process_namespace_fsctl(NSPACE_HANDLER_SNAPSHOT
, is64bit
, size
, data
);
8478 } else if (IOCBASECMD(cmd
) == FSCTL_SNAPSHOT_HANDLER_GET_EXT
) {
8479 error
= process_namespace_fsctl(NSPACE_HANDLER_SNAPSHOT
, is64bit
, size
, data
);
8480 } else if (IOCBASECMD(cmd
) == FSCTL_TRACKED_HANDLER_GET
) {
8481 error
= process_namespace_fsctl(NSPACE_HANDLER_TRACK
, is64bit
, size
, data
);
8482 } else if (IOCBASECMD(cmd
) == FSCTL_NAMESPACE_HANDLER_UPDATE
) {
8483 uint32_t token
, val
;
8486 if ((error
= suser(kauth_cred_get(), &(p
->p_acflag
)))) {
8490 if (!nspace_is_special_process(p
)) {
8495 token
= ((uint32_t *)data
)[0];
8496 val
= ((uint32_t *)data
)[1];
8498 lck_mtx_lock(&nspace_handler_lock
);
8500 for(i
=0; i
< MAX_NSPACE_ITEMS
; i
++) {
8501 if (nspace_items
[i
].token
== token
) {
8506 if (i
>= MAX_NSPACE_ITEMS
) {
8510 // if this bit is set, when resolve_nspace_item() times out
8511 // it will loop and go back to sleep.
8513 nspace_items
[i
].flags
|= NSPACE_ITEM_RESET_TIMER
;
8516 lck_mtx_unlock(&nspace_handler_lock
);
8519 printf("nspace-handler-update: did not find token %u\n", token
);
8522 } else if (IOCBASECMD(cmd
) == FSCTL_NAMESPACE_HANDLER_UNBLOCK
) {
8523 uint32_t token
, val
;
8526 if ((error
= suser(kauth_cred_get(), &(p
->p_acflag
)))) {
8530 if (!nspace_is_special_process(p
)) {
8535 token
= ((uint32_t *)data
)[0];
8536 val
= ((uint32_t *)data
)[1];
8538 lck_mtx_lock(&nspace_handler_lock
);
8540 for(i
=0; i
< MAX_NSPACE_ITEMS
; i
++) {
8541 if (nspace_items
[i
].token
== token
) {
8546 if (i
>= MAX_NSPACE_ITEMS
) {
8547 printf("nspace-handler-unblock: did not find token %u\n", token
);
8550 if (val
== 0 && nspace_items
[i
].vp
) {
8551 vnode_lock_spin(nspace_items
[i
].vp
);
8552 nspace_items
[i
].vp
->v_flag
&= ~VNEEDSSNAPSHOT
;
8553 vnode_unlock(nspace_items
[i
].vp
);
8556 nspace_items
[i
].vp
= NULL
;
8557 nspace_items
[i
].arg
= NULL
;
8558 nspace_items
[i
].op
= 0;
8559 nspace_items
[i
].vid
= 0;
8560 nspace_items
[i
].flags
= NSPACE_ITEM_DONE
;
8561 nspace_items
[i
].token
= 0;
8563 wakeup((caddr_t
)&(nspace_items
[i
].vp
));
8566 lck_mtx_unlock(&nspace_handler_lock
);
8568 } else if (IOCBASECMD(cmd
) == FSCTL_NAMESPACE_HANDLER_CANCEL
) {
8569 uint32_t token
, val
;
8572 if ((error
= suser(kauth_cred_get(), &(p
->p_acflag
)))) {
8576 if (!nspace_is_special_process(p
)) {
8581 token
= ((uint32_t *)data
)[0];
8582 val
= ((uint32_t *)data
)[1];
8584 lck_mtx_lock(&nspace_handler_lock
);
8586 for(i
=0; i
< MAX_NSPACE_ITEMS
; i
++) {
8587 if (nspace_items
[i
].token
== token
) {
8592 if (i
>= MAX_NSPACE_ITEMS
) {
8593 printf("nspace-handler-cancel: did not find token %u\n", token
);
8596 if (nspace_items
[i
].vp
) {
8597 vnode_lock_spin(nspace_items
[i
].vp
);
8598 nspace_items
[i
].vp
->v_flag
&= ~VNEEDSSNAPSHOT
;
8599 vnode_unlock(nspace_items
[i
].vp
);
8602 nspace_items
[i
].vp
= NULL
;
8603 nspace_items
[i
].arg
= NULL
;
8604 nspace_items
[i
].vid
= 0;
8605 nspace_items
[i
].token
= val
;
8606 nspace_items
[i
].flags
&= ~NSPACE_ITEM_PROCESSING
;
8607 nspace_items
[i
].flags
|= NSPACE_ITEM_CANCELLED
;
8609 wakeup((caddr_t
)&(nspace_items
[i
].vp
));
8612 lck_mtx_unlock(&nspace_handler_lock
);
8613 } else if (IOCBASECMD(cmd
) == FSCTL_NAMESPACE_HANDLER_SET_SNAPSHOT_TIME
) {
8614 if ((error
= suser(kauth_cred_get(), &(current_proc()->p_acflag
)))) {
8618 // we explicitly do not do the namespace_handler_proc check here
8620 lck_mtx_lock(&nspace_handler_lock
);
8621 snapshot_timestamp
= ((uint32_t *)data
)[0];
8622 wakeup(&nspace_item_idx
);
8623 lck_mtx_unlock(&nspace_handler_lock
);
8624 printf("nspace-handler-set-snapshot-time: %d\n", (int)snapshot_timestamp
);
8626 } else if (IOCBASECMD(cmd
) == FSCTL_NAMESPACE_ALLOW_DMG_SNAPSHOT_EVENTS
) {
8627 if ((error
= suser(kauth_cred_get(), &(current_proc()->p_acflag
)))) {
8631 lck_mtx_lock(&nspace_handler_lock
);
8632 nspace_allow_virtual_devs
= ((uint32_t *)data
)[0];
8633 lck_mtx_unlock(&nspace_handler_lock
);
8634 printf("nspace-snapshot-handler will%s allow events on disk-images\n",
8635 nspace_allow_virtual_devs
? "" : " NOT");
8638 } else if (IOCBASECMD(cmd
) == FSCTL_SET_FSTYPENAME_OVERRIDE
) {
8639 if ((error
= suser(kauth_cred_get(), &(current_proc()->p_acflag
)))) {
8643 mount_lock(vp
->v_mount
);
8645 strlcpy(&vp
->v_mount
->fstypename_override
[0], data
, MFSTYPENAMELEN
);
8646 vp
->v_mount
->mnt_kern_flag
|= MNTK_TYPENAME_OVERRIDE
;
8647 if (vfs_isrdonly(vp
->v_mount
) && strcmp(vp
->v_mount
->fstypename_override
, "mtmfs") == 0) {
8648 vp
->v_mount
->mnt_kern_flag
|= MNTK_EXTENDED_SECURITY
;
8649 vp
->v_mount
->mnt_kern_flag
&= ~MNTK_AUTH_OPAQUE
;
8652 if (strcmp(vp
->v_mount
->fstypename_override
, "mtmfs") == 0) {
8653 vp
->v_mount
->mnt_kern_flag
&= ~MNTK_EXTENDED_SECURITY
;
8655 vp
->v_mount
->mnt_kern_flag
&= ~MNTK_TYPENAME_OVERRIDE
;
8656 vp
->v_mount
->fstypename_override
[0] = '\0';
8658 mount_unlock(vp
->v_mount
);
8661 /* Invoke the filesystem-specific code */
8662 error
= VNOP_IOCTL(vp
, IOCBASECMD(cmd
), data
, options
, ctx
);
8667 * Copy any data to user, size was
8668 * already set and checked above.
8670 if (error
== 0 && (cmd
& IOC_OUT
) && size
)
8671 error
= copyout(data
, udata
, size
);
8674 if (memp
) kfree(memp
, size
);
8681 fsctl (proc_t p
, struct fsctl_args
*uap
, __unused
int32_t *retval
)
8684 struct nameidata nd
;
8687 vfs_context_t ctx
= vfs_context_current();
8689 AUDIT_ARG(cmd
, uap
->cmd
);
8690 AUDIT_ARG(value32
, uap
->options
);
8691 /* Get the vnode for the file we are getting info on: */
8693 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
8694 NDINIT(&nd
, LOOKUP
, OP_FSCTL
, nameiflags
| AUDITVNPATH1
,
8695 UIO_USERSPACE
, uap
->path
, ctx
);
8696 if ((error
= namei(&nd
))) goto done
;
8701 error
= mac_mount_check_fsctl(ctx
, vnode_mount(vp
), uap
->cmd
);
8707 error
= fsctl_internal(p
, &vp
, uap
->cmd
, (user_addr_t
)uap
->data
, uap
->options
, ctx
);
8716 ffsctl (proc_t p
, struct ffsctl_args
*uap
, __unused
int32_t *retval
)
8720 vfs_context_t ctx
= vfs_context_current();
8723 AUDIT_ARG(fd
, uap
->fd
);
8724 AUDIT_ARG(cmd
, uap
->cmd
);
8725 AUDIT_ARG(value32
, uap
->options
);
8727 /* Get the vnode for the file we are getting info on: */
8728 if ((error
= file_vnode(uap
->fd
, &vp
)))
8731 if ((error
= vnode_getwithref(vp
))) {
8736 error
= mac_mount_check_fsctl(ctx
, vnode_mount(vp
), uap
->cmd
);
8742 error
= fsctl_internal(p
, &vp
, uap
->cmd
, (user_addr_t
)uap
->data
, uap
->options
, ctx
);
8752 /* end of fsctl system call */
8755 * An in-kernel sync for power management to call.
8757 __private_extern__
int
8762 struct sync_args data
;
8767 error
= sync(current_proc(), &data
, &retval
[0]);
8771 } /* end of sync_internal call */
8775 * Retrieve the data of an extended attribute.
8778 getxattr(proc_t p
, struct getxattr_args
*uap
, user_ssize_t
*retval
)
8781 struct nameidata nd
;
8782 char attrname
[XATTR_MAXNAMELEN
+1];
8783 vfs_context_t ctx
= vfs_context_current();
8785 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
8786 size_t attrsize
= 0;
8788 u_int32_t nameiflags
;
8790 char uio_buf
[ UIO_SIZEOF(1) ];
8792 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
8795 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
8796 NDINIT(&nd
, LOOKUP
, OP_GETXATTR
, nameiflags
, spacetype
, uap
->path
, ctx
);
8797 if ((error
= namei(&nd
))) {
8803 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
8806 if (xattr_protected(attrname
)) {
8807 if (!vfs_context_issuser(ctx
) || strcmp(attrname
, "com.apple.system.Security") != 0) {
8813 * the specific check for 0xffffffff is a hack to preserve
8814 * binaray compatibilty in K64 with applications that discovered
8815 * that passing in a buf pointer and a size of -1 resulted in
8816 * just the size of the indicated extended attribute being returned.
8817 * this isn't part of the documented behavior, but because of the
8818 * original implemtation's check for "uap->size > 0", this behavior
8819 * was allowed. In K32 that check turned into a signed comparison
8820 * even though uap->size is unsigned... in K64, we blow by that
8821 * check because uap->size is unsigned and doesn't get sign smeared
8822 * in the munger for a 32 bit user app. we also need to add a
8823 * check to limit the maximum size of the buffer being passed in...
8824 * unfortunately, the underlying fileystems seem to just malloc
8825 * the requested size even if the actual extended attribute is tiny.
8826 * because that malloc is for kernel wired memory, we have to put a
8829 * U32 running on K64 will yield 0x00000000ffffffff for uap->size
8830 * U64 running on K64 will yield -1 (64 bits wide)
8831 * U32/U64 running on K32 will yield -1 (32 bits wide)
8833 if (uap
->size
== 0xffffffff || uap
->size
== (size_t)-1)
8837 if (uap
->size
> (size_t)XATTR_MAXSIZE
)
8838 uap
->size
= XATTR_MAXSIZE
;
8840 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
8841 &uio_buf
[0], sizeof(uio_buf
));
8842 uio_addiov(auio
, uap
->value
, uap
->size
);
8845 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, ctx
);
8850 *retval
= uap
->size
- uio_resid(auio
);
8852 *retval
= (user_ssize_t
)attrsize
;
8859 * Retrieve the data of an extended attribute.
8862 fgetxattr(proc_t p
, struct fgetxattr_args
*uap
, user_ssize_t
*retval
)
8865 char attrname
[XATTR_MAXNAMELEN
+1];
8867 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
8868 size_t attrsize
= 0;
8871 char uio_buf
[ UIO_SIZEOF(1) ];
8873 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
8876 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
8879 if ( (error
= vnode_getwithref(vp
)) ) {
8883 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
8886 if (xattr_protected(attrname
)) {
8890 if (uap
->value
&& uap
->size
> 0) {
8891 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
8892 &uio_buf
[0], sizeof(uio_buf
));
8893 uio_addiov(auio
, uap
->value
, uap
->size
);
8896 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, vfs_context_current());
8898 (void)vnode_put(vp
);
8902 *retval
= uap
->size
- uio_resid(auio
);
8904 *retval
= (user_ssize_t
)attrsize
;
8910 * Set the data of an extended attribute.
8913 setxattr(proc_t p
, struct setxattr_args
*uap
, int *retval
)
8916 struct nameidata nd
;
8917 char attrname
[XATTR_MAXNAMELEN
+1];
8918 vfs_context_t ctx
= vfs_context_current();
8920 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
8922 u_int32_t nameiflags
;
8924 char uio_buf
[ UIO_SIZEOF(1) ];
8926 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
8929 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
8930 if (error
== EPERM
) {
8931 /* if the string won't fit in attrname, copyinstr emits EPERM */
8932 return (ENAMETOOLONG
);
8934 /* Otherwise return the default error from copyinstr to detect ERANGE, etc */
8937 if (xattr_protected(attrname
))
8939 if (uap
->size
!= 0 && uap
->value
== 0) {
8943 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
8944 NDINIT(&nd
, LOOKUP
, OP_SETXATTR
, nameiflags
, spacetype
, uap
->path
, ctx
);
8945 if ((error
= namei(&nd
))) {
8951 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
8952 &uio_buf
[0], sizeof(uio_buf
));
8953 uio_addiov(auio
, uap
->value
, uap
->size
);
8955 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, ctx
);
8958 add_fsevent(FSE_XATTR_MODIFIED
, ctx
,
8969 * Set the data of an extended attribute.
8972 fsetxattr(proc_t p
, struct fsetxattr_args
*uap
, int *retval
)
8975 char attrname
[XATTR_MAXNAMELEN
+1];
8977 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
8980 char uio_buf
[ UIO_SIZEOF(1) ];
8982 vfs_context_t ctx
= vfs_context_current();
8985 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
8988 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
8991 if (xattr_protected(attrname
))
8993 if (uap
->size
!= 0 && uap
->value
== 0) {
8996 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
8999 if ( (error
= vnode_getwithref(vp
)) ) {
9003 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
9004 &uio_buf
[0], sizeof(uio_buf
));
9005 uio_addiov(auio
, uap
->value
, uap
->size
);
9007 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, vfs_context_current());
9010 add_fsevent(FSE_XATTR_MODIFIED
, ctx
,
9022 * Remove an extended attribute.
9023 * XXX Code duplication here.
9026 removexattr(proc_t p
, struct removexattr_args
*uap
, int *retval
)
9029 struct nameidata nd
;
9030 char attrname
[XATTR_MAXNAMELEN
+1];
9031 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
9032 vfs_context_t ctx
= vfs_context_current();
9034 u_int32_t nameiflags
;
9037 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
9040 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
9044 if (xattr_protected(attrname
))
9046 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
9047 NDINIT(&nd
, LOOKUP
, OP_REMOVEXATTR
, nameiflags
, spacetype
, uap
->path
, ctx
);
9048 if ((error
= namei(&nd
))) {
9054 error
= vn_removexattr(vp
, attrname
, uap
->options
, ctx
);
9057 add_fsevent(FSE_XATTR_REMOVED
, ctx
,
9068 * Remove an extended attribute.
9069 * XXX Code duplication here.
9072 fremovexattr(__unused proc_t p
, struct fremovexattr_args
*uap
, int *retval
)
9075 char attrname
[XATTR_MAXNAMELEN
+1];
9079 vfs_context_t ctx
= vfs_context_current();
9082 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
9085 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
9089 if (xattr_protected(attrname
))
9091 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
9094 if ( (error
= vnode_getwithref(vp
)) ) {
9099 error
= vn_removexattr(vp
, attrname
, uap
->options
, vfs_context_current());
9102 add_fsevent(FSE_XATTR_REMOVED
, ctx
,
9114 * Retrieve the list of extended attribute names.
9115 * XXX Code duplication here.
9118 listxattr(proc_t p
, struct listxattr_args
*uap
, user_ssize_t
*retval
)
9121 struct nameidata nd
;
9122 vfs_context_t ctx
= vfs_context_current();
9124 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
9125 size_t attrsize
= 0;
9126 u_int32_t nameiflags
;
9128 char uio_buf
[ UIO_SIZEOF(1) ];
9130 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
9133 nameiflags
= ((uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
) | NOTRIGGER
;
9134 NDINIT(&nd
, LOOKUP
, OP_LISTXATTR
, nameiflags
, spacetype
, uap
->path
, ctx
);
9135 if ((error
= namei(&nd
))) {
9140 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
9141 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
9142 &uio_buf
[0], sizeof(uio_buf
));
9143 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
9146 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, ctx
);
9150 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
9152 *retval
= (user_ssize_t
)attrsize
;
9158 * Retrieve the list of extended attribute names.
9159 * XXX Code duplication here.
9162 flistxattr(proc_t p
, struct flistxattr_args
*uap
, user_ssize_t
*retval
)
9166 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
9167 size_t attrsize
= 0;
9169 char uio_buf
[ UIO_SIZEOF(1) ];
9171 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
9174 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
9177 if ( (error
= vnode_getwithref(vp
)) ) {
9181 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
9182 auio
= uio_createwithbuffer(1, 0, spacetype
,
9183 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
9184 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
9187 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, vfs_context_current());
9192 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
9194 *retval
= (user_ssize_t
)attrsize
;
9200 * Obtain the full pathname of a file system object by id.
9202 * This is a private SPI used by the File Manager.
9206 fsgetpath(__unused proc_t p
, struct fsgetpath_args
*uap
, user_ssize_t
*retval
)
9209 struct mount
*mp
= NULL
;
9210 vfs_context_t ctx
= vfs_context_current();
9217 if ((error
= copyin(uap
->fsid
, (caddr_t
)&fsid
, sizeof(fsid
)))) {
9220 AUDIT_ARG(value32
, fsid
.val
[0]);
9221 AUDIT_ARG(value64
, uap
->objid
);
9222 /* Restrict output buffer size for now. */
9223 if (uap
->bufsize
> PAGE_SIZE
) {
9226 MALLOC(realpath
, char *, uap
->bufsize
, M_TEMP
, M_WAITOK
);
9227 if (realpath
== NULL
) {
9230 /* Find the target mountpoint. */
9231 if ((mp
= mount_lookupby_volfsid(fsid
.val
[0], 1)) == NULL
) {
9232 error
= ENOTSUP
; /* unexpected failure */
9235 /* Find the target vnode. */
9236 if (uap
->objid
== 2) {
9237 error
= VFS_ROOT(mp
, &vp
, ctx
);
9239 error
= VFS_VGET(mp
, (ino64_t
)uap
->objid
, &vp
, ctx
);
9246 error
= mac_vnode_check_fsgetpath(ctx
, vp
);
9252 /* Obtain the absolute path to this vnode. */
9253 bpflags
= vfs_context_suser(ctx
) ? BUILDPATH_CHECKACCESS
: 0;
9254 bpflags
|= BUILDPATH_CHECK_MOVED
;
9255 error
= build_path(vp
, realpath
, uap
->bufsize
, &length
, bpflags
, ctx
);
9260 AUDIT_ARG(text
, realpath
);
9261 error
= copyout((caddr_t
)realpath
, uap
->buf
, length
);
9263 *retval
= (user_ssize_t
)length
; /* may be superseded by error */
9266 FREE(realpath
, M_TEMP
);
9272 * Common routine to handle various flavors of statfs data heading out
9275 * Returns: 0 Success
9279 munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
9280 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
9281 boolean_t partial_copy
)
9284 int my_size
, copy_size
;
9287 struct user64_statfs sfs
;
9288 my_size
= copy_size
= sizeof(sfs
);
9289 bzero(&sfs
, my_size
);
9290 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
9291 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
9292 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
9293 sfs
.f_bsize
= (user64_long_t
)sfsp
->f_bsize
;
9294 sfs
.f_iosize
= (user64_long_t
)sfsp
->f_iosize
;
9295 sfs
.f_blocks
= (user64_long_t
)sfsp
->f_blocks
;
9296 sfs
.f_bfree
= (user64_long_t
)sfsp
->f_bfree
;
9297 sfs
.f_bavail
= (user64_long_t
)sfsp
->f_bavail
;
9298 sfs
.f_files
= (user64_long_t
)sfsp
->f_files
;
9299 sfs
.f_ffree
= (user64_long_t
)sfsp
->f_ffree
;
9300 sfs
.f_fsid
= sfsp
->f_fsid
;
9301 sfs
.f_owner
= sfsp
->f_owner
;
9302 if (mp
->mnt_kern_flag
& MNTK_TYPENAME_OVERRIDE
) {
9303 strlcpy(&sfs
.f_fstypename
[0], &mp
->fstypename_override
[0], MFSTYPENAMELEN
);
9305 strlcpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
);
9307 strlcpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
);
9308 strlcpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
);
9311 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
9313 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
9316 struct user32_statfs sfs
;
9318 my_size
= copy_size
= sizeof(sfs
);
9319 bzero(&sfs
, my_size
);
9321 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
9322 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
9323 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
9326 * It's possible for there to be more than 2^^31 blocks in the filesystem, so we
9327 * have to fudge the numbers here in that case. We inflate the blocksize in order
9328 * to reflect the filesystem size as best we can.
9330 if ((sfsp
->f_blocks
> INT_MAX
)
9331 /* Hack for 4061702 . I think the real fix is for Carbon to
9332 * look for some volume capability and not depend on hidden
9333 * semantics agreed between a FS and carbon.
9334 * f_blocks, f_bfree, and f_bavail set to -1 is the trigger
9335 * for Carbon to set bNoVolumeSizes volume attribute.
9336 * Without this the webdavfs files cannot be copied onto
9337 * disk as they look huge. This change should not affect
9338 * XSAN as they should not setting these to -1..
9340 && (sfsp
->f_blocks
!= 0xffffffffffffffffULL
)
9341 && (sfsp
->f_bfree
!= 0xffffffffffffffffULL
)
9342 && (sfsp
->f_bavail
!= 0xffffffffffffffffULL
)) {
9346 * Work out how far we have to shift the block count down to make it fit.
9347 * Note that it's possible to have to shift so far that the resulting
9348 * blocksize would be unreportably large. At that point, we will clip
9349 * any values that don't fit.
9351 * For safety's sake, we also ensure that f_iosize is never reported as
9352 * being smaller than f_bsize.
9354 for (shift
= 0; shift
< 32; shift
++) {
9355 if ((sfsp
->f_blocks
>> shift
) <= INT_MAX
)
9357 if ((sfsp
->f_bsize
<< (shift
+ 1)) > INT_MAX
)
9360 #define __SHIFT_OR_CLIP(x, s) ((((x) >> (s)) > INT_MAX) ? INT_MAX : ((x) >> (s)))
9361 sfs
.f_blocks
= (user32_long_t
)__SHIFT_OR_CLIP(sfsp
->f_blocks
, shift
);
9362 sfs
.f_bfree
= (user32_long_t
)__SHIFT_OR_CLIP(sfsp
->f_bfree
, shift
);
9363 sfs
.f_bavail
= (user32_long_t
)__SHIFT_OR_CLIP(sfsp
->f_bavail
, shift
);
9364 #undef __SHIFT_OR_CLIP
9365 sfs
.f_bsize
= (user32_long_t
)(sfsp
->f_bsize
<< shift
);
9366 sfs
.f_iosize
= lmax(sfsp
->f_iosize
, sfsp
->f_bsize
);
9368 /* filesystem is small enough to be reported honestly */
9369 sfs
.f_bsize
= (user32_long_t
)sfsp
->f_bsize
;
9370 sfs
.f_iosize
= (user32_long_t
)sfsp
->f_iosize
;
9371 sfs
.f_blocks
= (user32_long_t
)sfsp
->f_blocks
;
9372 sfs
.f_bfree
= (user32_long_t
)sfsp
->f_bfree
;
9373 sfs
.f_bavail
= (user32_long_t
)sfsp
->f_bavail
;
9375 sfs
.f_files
= (user32_long_t
)sfsp
->f_files
;
9376 sfs
.f_ffree
= (user32_long_t
)sfsp
->f_ffree
;
9377 sfs
.f_fsid
= sfsp
->f_fsid
;
9378 sfs
.f_owner
= sfsp
->f_owner
;
9379 if (mp
->mnt_kern_flag
& MNTK_TYPENAME_OVERRIDE
) {
9380 strlcpy(&sfs
.f_fstypename
[0], &mp
->fstypename_override
[0], MFSTYPENAMELEN
);
9382 strlcpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
);
9384 strlcpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
);
9385 strlcpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
);
9388 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
9390 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
9393 if (sizep
!= NULL
) {
9400 * copy stat structure into user_stat structure.
9402 void munge_user64_stat(struct stat
*sbp
, struct user64_stat
*usbp
)
9404 bzero(usbp
, sizeof(*usbp
));
9406 usbp
->st_dev
= sbp
->st_dev
;
9407 usbp
->st_ino
= sbp
->st_ino
;
9408 usbp
->st_mode
= sbp
->st_mode
;
9409 usbp
->st_nlink
= sbp
->st_nlink
;
9410 usbp
->st_uid
= sbp
->st_uid
;
9411 usbp
->st_gid
= sbp
->st_gid
;
9412 usbp
->st_rdev
= sbp
->st_rdev
;
9413 #ifndef _POSIX_C_SOURCE
9414 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
9415 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
9416 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
9417 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
9418 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
9419 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
9421 usbp
->st_atime
= sbp
->st_atime
;
9422 usbp
->st_atimensec
= sbp
->st_atimensec
;
9423 usbp
->st_mtime
= sbp
->st_mtime
;
9424 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
9425 usbp
->st_ctime
= sbp
->st_ctime
;
9426 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
9428 usbp
->st_size
= sbp
->st_size
;
9429 usbp
->st_blocks
= sbp
->st_blocks
;
9430 usbp
->st_blksize
= sbp
->st_blksize
;
9431 usbp
->st_flags
= sbp
->st_flags
;
9432 usbp
->st_gen
= sbp
->st_gen
;
9433 usbp
->st_lspare
= sbp
->st_lspare
;
9434 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
9435 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];
9438 void munge_user32_stat(struct stat
*sbp
, struct user32_stat
*usbp
)
9440 bzero(usbp
, sizeof(*usbp
));
9442 usbp
->st_dev
= sbp
->st_dev
;
9443 usbp
->st_ino
= sbp
->st_ino
;
9444 usbp
->st_mode
= sbp
->st_mode
;
9445 usbp
->st_nlink
= sbp
->st_nlink
;
9446 usbp
->st_uid
= sbp
->st_uid
;
9447 usbp
->st_gid
= sbp
->st_gid
;
9448 usbp
->st_rdev
= sbp
->st_rdev
;
9449 #ifndef _POSIX_C_SOURCE
9450 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
9451 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
9452 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
9453 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
9454 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
9455 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
9457 usbp
->st_atime
= sbp
->st_atime
;
9458 usbp
->st_atimensec
= sbp
->st_atimensec
;
9459 usbp
->st_mtime
= sbp
->st_mtime
;
9460 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
9461 usbp
->st_ctime
= sbp
->st_ctime
;
9462 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
9464 usbp
->st_size
= sbp
->st_size
;
9465 usbp
->st_blocks
= sbp
->st_blocks
;
9466 usbp
->st_blksize
= sbp
->st_blksize
;
9467 usbp
->st_flags
= sbp
->st_flags
;
9468 usbp
->st_gen
= sbp
->st_gen
;
9469 usbp
->st_lspare
= sbp
->st_lspare
;
9470 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
9471 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];
9475 * copy stat64 structure into user_stat64 structure.
9477 void munge_user64_stat64(struct stat64
*sbp
, struct user64_stat64
*usbp
)
9479 bzero(usbp
, sizeof(*usbp
));
9481 usbp
->st_dev
= sbp
->st_dev
;
9482 usbp
->st_ino
= sbp
->st_ino
;
9483 usbp
->st_mode
= sbp
->st_mode
;
9484 usbp
->st_nlink
= sbp
->st_nlink
;
9485 usbp
->st_uid
= sbp
->st_uid
;
9486 usbp
->st_gid
= sbp
->st_gid
;
9487 usbp
->st_rdev
= sbp
->st_rdev
;
9488 #ifndef _POSIX_C_SOURCE
9489 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
9490 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
9491 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
9492 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
9493 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
9494 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
9495 usbp
->st_birthtimespec
.tv_sec
= sbp
->st_birthtimespec
.tv_sec
;
9496 usbp
->st_birthtimespec
.tv_nsec
= sbp
->st_birthtimespec
.tv_nsec
;
9498 usbp
->st_atime
= sbp
->st_atime
;
9499 usbp
->st_atimensec
= sbp
->st_atimensec
;
9500 usbp
->st_mtime
= sbp
->st_mtime
;
9501 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
9502 usbp
->st_ctime
= sbp
->st_ctime
;
9503 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
9504 usbp
->st_birthtime
= sbp
->st_birthtime
;
9505 usbp
->st_birthtimensec
= sbp
->st_birthtimensec
;
9507 usbp
->st_size
= sbp
->st_size
;
9508 usbp
->st_blocks
= sbp
->st_blocks
;
9509 usbp
->st_blksize
= sbp
->st_blksize
;
9510 usbp
->st_flags
= sbp
->st_flags
;
9511 usbp
->st_gen
= sbp
->st_gen
;
9512 usbp
->st_lspare
= sbp
->st_lspare
;
9513 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
9514 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];
9517 void munge_user32_stat64(struct stat64
*sbp
, struct user32_stat64
*usbp
)
9519 bzero(usbp
, sizeof(*usbp
));
9521 usbp
->st_dev
= sbp
->st_dev
;
9522 usbp
->st_ino
= sbp
->st_ino
;
9523 usbp
->st_mode
= sbp
->st_mode
;
9524 usbp
->st_nlink
= sbp
->st_nlink
;
9525 usbp
->st_uid
= sbp
->st_uid
;
9526 usbp
->st_gid
= sbp
->st_gid
;
9527 usbp
->st_rdev
= sbp
->st_rdev
;
9528 #ifndef _POSIX_C_SOURCE
9529 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
9530 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
9531 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
9532 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
9533 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
9534 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
9535 usbp
->st_birthtimespec
.tv_sec
= sbp
->st_birthtimespec
.tv_sec
;
9536 usbp
->st_birthtimespec
.tv_nsec
= sbp
->st_birthtimespec
.tv_nsec
;
9538 usbp
->st_atime
= sbp
->st_atime
;
9539 usbp
->st_atimensec
= sbp
->st_atimensec
;
9540 usbp
->st_mtime
= sbp
->st_mtime
;
9541 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
9542 usbp
->st_ctime
= sbp
->st_ctime
;
9543 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
9544 usbp
->st_birthtime
= sbp
->st_birthtime
;
9545 usbp
->st_birthtimensec
= sbp
->st_birthtimensec
;
9547 usbp
->st_size
= sbp
->st_size
;
9548 usbp
->st_blocks
= sbp
->st_blocks
;
9549 usbp
->st_blksize
= sbp
->st_blksize
;
9550 usbp
->st_flags
= sbp
->st_flags
;
9551 usbp
->st_gen
= sbp
->st_gen
;
9552 usbp
->st_lspare
= sbp
->st_lspare
;
9553 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
9554 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];