2 * Copyright (c) 1995-2008 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/sysproto.h>
96 #include <sys/xattr.h>
97 #include <sys/fcntl.h>
98 #include <sys/fsctl.h>
99 #include <sys/ubc_internal.h>
100 #include <sys/disk.h>
101 #include <machine/cons.h>
102 #include <machine/limits.h>
103 #include <miscfs/specfs/specdev.h>
104 #include <miscfs/union/union.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>
113 #include <vm/vm_pageout.h>
115 #include <libkern/OSAtomic.h>
116 #include <pexpert/pexpert.h>
119 #include <security/mac.h>
120 #include <security/mac_framework.h>
124 #define GET_PATH(x) \
125 (x) = get_pathbuff();
126 #define RELEASE_PATH(x) \
129 #define GET_PATH(x) \
130 MALLOC_ZONE((x), char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
131 #define RELEASE_PATH(x) \
132 FREE_ZONE((x), MAXPATHLEN, M_NAMEI);
133 #endif /* CONFIG_FSE */
135 /* struct for checkdirs iteration */
140 /* callback for checkdirs iteration */
141 static int checkdirs_callback(proc_t p
, void * arg
);
143 static int change_dir(struct nameidata
*ndp
, vfs_context_t ctx
);
144 static int checkdirs(vnode_t olddp
, vfs_context_t ctx
);
145 void enablequotas(struct mount
*mp
, vfs_context_t ctx
);
146 static int getfsstat_callback(mount_t mp
, void * arg
);
147 static int getutimes(user_addr_t usrtvp
, struct timespec
*tsp
);
148 static int setutimes(vfs_context_t ctx
, vnode_t vp
, const struct timespec
*ts
, int nullflag
);
149 static int sync_callback(mount_t
, void *);
150 static int munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
151 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
152 boolean_t partial_copy
);
153 static int statfs64_common(struct mount
*mp
, struct vfsstatfs
*sfsp
,
155 static int fsync_common(proc_t p
, struct fsync_args
*uap
, int flags
);
157 #ifdef CONFIG_IMGSRC_ACCESS
158 static int prepare_coveredvp(vnode_t vp
, vfs_context_t ctx
, struct componentname
*cnp
, const char *fsname
);
159 static int authorize_devpath_and_update_mntfromname(mount_t mp
, user_addr_t devpath
, vnode_t
*devvpp
, vfs_context_t ctx
);
160 static int place_mount_and_checkdirs(mount_t mp
, vnode_t vp
, vfs_context_t ctx
);
161 static void undo_place_on_covered_vp(mount_t mp
, vnode_t vp
);
162 static int mount_begin_update(mount_t mp
, vfs_context_t ctx
, int flags
);
163 static void mount_end_update(mount_t mp
);
164 static int relocate_imageboot_source(vnode_t vp
, struct componentname
*cnp
, const char *fsname
, vfs_context_t ctx
, boolean_t is64bit
, user_addr_t fsmountargs
);
165 #endif /* CONFIG_IMGSRC_ACCESS */
167 int (*union_dircheckp
)(struct vnode
**, struct fileproc
*, vfs_context_t
);
170 int sync_internal(void);
173 int open1(vfs_context_t
, struct nameidata
*, int, struct vnode_attr
*, int32_t *);
176 int unlink1(vfs_context_t
, struct nameidata
*, int);
179 #ifdef __APPLE_API_OBSOLETE
181 int fd
; /* file descriptor of the target file */
182 struct vstat
*vsb
; /* vstat structure for returned info */
185 const char *path
; /* pathname of the target file */
186 struct vstat
*vsb
; /* vstat structure for returned info */
188 struct mkcomplex_args
{
189 const char *path
; /* pathname of the file to be created */
190 mode_t mode
; /* access mode for the newly created file */
191 u_int32_t type
; /* format of the complex file */
194 const char *path
; /* pathname of the target file */
195 struct vstat
*vsb
; /* vstat structure for returned info */
198 int fstatv(proc_t p
, struct fstatv_args
*uap
, int32_t *retval
);
199 int lstatv(proc_t p
, struct lstatv_args
*uap
, int32_t *retval
);
200 int mkcomplex(proc_t p
, struct mkcomplex_args
*uap
, int32_t *retval
);
201 int statv(proc_t p
, struct statv_args
*uap
, int32_t *retval
);
203 #endif /* __APPLE_API_OBSOLETE */
206 * incremented each time a mount or unmount operation occurs
207 * used to invalidate the cached value of the rootvp in the
208 * mount structure utilized by cache_lookup_path
210 uint32_t mount_generation
= 0;
212 /* counts number of mount and unmount operations */
213 unsigned int vfs_nummntops
=0;
215 extern struct fileops vnops
;
216 extern errno_t
rmdir_remove_orphaned_appleDouble(vnode_t
, vfs_context_t
, int *);
220 * Virtual File System System Calls
224 * Mount a file system.
228 mount(proc_t p
, struct mount_args
*uap
, __unused
int32_t *retval
)
230 struct __mac_mount_args muap
;
232 muap
.type
= uap
->type
;
233 muap
.path
= uap
->path
;
234 muap
.flags
= uap
->flags
;
235 muap
.data
= uap
->data
;
236 muap
.mac_p
= USER_ADDR_NULL
;
237 return (__mac_mount(p
, &muap
, retval
));
242 * Mount a file system taking into account MAC label behavior.
243 * See mount(2) man page for more information
245 * Parameters: p Process requesting the mount
246 * uap User argument descriptor (see below)
249 * Indirect: uap->type Filesystem type
250 * uap->path Path to mount
251 * uap->data Mount arguments
252 * uap->mac_p MAC info
253 * uap->flags Mount flags
260 __mac_mount(struct proc
*p
, register struct __mac_mount_args
*uap
, __unused
int32_t *retval
)
262 struct vnode
*vp
, *pvp
;
263 struct vnode
*devvp
= NULLVP
;
264 struct vnode
*device_vnode
= NULLVP
;
269 struct vfstable
*vfsp
= (struct vfstable
*)0;
271 struct vnode_attr va
;
272 vfs_context_t ctx
= vfs_context_current();
274 struct nameidata nd1
;
275 char fstypename
[MFSNAMELEN
];
277 user_addr_t devpath
= USER_ADDR_NULL
;
278 user_addr_t fsmountargs
= uap
->data
;
281 boolean_t vfsp_ref
= FALSE
;
284 boolean_t is_rwlock_locked
= FALSE
;
285 boolean_t did_rele
= FALSE
;
286 boolean_t have_usecount
= FALSE
;
288 AUDIT_ARG(fflags
, uap
->flags
);
290 is_64bit
= proc_is64bit(p
);
293 * Get vnode to be covered
295 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
| WANTPARENT
,
296 UIO_USERSPACE
, uap
->path
, ctx
);
303 if ((vp
->v_flag
& VROOT
) &&
304 (vp
->v_mount
->mnt_flag
& MNT_ROOTFS
))
305 uap
->flags
|= MNT_UPDATE
;
307 error
= copyinstr(uap
->type
, fstypename
, MFSNAMELEN
, &dummy
);
311 #ifdef CONFIG_IMGSRC_ACCESS
312 if (uap
->flags
== MNT_IMGSRC
) {
313 error
= relocate_imageboot_source(vp
, &nd
.ni_cnd
, fstypename
, ctx
, is_64bit
, fsmountargs
);
318 #endif /* CONFIG_IMGSRC_ACCESS */
320 if (uap
->flags
& MNT_UPDATE
) {
321 if ((vp
->v_flag
& VROOT
) == 0) {
327 /* unmount in progress return error */
329 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
335 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
336 is_rwlock_locked
= TRUE
;
338 * We only allow the filesystem to be reloaded if it
339 * is currently mounted read-only.
341 if ((uap
->flags
& MNT_RELOAD
) &&
342 ((mp
->mnt_flag
& MNT_RDONLY
) == 0)) {
347 #ifdef CONFIG_IMGSRC_ACCESS
348 /* Can't downgrade the backer of the root FS */
349 if ((mp
->mnt_kern_flag
& MNTK_BACKS_ROOT
) &&
350 (!vfs_isrdonly(mp
)) && (uap
->flags
& MNT_RDONLY
))
355 #endif /* CONFIG_IMGSRC_ACCESS */
358 * Only root, or the user that did the original mount is
359 * permitted to update it.
361 if (mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(vfs_context_ucred(ctx
)) &&
362 (error
= suser(vfs_context_ucred(ctx
), &p
->p_acflag
))) {
366 error
= mac_mount_check_remount(ctx
, mp
);
368 lck_rw_done(&mp
->mnt_rwlock
);
373 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV,
374 * and MNT_NOEXEC if mount point is already MNT_NOEXEC.
376 if (suser(vfs_context_ucred(ctx
), NULL
)) {
377 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
378 if (mp
->mnt_flag
& MNT_NOEXEC
)
379 uap
->flags
|= MNT_NOEXEC
;
384 uap
->flags
& (MNT_RELOAD
| MNT_FORCE
| MNT_UPDATE
);
386 vfsp
= mp
->mnt_vtable
;
390 * If the user is not root, ensure that they own the directory
391 * onto which we are attempting to mount.
394 VATTR_WANTED(&va
, va_uid
);
395 if ((error
= vnode_getattr(vp
, &va
, ctx
)) ||
396 (va
.va_uid
!= kauth_cred_getuid(vfs_context_ucred(ctx
)) &&
397 (error
= suser(vfs_context_ucred(ctx
), &p
->p_acflag
)))) {
401 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV, and
402 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
404 if (suser(vfs_context_ucred(ctx
), NULL
)) {
405 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
406 if (vp
->v_mount
->mnt_flag
& MNT_NOEXEC
)
407 uap
->flags
|= MNT_NOEXEC
;
409 if ( (error
= VNOP_FSYNC(vp
, MNT_WAIT
, ctx
)) )
412 if ( (error
= buf_invalidateblks(vp
, BUF_WRITE_DATA
, 0, 0)) )
415 if (vp
->v_type
!= VDIR
) {
420 /* XXXAUDIT: Should we capture the type on the error path as well? */
421 AUDIT_ARG(text
, fstypename
);
423 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
424 if (!strncmp(vfsp
->vfc_name
, fstypename
, MFSNAMELEN
)) {
425 vfsp
->vfc_refcount
++;
435 error
= mac_mount_check_mount(ctx
, vp
,
436 &nd
.ni_cnd
, vfsp
->vfc_name
);
440 if (ISSET(vp
->v_flag
, VMOUNT
) && (vp
->v_mountedhere
!= NULL
)) {
445 SET(vp
->v_flag
, VMOUNT
);
449 * Allocate and initialize the filesystem.
451 MALLOC_ZONE(mp
, struct mount
*, (u_int32_t
)sizeof(struct mount
),
453 bzero((char *)mp
, (u_int32_t
)sizeof(struct mount
));
456 /* Initialize the default IO constraints */
457 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
458 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
459 mp
->mnt_maxsegreadsize
= mp
->mnt_maxreadcnt
;
460 mp
->mnt_maxsegwritesize
= mp
->mnt_maxwritecnt
;
461 mp
->mnt_devblocksize
= DEV_BSIZE
;
462 mp
->mnt_alignmentmask
= PAGE_MASK
;
463 mp
->mnt_ioqueue_depth
= MNT_DEFAULT_IOQUEUE_DEPTH
;
466 mp
->mnt_realrootvp
= NULLVP
;
467 mp
->mnt_authcache_ttl
= CACHED_LOOKUP_RIGHT_TTL
;
469 TAILQ_INIT(&mp
->mnt_vnodelist
);
470 TAILQ_INIT(&mp
->mnt_workerqueue
);
471 TAILQ_INIT(&mp
->mnt_newvnodes
);
473 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
474 is_rwlock_locked
= TRUE
;
475 mp
->mnt_op
= vfsp
->vfc_vfsops
;
476 mp
->mnt_vtable
= vfsp
;
477 //mp->mnt_stat.f_type = vfsp->vfc_typenum;
478 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
479 strncpy(mp
->mnt_vfsstat
.f_fstypename
, vfsp
->vfc_name
, MFSTYPENAMELEN
);
480 strncpy(mp
->mnt_vfsstat
.f_mntonname
, nd
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
481 mp
->mnt_vnodecovered
= vp
;
482 mp
->mnt_vfsstat
.f_owner
= kauth_cred_getuid(vfs_context_ucred(ctx
));
483 mp
->mnt_devbsdunit
= LOWPRI_MAX_NUM_DEV
- 1;
485 /* XXX 3762912 hack to support HFS filesystem 'owner' - filesystem may update later */
486 vfs_setowner(mp
, KAUTH_UID_NONE
, KAUTH_GID_NONE
);
490 * Set the mount level flags.
492 if (uap
->flags
& MNT_RDONLY
)
493 mp
->mnt_flag
|= MNT_RDONLY
;
494 else if (mp
->mnt_flag
& MNT_RDONLY
)
495 mp
->mnt_kern_flag
|= MNTK_WANTRDWR
;
496 mp
->mnt_flag
&= ~(MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
497 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
498 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
|
499 MNT_DEFWRITE
| MNT_NOATIME
| MNT_QUARANTINE
);
500 mp
->mnt_flag
|= uap
->flags
& (MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
501 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
502 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
|
503 MNT_DEFWRITE
| MNT_NOATIME
| MNT_QUARANTINE
);
506 if (uap
->flags
& MNT_MULTILABEL
) {
507 if (vfsp
->vfc_vfsflags
& VFC_VFSNOMACLABEL
) {
511 mp
->mnt_flag
|= MNT_MULTILABEL
;
515 if (vfsp
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
517 if ( (error
= copyin(fsmountargs
, (caddr_t
)&devpath
, sizeof(devpath
))) )
519 fsmountargs
+= sizeof(devpath
);
522 if ( (error
= copyin(fsmountargs
, (caddr_t
)&tmp
, sizeof(tmp
))) )
524 /* munge into LP64 addr */
525 devpath
= CAST_USER_ADDR_T(tmp
);
526 fsmountargs
+= sizeof(tmp
);
529 /* if it is not update and device name needs to be parsed */
531 NDINIT(&nd1
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, devpath
, ctx
);
532 if ( (error
= namei(&nd1
)) )
535 strncpy(mp
->mnt_vfsstat
.f_mntfromname
, nd1
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
540 if (devvp
->v_type
!= VBLK
) {
544 if (major(devvp
->v_rdev
) >= nblkdev
) {
549 * If mount by non-root, then verify that user has necessary
550 * permissions on the device.
552 if (suser(vfs_context_ucred(ctx
), NULL
) != 0) {
553 accessmode
= KAUTH_VNODE_READ_DATA
;
554 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
555 accessmode
|= KAUTH_VNODE_WRITE_DATA
;
556 if ((error
= vnode_authorize(devvp
, NULL
, accessmode
, ctx
)) != 0)
560 if (devpath
&& ((uap
->flags
& MNT_UPDATE
) == 0)) {
561 if ( (error
= vnode_ref(devvp
)) )
564 * Disallow multiple mounts of the same device.
565 * Disallow mounting of a device that is currently in use
566 * (except for root, which might share swap device for miniroot).
567 * Flush out any old buffers remaining from a previous use.
569 if ( (error
= vfs_mountedon(devvp
)) )
572 if (vcount(devvp
) > 1 && !(vfs_flags(mp
) & MNT_ROOTFS
)) {
576 if ( (error
= VNOP_FSYNC(devvp
, MNT_WAIT
, ctx
)) ) {
580 if ( (error
= buf_invalidateblks(devvp
, BUF_WRITE_DATA
, 0, 0)) )
583 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
585 error
= mac_vnode_check_open(ctx
,
587 ronly
? FREAD
: FREAD
|FWRITE
);
591 if ( (error
= VNOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, ctx
)) )
594 mp
->mnt_devvp
= devvp
;
595 device_vnode
= devvp
;
597 if ((mp
->mnt_flag
& MNT_RDONLY
) && (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)) {
601 * If upgrade to read-write by non-root, then verify
602 * that user has necessary permissions on the device.
604 device_vnode
= mp
->mnt_devvp
;
607 vnode_getalways(device_vnode
);
609 if (suser(vfs_context_ucred(ctx
), NULL
)) {
610 if ((error
= vnode_authorize(device_vnode
, NULL
,
611 KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, ctx
)) != 0) {
612 vnode_put(device_vnode
);
617 /* Tell the device that we're upgrading */
618 dev
= (dev_t
)device_vnode
->v_rdev
;
621 if ((u_int
)maj
>= (u_int
)nblkdev
)
622 panic("Volume mounted on a device with invalid major number.\n");
624 error
= bdevsw
[maj
].d_open(dev
, FREAD
| FWRITE
, S_IFBLK
, p
);
626 vnode_put(device_vnode
);
632 device_vnode
= NULLVP
;
636 if ((uap
->flags
& MNT_UPDATE
) == 0) {
637 mac_mount_label_init(mp
);
638 mac_mount_label_associate(ctx
, mp
);
640 if (uap
->mac_p
!= USER_ADDR_NULL
) {
642 char *labelstr
= NULL
;
645 if ((uap
->flags
& MNT_UPDATE
) != 0) {
646 error
= mac_mount_check_label_update(
652 error
= copyin(uap
->mac_p
, &mac
, sizeof(mac
));
655 error
= copyin(uap
->mac_p
, &mac32
, sizeof(mac32
));
656 mac
.m_buflen
= mac32
.m_buflen
;
657 mac
.m_string
= CAST_USER_ADDR_T(mac32
.m_string
);
661 if ((mac
.m_buflen
> MAC_MAX_LABEL_BUF_LEN
) ||
662 (mac
.m_buflen
< 2)) {
666 MALLOC(labelstr
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
667 error
= copyinstr(mac
.m_string
, labelstr
, mac
.m_buflen
, &ulen
);
669 FREE(labelstr
, M_MACTEMP
);
672 AUDIT_ARG(mac_string
, labelstr
);
673 error
= mac_mount_label_internalize(mp
->mnt_mntlabel
, labelstr
);
674 FREE(labelstr
, M_MACTEMP
);
679 if (device_vnode
!= NULL
) {
680 VNOP_IOCTL(device_vnode
, DKIOCGETBSDUNIT
, (caddr_t
)&mp
->mnt_devbsdunit
, 0, NULL
);
681 mp
->mnt_devbsdunit
%= LOWPRI_MAX_NUM_DEV
;
685 * Mount the filesystem.
687 error
= VFS_MOUNT(mp
, device_vnode
, fsmountargs
, ctx
);
689 if (uap
->flags
& MNT_UPDATE
) {
690 if (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)
691 mp
->mnt_flag
&= ~MNT_RDONLY
;
693 (MNT_UPDATE
| MNT_RELOAD
| MNT_FORCE
);
694 mp
->mnt_kern_flag
&=~ MNTK_WANTRDWR
;
697 vfs_event_signal(NULL
, VQ_UPDATE
, (intptr_t)NULL
);
698 lck_rw_done(&mp
->mnt_rwlock
);
699 is_rwlock_locked
= FALSE
;
701 enablequotas(mp
, ctx
);
705 * Put the new filesystem on the mount list after root.
708 struct vfs_attr vfsattr
;
710 if (vfs_flags(mp
) & MNT_MULTILABEL
) {
711 error
= VFS_ROOT(mp
, &rvp
, ctx
);
713 printf("%s() VFS_ROOT returned %d\n", __func__
, error
);
716 error
= vnode_label(mp
, NULL
, rvp
, NULL
, 0, ctx
);
718 * drop reference provided by VFS_ROOT
728 CLR(vp
->v_flag
, VMOUNT
);
729 vp
->v_mountedhere
= mp
;
733 * taking the name_cache_lock exclusively will
734 * insure that everyone is out of the fast path who
735 * might be trying to use a now stale copy of
736 * vp->v_mountedhere->mnt_realrootvp
737 * bumping mount_generation causes the cached values
744 error
= vnode_ref(vp
);
749 have_usecount
= TRUE
;
751 error
= checkdirs(vp
, ctx
);
753 /* Unmount the filesystem as cdir/rdirs cannot be updated */
757 * there is no cleanup code here so I have made it void
758 * we need to revisit this
760 (void)VFS_START(mp
, 0, ctx
);
762 error
= mount_list_add(mp
);
767 lck_rw_done(&mp
->mnt_rwlock
);
768 is_rwlock_locked
= FALSE
;
770 /* Check if this mounted file system supports EAs or named streams. */
771 /* Skip WebDAV file systems for now since they hang in VFS_GETATTR here. */
772 VFSATTR_INIT(&vfsattr
);
773 VFSATTR_WANTED(&vfsattr
, f_capabilities
);
774 if (strncmp(mp
->mnt_vfsstat
.f_fstypename
, "webdav", sizeof("webdav")) != 0 &&
775 vfs_getattr(mp
, &vfsattr
, ctx
) == 0 &&
776 VFSATTR_IS_SUPPORTED(&vfsattr
, f_capabilities
)) {
777 if ((vfsattr
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] & VOL_CAP_INT_EXTENDED_ATTR
) &&
778 (vfsattr
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] & VOL_CAP_INT_EXTENDED_ATTR
)) {
779 mp
->mnt_kern_flag
|= MNTK_EXTENDED_ATTRS
;
782 if ((vfsattr
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] & VOL_CAP_INT_NAMEDSTREAMS
) &&
783 (vfsattr
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] & VOL_CAP_INT_NAMEDSTREAMS
)) {
784 mp
->mnt_kern_flag
|= MNTK_NAMED_STREAMS
;
787 /* Check if this file system supports path from id lookups. */
788 if ((vfsattr
.f_capabilities
.capabilities
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_PATH_FROM_ID
) &&
789 (vfsattr
.f_capabilities
.valid
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_PATH_FROM_ID
)) {
790 mp
->mnt_kern_flag
|= MNTK_PATH_FROM_ID
;
791 } else if (mp
->mnt_flag
& MNT_DOVOLFS
) {
792 /* Legacy MNT_DOVOLFS flag also implies path from id lookups. */
793 mp
->mnt_kern_flag
|= MNTK_PATH_FROM_ID
;
796 if (mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSNATIVEXATTR
) {
797 mp
->mnt_kern_flag
|= MNTK_EXTENDED_ATTRS
;
799 if (mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSPREFLIGHT
) {
800 mp
->mnt_kern_flag
|= MNTK_UNMOUNT_PREFLIGHT
;
802 /* increment the operations count */
803 OSAddAtomic(1, &vfs_nummntops
);
804 enablequotas(mp
, ctx
);
807 device_vnode
->v_specflags
|= SI_MOUNTEDON
;
810 * cache the IO attributes for the underlying physical media...
811 * an error return indicates the underlying driver doesn't
812 * support all the queries necessary... however, reasonable
813 * defaults will have been set, so no reason to bail or care
815 vfs_init_io_attributes(device_vnode
, mp
);
818 /* Now that mount is setup, notify the listeners */
819 vfs_event_signal(NULL
, VQ_MOUNT
, (intptr_t)NULL
);
822 CLR(vp
->v_flag
, VMOUNT
);
825 mp
->mnt_vtable
->vfc_refcount
--;
829 vnode_rele(device_vnode
);
830 VNOP_CLOSE(device_vnode
, ronly
? FREAD
: FREAD
|FWRITE
, ctx
);
832 lck_rw_done(&mp
->mnt_rwlock
);
833 is_rwlock_locked
= FALSE
;
834 mount_lock_destroy(mp
);
836 mac_mount_label_destroy(mp
);
838 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
843 * drop I/O count on covered 'vp' and
844 * on the device vp if there was one
846 if (devpath
&& devvp
)
850 /* Note that we've changed something in the parent directory */
851 post_event_if_success(pvp
, error
, NOTE_WRITE
);
857 (void)VFS_UNMOUNT(mp
, MNT_FORCE
, ctx
);
858 if (device_vnode
!= NULLVP
) {
859 vnode_rele(device_vnode
);
860 VNOP_CLOSE(device_vnode
, mp
->mnt_flag
& MNT_RDONLY
? FREAD
: FREAD
|FWRITE
,
865 vp
->v_mountedhere
= (mount_t
) 0;
872 if (devpath
&& ((uap
->flags
& MNT_UPDATE
) == 0) && (!did_rele
))
875 if (devpath
&& devvp
)
878 /* Release mnt_rwlock only when it was taken */
879 if (is_rwlock_locked
== TRUE
) {
880 lck_rw_done(&mp
->mnt_rwlock
);
884 mac_mount_label_destroy(mp
);
886 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
891 vfsp
->vfc_refcount
--;
901 #ifdef CONFIG_IMGSRC_ACCESS
903 * Flush in-core data, check for competing mount attempts,
907 prepare_coveredvp(vnode_t vp
, vfs_context_t ctx
, struct componentname
*cnp
, const char *fsname
)
909 struct vnode_attr va
;
913 * If the user is not root, ensure that they own the directory
914 * onto which we are attempting to mount.
917 VATTR_WANTED(&va
, va_uid
);
918 if ((error
= vnode_getattr(vp
, &va
, ctx
)) ||
919 (va
.va_uid
!= kauth_cred_getuid(vfs_context_ucred(ctx
)) &&
920 (!vfs_context_issuser(ctx
)))) {
925 if ( (error
= VNOP_FSYNC(vp
, MNT_WAIT
, ctx
)) )
928 if ( (error
= buf_invalidateblks(vp
, BUF_WRITE_DATA
, 0, 0)) )
931 if (vp
->v_type
!= VDIR
) {
936 if (ISSET(vp
->v_flag
, VMOUNT
) && (vp
->v_mountedhere
!= NULL
)) {
942 error
= mac_mount_check_mount(ctx
, vp
,
949 SET(vp
->v_flag
, VMOUNT
);
957 authorize_devpath_and_update_mntfromname(mount_t mp
, user_addr_t devpath
, vnode_t
*devvpp
, vfs_context_t ctx
)
964 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, devpath
, ctx
);
965 if ( (error
= namei(&nd
)) )
968 strncpy(mp
->mnt_vfsstat
.f_mntfromname
, nd
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
972 if (vp
->v_type
!= VBLK
) {
976 if (major(vp
->v_rdev
) >= nblkdev
) {
981 * If mount by non-root, then verify that user has necessary
982 * permissions on the device.
984 if (!vfs_context_issuser(ctx
)) {
985 accessmode
= KAUTH_VNODE_READ_DATA
;
986 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
987 accessmode
|= KAUTH_VNODE_WRITE_DATA
;
988 if ((error
= vnode_authorize(vp
, NULL
, accessmode
, ctx
)) != 0)
1002 * Clear VMOUNT, set v_mountedhere, and mnt_vnodecovered, ref the vnode,
1003 * and call checkdirs()
1006 place_mount_and_checkdirs(mount_t mp
, vnode_t vp
, vfs_context_t ctx
)
1010 mp
->mnt_vnodecovered
= vp
; /* XXX This is normally only set at init-time ... */
1012 vnode_lock_spin(vp
);
1013 CLR(vp
->v_flag
, VMOUNT
);
1014 vp
->v_mountedhere
= mp
;
1018 * taking the name_cache_lock exclusively will
1019 * insure that everyone is out of the fast path who
1020 * might be trying to use a now stale copy of
1021 * vp->v_mountedhere->mnt_realrootvp
1022 * bumping mount_generation causes the cached values
1027 name_cache_unlock();
1029 error
= vnode_ref(vp
);
1034 error
= checkdirs(vp
, ctx
);
1036 /* Unmount the filesystem as cdir/rdirs cannot be updated */
1043 mp
->mnt_vnodecovered
= NULLVP
;
1049 undo_place_on_covered_vp(mount_t mp
, vnode_t vp
)
1052 vnode_lock_spin(vp
);
1053 vp
->v_mountedhere
= (mount_t
)NULL
;
1056 mp
->mnt_vnodecovered
= NULLVP
;
1060 mount_begin_update(mount_t mp
, vfs_context_t ctx
, int flags
)
1064 /* unmount in progress return error */
1065 mount_lock_spin(mp
);
1066 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
1071 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
1074 * We only allow the filesystem to be reloaded if it
1075 * is currently mounted read-only.
1077 if ((flags
& MNT_RELOAD
) &&
1078 ((mp
->mnt_flag
& MNT_RDONLY
) == 0)) {
1084 * Only root, or the user that did the original mount is
1085 * permitted to update it.
1087 if (mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(vfs_context_ucred(ctx
)) &&
1088 (!vfs_context_issuser(ctx
))) {
1093 error
= mac_mount_check_remount(ctx
, mp
);
1101 lck_rw_done(&mp
->mnt_rwlock
);
1108 mount_end_update(mount_t mp
)
1110 lck_rw_done(&mp
->mnt_rwlock
);
1114 relocate_imageboot_source(vnode_t vp
, struct componentname
*cnp
,
1115 const char *fsname
, vfs_context_t ctx
,
1116 boolean_t is64bit
, user_addr_t fsmountargs
)
1120 boolean_t placed
= FALSE
;
1122 struct vfstable
*vfsp
;
1123 user_addr_t devpath
;
1124 char *old_mntonname
;
1126 /* If we didn't imageboot, nothing to move */
1127 if (imgsrc_rootvnode
== NULLVP
) {
1131 /* Only root can do this */
1132 if (!vfs_context_issuser(ctx
)) {
1136 error
= vnode_get(imgsrc_rootvnode
);
1141 MALLOC(old_mntonname
, char*, MAXPATHLEN
, M_TEMP
, M_WAITOK
);
1143 /* Can only move once */
1144 mp
= vnode_mount(imgsrc_rootvnode
);
1145 if ((mp
->mnt_kern_flag
& MNTK_HAS_MOVED
) == MNTK_HAS_MOVED
) {
1150 /* Get exclusive rwlock on mount, authorize update on mp */
1151 error
= mount_begin_update(mp
, ctx
, 0);
1157 * It can only be moved once. Flag is set under the rwlock,
1158 * so we're now safe to proceed.
1160 if ((mp
->mnt_kern_flag
& MNTK_HAS_MOVED
) == MNTK_HAS_MOVED
) {
1164 /* Mark covered vnode as mount in progress, authorize placing mount on top */
1165 error
= prepare_coveredvp(vp
, ctx
, cnp
, fsname
);
1170 /* Sanity check the name caller has provided */
1171 vfsp
= mp
->mnt_vtable
;
1172 if (strncmp(vfsp
->vfc_name
, fsname
, MFSNAMELEN
) != 0) {
1177 /* Check the device vnode and update mount-from name, for local filesystems */
1178 if (vfsp
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
1180 if ( (error
= copyin(fsmountargs
, (caddr_t
)&devpath
, sizeof(devpath
))) )
1182 fsmountargs
+= sizeof(devpath
);
1185 if ( (error
= copyin(fsmountargs
, (caddr_t
)&tmp
, sizeof(tmp
))) )
1187 /* munge into LP64 addr */
1188 devpath
= CAST_USER_ADDR_T(tmp
);
1189 fsmountargs
+= sizeof(tmp
);
1192 if (devpath
!= USER_ADDR_NULL
) {
1193 error
= authorize_devpath_and_update_mntfromname(mp
, devpath
, &devvp
, ctx
);
1203 * Place mp on top of vnode, ref the vnode, call checkdirs(),
1204 * and increment the name cache's mount generation
1206 error
= place_mount_and_checkdirs(mp
, vp
, ctx
);
1213 strncpy(old_mntonname
, mp
->mnt_vfsstat
.f_mntonname
, MAXPATHLEN
);
1214 strncpy(mp
->mnt_vfsstat
.f_mntonname
, cnp
->cn_pnbuf
, MAXPATHLEN
);
1216 /* Forbid future moves */
1218 mp
->mnt_kern_flag
|= MNTK_HAS_MOVED
;
1221 /* Finally, add to mount list, completely ready to go */
1222 error
= mount_list_add(mp
);
1227 mount_end_update(mp
);
1228 vnode_put(imgsrc_rootvnode
);
1229 FREE(old_mntonname
, M_TEMP
);
1233 strncpy(mp
->mnt_vfsstat
.f_mntonname
, old_mntonname
, MAXPATHLEN
);
1236 mp
->mnt_kern_flag
&= ~(MNTK_HAS_MOVED
);
1241 * Placing the mp on the vnode clears VMOUNT,
1242 * so cleanup is different after that point
1245 /* Rele the vp, clear VMOUNT and v_mountedhere */
1246 undo_place_on_covered_vp(mp
, vp
);
1248 vnode_lock_spin(vp
);
1249 CLR(vp
->v_flag
, VMOUNT
);
1253 mount_end_update(mp
);
1256 vnode_put(imgsrc_rootvnode
);
1257 FREE(old_mntonname
, M_TEMP
);
1261 #endif /* CONFIG_IMGSRC_ACCESS */
1264 enablequotas(struct mount
*mp
, vfs_context_t ctx
)
1266 struct nameidata qnd
;
1268 char qfpath
[MAXPATHLEN
];
1269 const char *qfname
= QUOTAFILENAME
;
1270 const char *qfopsname
= QUOTAOPSNAME
;
1271 const char *qfextension
[] = INITQFNAMES
;
1273 /* XXX Shoulkd be an MNTK_ flag, instead of strncmp()'s */
1274 if (strncmp(mp
->mnt_vfsstat
.f_fstypename
, "hfs", sizeof("hfs")) != 0 ) {
1278 * Enable filesystem disk quotas if necessary.
1279 * We ignore errors as this should not interfere with final mount
1281 for (type
=0; type
< MAXQUOTAS
; type
++) {
1282 snprintf(qfpath
, sizeof(qfpath
), "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfopsname
, qfextension
[type
]);
1283 NDINIT(&qnd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE
, CAST_USER_ADDR_T(qfpath
), ctx
);
1284 if (namei(&qnd
) != 0)
1285 continue; /* option file to trigger quotas is not present */
1286 vnode_put(qnd
.ni_vp
);
1288 snprintf(qfpath
, sizeof(qfpath
), "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfname
, qfextension
[type
]);
1290 (void) VFS_QUOTACTL(mp
, QCMD(Q_QUOTAON
, type
), 0, qfpath
, ctx
);
1297 checkdirs_callback(proc_t p
, void * arg
)
1299 struct cdirargs
* cdrp
= (struct cdirargs
* )arg
;
1300 vnode_t olddp
= cdrp
->olddp
;
1301 vnode_t newdp
= cdrp
->newdp
;
1302 struct filedesc
*fdp
;
1306 int cdir_changed
= 0;
1307 int rdir_changed
= 0;
1310 * XXX Also needs to iterate each thread in the process to see if it
1311 * XXX is using a per-thread current working directory, and, if so,
1312 * XXX update that as well.
1317 if (fdp
== (struct filedesc
*)0) {
1319 return(PROC_RETURNED
);
1321 fdp_cvp
= fdp
->fd_cdir
;
1322 fdp_rvp
= fdp
->fd_rdir
;
1325 if (fdp_cvp
== olddp
) {
1332 if (fdp_rvp
== olddp
) {
1339 if (cdir_changed
|| rdir_changed
) {
1341 fdp
->fd_cdir
= fdp_cvp
;
1342 fdp
->fd_rdir
= fdp_rvp
;
1345 return(PROC_RETURNED
);
1351 * Scan all active processes to see if any of them have a current
1352 * or root directory onto which the new filesystem has just been
1353 * mounted. If so, replace them with the new mount point.
1356 checkdirs(vnode_t olddp
, vfs_context_t ctx
)
1361 struct cdirargs cdr
;
1362 struct uthread
* uth
= get_bsdthread_info(current_thread());
1364 if (olddp
->v_usecount
== 1)
1366 if (uth
!= (struct uthread
*)0)
1367 uth
->uu_notrigger
= 1;
1368 err
= VFS_ROOT(olddp
->v_mountedhere
, &newdp
, ctx
);
1369 if (uth
!= (struct uthread
*)0)
1370 uth
->uu_notrigger
= 0;
1374 panic("mount: lost mount: error %d", err
);
1381 /* do not block for exec/fork trans as the vp in cwd & rootdir are not changing */
1382 proc_iterate(PROC_ALLPROCLIST
| PROC_NOWAITTRANS
, checkdirs_callback
, (void *)&cdr
, NULL
, NULL
);
1384 if (rootvnode
== olddp
) {
1396 * Unmount a file system.
1398 * Note: unmount takes a path to the vnode mounted on as argument,
1399 * not special file (as before).
1403 unmount(__unused proc_t p
, struct unmount_args
*uap
, __unused
int32_t *retval
)
1408 struct nameidata nd
;
1409 vfs_context_t ctx
= vfs_context_current();
1411 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
1412 UIO_USERSPACE
, uap
->path
, ctx
);
1421 error
= mac_mount_check_umount(ctx
, mp
);
1428 * Must be the root of the filesystem
1430 if ((vp
->v_flag
& VROOT
) == 0) {
1436 /* safedounmount consumes the mount ref */
1437 return (safedounmount(mp
, uap
->flags
, ctx
));
1441 vfs_unmountbyfsid(fsid_t
* fsid
, int flags
, vfs_context_t ctx
)
1445 mp
= mount_list_lookupby_fsid(fsid
, 0, 1);
1446 if (mp
== (mount_t
)0) {
1451 /* safedounmount consumes the mount ref */
1452 return(safedounmount(mp
, flags
, ctx
));
1457 * The mount struct comes with a mount ref which will be consumed.
1458 * Do the actual file system unmount, prevent some common foot shooting.
1461 safedounmount(struct mount
*mp
, int flags
, vfs_context_t ctx
)
1464 proc_t p
= vfs_context_proc(ctx
);
1467 * Only root, or the user that did the original mount is
1468 * permitted to unmount this filesystem.
1470 if ((mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(kauth_cred_get())) &&
1471 (error
= suser(kauth_cred_get(), &p
->p_acflag
)))
1475 * Don't allow unmounting the root file system.
1477 if (mp
->mnt_flag
& MNT_ROOTFS
) {
1478 error
= EBUSY
; /* the root is always busy */
1482 #ifdef CONFIG_IMGSRC_ACCESS
1483 if (mp
->mnt_kern_flag
& MNTK_BACKS_ROOT
) {
1487 #endif /* CONFIG_IMGSRC_ACCESS */
1489 return (dounmount(mp
, flags
, 1, ctx
));
1497 * Do the actual file system unmount.
1500 dounmount(struct mount
*mp
, int flags
, int withref
, vfs_context_t ctx
)
1502 vnode_t coveredvp
= (vnode_t
)0;
1505 int forcedunmount
= 0;
1507 struct vnode
*devvp
= NULLVP
;
1509 if (flags
& MNT_FORCE
)
1512 /* XXX post jaguar fix LK_DRAIN - then clean this up */
1513 if ((flags
& MNT_FORCE
)) {
1514 mp
->mnt_kern_flag
|= MNTK_FRCUNMOUNT
;
1515 mp
->mnt_lflag
|= MNT_LFORCE
;
1517 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
1518 mp
->mnt_lflag
|= MNT_LWAIT
;
1521 msleep((caddr_t
)mp
, &mp
->mnt_mlock
, (PVFS
| PDROP
), "dounmount", NULL
);
1523 * The prior unmount attempt has probably succeeded.
1524 * Do not dereference mp here - returning EBUSY is safest.
1528 mp
->mnt_kern_flag
|= MNTK_UNMOUNT
;
1529 mp
->mnt_lflag
|= MNT_LUNMOUNT
;
1530 mp
->mnt_flag
&=~ MNT_ASYNC
;
1532 * anyone currently in the fast path that
1533 * trips over the cached rootvp will be
1534 * dumped out and forced into the slow path
1535 * to regenerate a new cached value
1537 mp
->mnt_realrootvp
= NULLVP
;
1541 * taking the name_cache_lock exclusively will
1542 * insure that everyone is out of the fast path who
1543 * might be trying to use a now stale copy of
1544 * vp->v_mountedhere->mnt_realrootvp
1545 * bumping mount_generation causes the cached values
1550 name_cache_unlock();
1553 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
1557 fsevent_unmount(mp
); /* has to come first! */
1560 if (forcedunmount
== 0) {
1561 ubc_umount(mp
); /* release cached vnodes */
1562 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
1563 error
= VFS_SYNC(mp
, MNT_WAIT
, ctx
);
1566 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
1567 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
1568 mp
->mnt_lflag
&= ~MNT_LFORCE
;
1575 lflags
|= FORCECLOSE
;
1576 error
= vflush(mp
, NULLVP
, SKIPSWAP
| SKIPSYSTEM
| SKIPROOT
| lflags
);
1577 if ((forcedunmount
== 0) && error
) {
1579 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
1580 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
1581 mp
->mnt_lflag
&= ~MNT_LFORCE
;
1585 /* make sure there are no one in the mount iterations or lookup */
1586 mount_iterdrain(mp
);
1588 error
= VFS_UNMOUNT(mp
, flags
, ctx
);
1590 mount_iterreset(mp
);
1592 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
1593 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
1594 mp
->mnt_lflag
&= ~MNT_LFORCE
;
1598 /* increment the operations count */
1600 OSAddAtomic(1, &vfs_nummntops
);
1602 if ( mp
->mnt_devvp
&& mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
1603 /* hold an io reference and drop the usecount before close */
1604 devvp
= mp
->mnt_devvp
;
1605 vnode_getalways(devvp
);
1607 VNOP_CLOSE(devvp
, mp
->mnt_flag
& MNT_RDONLY
? FREAD
: FREAD
|FWRITE
,
1609 vnode_clearmountedon(devvp
);
1612 lck_rw_done(&mp
->mnt_rwlock
);
1613 mount_list_remove(mp
);
1614 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
1616 /* mark the mount point hook in the vp but not drop the ref yet */
1617 if ((coveredvp
= mp
->mnt_vnodecovered
) != NULLVP
) {
1618 vnode_getwithref(coveredvp
);
1619 vnode_lock_spin(coveredvp
);
1620 coveredvp
->v_mountedhere
= (struct mount
*)0;
1621 vnode_unlock(coveredvp
);
1622 vnode_put(coveredvp
);
1626 mp
->mnt_vtable
->vfc_refcount
--;
1627 mount_list_unlock();
1629 cache_purgevfs(mp
); /* remove cache entries for this file sys */
1630 vfs_event_signal(NULL
, VQ_UNMOUNT
, (intptr_t)NULL
);
1632 mp
->mnt_lflag
|= MNT_LDEAD
;
1634 if (mp
->mnt_lflag
& MNT_LWAIT
) {
1636 * do the wakeup here
1637 * in case we block in mount_refdrain
1638 * which will drop the mount lock
1639 * and allow anyone blocked in vfs_busy
1640 * to wakeup and see the LDEAD state
1642 mp
->mnt_lflag
&= ~MNT_LWAIT
;
1643 wakeup((caddr_t
)mp
);
1647 if (mp
->mnt_lflag
& MNT_LWAIT
) {
1648 mp
->mnt_lflag
&= ~MNT_LWAIT
;
1652 lck_rw_done(&mp
->mnt_rwlock
);
1655 wakeup((caddr_t
)mp
);
1657 if ((coveredvp
!= NULLVP
)) {
1660 vnode_getwithref(coveredvp
);
1661 pvp
= vnode_getparent(coveredvp
);
1662 vnode_rele(coveredvp
);
1663 vnode_lock_spin(coveredvp
);
1664 if(mp
->mnt_crossref
== 0) {
1665 vnode_unlock(coveredvp
);
1666 mount_lock_destroy(mp
);
1668 mac_mount_label_destroy(mp
);
1670 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
1672 coveredvp
->v_lflag
|= VL_MOUNTDEAD
;
1673 vnode_unlock(coveredvp
);
1675 vnode_put(coveredvp
);
1678 lock_vnode_and_post(pvp
, NOTE_WRITE
);
1681 } else if (mp
->mnt_flag
& MNT_ROOTFS
) {
1682 mount_lock_destroy(mp
);
1684 mac_mount_label_destroy(mp
);
1686 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
1688 panic("dounmount: no coveredvp");
1694 mount_dropcrossref(mount_t mp
, vnode_t dp
, int need_put
)
1698 if (mp
->mnt_crossref
< 0)
1699 panic("mount cross refs -ve");
1700 if (((dp
->v_lflag
& VL_MOUNTDEAD
) == VL_MOUNTDEAD
) && (mp
->mnt_crossref
== 0)) {
1701 dp
->v_lflag
&= ~VL_MOUNTDEAD
;
1703 vnode_put_locked(dp
);
1705 mount_lock_destroy(mp
);
1707 mac_mount_label_destroy(mp
);
1709 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
1713 vnode_put_locked(dp
);
1719 * Sync each mounted filesystem.
1723 struct ctldebug debug0
= { "syncprt", &syncprt
};
1726 int print_vmpage_stat
=0;
1729 sync_callback(mount_t mp
, void * arg
)
1733 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
1734 asyncflag
= mp
->mnt_flag
& MNT_ASYNC
;
1735 mp
->mnt_flag
&= ~MNT_ASYNC
;
1736 VFS_SYNC(mp
, arg
? MNT_WAIT
: MNT_NOWAIT
, vfs_context_current());
1738 mp
->mnt_flag
|= MNT_ASYNC
;
1740 return(VFS_RETURNED
);
1744 #include <kern/clock.h>
1746 clock_sec_t sync_wait_time
= 0;
1750 sync(__unused proc_t p
, __unused
struct sync_args
*uap
, __unused
int32_t *retval
)
1754 vfs_iterate(LK_NOWAIT
, sync_callback
, (void *)0);
1757 static fsid_t fsid
= { { 0, 0 } };
1759 clock_get_calendar_microtime(&sync_wait_time
, &nsecs
);
1760 vfs_event_signal(&fsid
, VQ_SYNCEVENT
, (intptr_t)NULL
);
1761 wakeup((caddr_t
)&sync_wait_time
);
1765 if(print_vmpage_stat
) {
1766 vm_countdirtypages();
1772 #endif /* DIAGNOSTIC */
1777 * Change filesystem quotas.
1780 static int quotactl_funneled(proc_t p
, struct quotactl_args
*uap
, int32_t *retval
);
1783 quotactl(proc_t p
, struct quotactl_args
*uap
, int32_t *retval
)
1785 boolean_t funnel_state
;
1788 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
1789 error
= quotactl_funneled(p
, uap
, retval
);
1790 thread_funnel_set(kernel_flock
, funnel_state
);
1795 quotactl_funneled(proc_t p
, struct quotactl_args
*uap
, __unused
int32_t *retval
)
1798 int error
, quota_cmd
, quota_status
;
1801 struct nameidata nd
;
1802 vfs_context_t ctx
= vfs_context_current();
1803 struct dqblk my_dqblk
;
1805 AUDIT_ARG(uid
, uap
->uid
);
1806 AUDIT_ARG(cmd
, uap
->cmd
);
1807 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1808 UIO_USERSPACE
, uap
->path
, ctx
);
1812 mp
= nd
.ni_vp
->v_mount
;
1813 vnode_put(nd
.ni_vp
);
1816 /* copyin any data we will need for downstream code */
1817 quota_cmd
= uap
->cmd
>> SUBCMDSHIFT
;
1819 switch (quota_cmd
) {
1821 /* uap->arg specifies a file from which to take the quotas */
1822 fnamelen
= MAXPATHLEN
;
1823 datap
= kalloc(MAXPATHLEN
);
1824 error
= copyinstr(uap
->arg
, datap
, MAXPATHLEN
, &fnamelen
);
1827 /* uap->arg is a pointer to a dqblk structure. */
1828 datap
= (caddr_t
) &my_dqblk
;
1832 /* uap->arg is a pointer to a dqblk structure. */
1833 datap
= (caddr_t
) &my_dqblk
;
1834 if (proc_is64bit(p
)) {
1835 struct user_dqblk my_dqblk64
;
1836 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk64
, sizeof (my_dqblk64
));
1838 munge_dqblk(&my_dqblk
, &my_dqblk64
, FALSE
);
1842 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk
, sizeof (my_dqblk
));
1846 /* uap->arg is a pointer to an integer */
1847 datap
= (caddr_t
) "a_status
;
1855 error
= VFS_QUOTACTL(mp
, uap
->cmd
, uap
->uid
, datap
, ctx
);
1858 switch (quota_cmd
) {
1861 kfree(datap
, MAXPATHLEN
);
1864 /* uap->arg is a pointer to a dqblk structure we need to copy out to */
1866 if (proc_is64bit(p
)) {
1867 struct user_dqblk my_dqblk64
;
1868 munge_dqblk(&my_dqblk
, &my_dqblk64
, TRUE
);
1869 error
= copyout((caddr_t
)&my_dqblk64
, uap
->arg
, sizeof (my_dqblk64
));
1872 error
= copyout(datap
, uap
->arg
, sizeof (struct dqblk
));
1877 /* uap->arg is a pointer to an integer */
1879 error
= copyout(datap
, uap
->arg
, sizeof(quota_status
));
1890 quotactl(__unused proc_t p
, __unused
struct quotactl_args
*uap
, __unused
int32_t *retval
)
1892 return (EOPNOTSUPP
);
1897 * Get filesystem statistics.
1899 * Returns: 0 Success
1901 * vfs_update_vfsstat:???
1902 * munge_statfs:EFAULT
1906 statfs(__unused proc_t p
, struct statfs_args
*uap
, __unused
int32_t *retval
)
1909 struct vfsstatfs
*sp
;
1911 struct nameidata nd
;
1912 vfs_context_t ctx
= vfs_context_current();
1915 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
1916 UIO_USERSPACE
, uap
->path
, ctx
);
1922 sp
= &mp
->mnt_vfsstat
;
1925 error
= vfs_update_vfsstat(mp
, ctx
, VFS_USER_EVENT
);
1930 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1935 * Get filesystem statistics.
1939 fstatfs(__unused proc_t p
, struct fstatfs_args
*uap
, __unused
int32_t *retval
)
1943 struct vfsstatfs
*sp
;
1946 AUDIT_ARG(fd
, uap
->fd
);
1948 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1951 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
1958 sp
= &mp
->mnt_vfsstat
;
1959 if ((error
= vfs_update_vfsstat(mp
,vfs_context_current(),VFS_USER_EVENT
)) != 0) {
1965 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1971 * Common routine to handle copying of statfs64 data to user space
1974 statfs64_common(struct mount
*mp
, struct vfsstatfs
*sfsp
, user_addr_t bufp
)
1977 struct statfs64 sfs
;
1979 bzero(&sfs
, sizeof(sfs
));
1981 sfs
.f_bsize
= sfsp
->f_bsize
;
1982 sfs
.f_iosize
= (int32_t)sfsp
->f_iosize
;
1983 sfs
.f_blocks
= sfsp
->f_blocks
;
1984 sfs
.f_bfree
= sfsp
->f_bfree
;
1985 sfs
.f_bavail
= sfsp
->f_bavail
;
1986 sfs
.f_files
= sfsp
->f_files
;
1987 sfs
.f_ffree
= sfsp
->f_ffree
;
1988 sfs
.f_fsid
= sfsp
->f_fsid
;
1989 sfs
.f_owner
= sfsp
->f_owner
;
1990 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
1991 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
1992 sfs
.f_fssubtype
= sfsp
->f_fssubtype
;
1993 strlcpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSTYPENAMELEN
);
1994 strlcpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MAXPATHLEN
);
1995 strlcpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MAXPATHLEN
);
1997 error
= copyout((caddr_t
)&sfs
, bufp
, sizeof(sfs
));
2003 * Get file system statistics in 64-bit mode
2006 statfs64(__unused
struct proc
*p
, struct statfs64_args
*uap
, __unused
int32_t *retval
)
2009 struct vfsstatfs
*sp
;
2011 struct nameidata nd
;
2012 vfs_context_t ctxp
= vfs_context_current();
2015 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
2016 UIO_USERSPACE
, uap
->path
, ctxp
);
2022 sp
= &mp
->mnt_vfsstat
;
2025 error
= vfs_update_vfsstat(mp
, ctxp
, VFS_USER_EVENT
);
2030 error
= statfs64_common(mp
, sp
, uap
->buf
);
2036 * Get file system statistics in 64-bit mode
2039 fstatfs64(__unused
struct proc
*p
, struct fstatfs64_args
*uap
, __unused
int32_t *retval
)
2043 struct vfsstatfs
*sp
;
2046 AUDIT_ARG(fd
, uap
->fd
);
2048 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
2051 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
2058 sp
= &mp
->mnt_vfsstat
;
2059 if ((error
= vfs_update_vfsstat(mp
, vfs_context_current(), VFS_USER_EVENT
)) != 0) {
2065 error
= statfs64_common(mp
, sp
, uap
->buf
);
2070 struct getfsstat_struct
{
2081 getfsstat_callback(mount_t mp
, void * arg
)
2084 struct getfsstat_struct
*fstp
= (struct getfsstat_struct
*)arg
;
2085 struct vfsstatfs
*sp
;
2087 vfs_context_t ctx
= vfs_context_current();
2089 if (fstp
->sfsp
&& fstp
->count
< fstp
->maxcount
) {
2090 sp
= &mp
->mnt_vfsstat
;
2092 * If MNT_NOWAIT is specified, do not refresh the
2093 * fsstat cache. MNT_WAIT/MNT_DWAIT overrides MNT_NOWAIT.
2095 if (((fstp
->flags
& MNT_NOWAIT
) == 0 || (fstp
->flags
& (MNT_WAIT
| MNT_DWAIT
))) &&
2096 (error
= vfs_update_vfsstat(mp
, ctx
,
2098 KAUTH_DEBUG("vfs_update_vfsstat returned %d", error
);
2099 return(VFS_RETURNED
);
2103 * Need to handle LP64 version of struct statfs
2105 error
= munge_statfs(mp
, sp
, fstp
->sfsp
, &my_size
, IS_64BIT_PROCESS(vfs_context_proc(ctx
)), FALSE
);
2107 fstp
->error
= error
;
2108 return(VFS_RETURNED_DONE
);
2110 fstp
->sfsp
+= my_size
;
2113 error
= mac_mount_label_get(mp
, *fstp
->mp
);
2115 fstp
->error
= error
;
2116 return(VFS_RETURNED_DONE
);
2122 return(VFS_RETURNED
);
2126 * Get statistics on all filesystems.
2129 getfsstat(__unused proc_t p
, struct getfsstat_args
*uap
, int *retval
)
2131 struct __mac_getfsstat_args muap
;
2133 muap
.buf
= uap
->buf
;
2134 muap
.bufsize
= uap
->bufsize
;
2135 muap
.mac
= USER_ADDR_NULL
;
2137 muap
.flags
= uap
->flags
;
2139 return (__mac_getfsstat(p
, &muap
, retval
));
2143 * __mac_getfsstat: Get MAC-related file system statistics
2145 * Parameters: p (ignored)
2146 * uap User argument descriptor (see below)
2147 * retval Count of file system statistics (N stats)
2149 * Indirect: uap->bufsize Buffer size
2150 * uap->macsize MAC info size
2151 * uap->buf Buffer where information will be returned
2153 * uap->flags File system flags
2156 * Returns: 0 Success
2161 __mac_getfsstat(__unused proc_t p
, struct __mac_getfsstat_args
*uap
, int *retval
)
2165 size_t count
, maxcount
, bufsize
, macsize
;
2166 struct getfsstat_struct fst
;
2168 bufsize
= (size_t) uap
->bufsize
;
2169 macsize
= (size_t) uap
->macsize
;
2171 if (IS_64BIT_PROCESS(p
)) {
2172 maxcount
= bufsize
/ sizeof(struct user64_statfs
);
2175 maxcount
= bufsize
/ sizeof(struct user32_statfs
);
2183 if (uap
->mac
!= USER_ADDR_NULL
) {
2188 count
= (macsize
/ (IS_64BIT_PROCESS(p
) ? 8 : 4));
2189 if (count
!= maxcount
)
2192 /* Copy in the array */
2193 MALLOC(mp0
, u_int32_t
*, macsize
, M_MACTEMP
, M_WAITOK
);
2198 error
= copyin(uap
->mac
, mp0
, macsize
);
2200 FREE(mp0
, M_MACTEMP
);
2204 /* Normalize to an array of user_addr_t */
2205 MALLOC(mp
, user_addr_t
*, count
* sizeof(user_addr_t
), M_MACTEMP
, M_WAITOK
);
2207 FREE(mp0
, M_MACTEMP
);
2211 for (i
= 0; i
< count
; i
++) {
2212 if (IS_64BIT_PROCESS(p
))
2213 mp
[i
] = ((user_addr_t
*)mp0
)[i
];
2215 mp
[i
] = (user_addr_t
)mp0
[i
];
2217 FREE(mp0
, M_MACTEMP
);
2224 fst
.flags
= uap
->flags
;
2227 fst
.maxcount
= maxcount
;
2230 vfs_iterate(0, getfsstat_callback
, &fst
);
2233 FREE(mp
, M_MACTEMP
);
2236 KAUTH_DEBUG("ERROR - %s gets %d", p
->p_comm
, fst
.error
);
2240 if (fst
.sfsp
&& fst
.count
> fst
.maxcount
)
2241 *retval
= fst
.maxcount
;
2243 *retval
= fst
.count
;
2248 getfsstat64_callback(mount_t mp
, void * arg
)
2250 struct getfsstat_struct
*fstp
= (struct getfsstat_struct
*)arg
;
2251 struct vfsstatfs
*sp
;
2254 if (fstp
->sfsp
&& fstp
->count
< fstp
->maxcount
) {
2255 sp
= &mp
->mnt_vfsstat
;
2257 * If MNT_NOWAIT is specified, do not refresh the fsstat
2258 * cache. MNT_WAIT overrides MNT_NOWAIT.
2260 * We treat MNT_DWAIT as MNT_WAIT for all instances of
2261 * getfsstat, since the constants are out of the same
2264 if (((fstp
->flags
& MNT_NOWAIT
) == 0 ||
2265 (fstp
->flags
& (MNT_WAIT
| MNT_DWAIT
))) &&
2266 (error
= vfs_update_vfsstat(mp
, vfs_context_current(), VFS_USER_EVENT
))) {
2267 KAUTH_DEBUG("vfs_update_vfsstat returned %d", error
);
2268 return(VFS_RETURNED
);
2271 error
= statfs64_common(mp
, sp
, fstp
->sfsp
);
2273 fstp
->error
= error
;
2274 return(VFS_RETURNED_DONE
);
2276 fstp
->sfsp
+= sizeof(struct statfs64
);
2279 return(VFS_RETURNED
);
2283 * Get statistics on all file systems in 64 bit mode.
2286 getfsstat64(__unused proc_t p
, struct getfsstat64_args
*uap
, int *retval
)
2289 int count
, maxcount
;
2290 struct getfsstat_struct fst
;
2292 maxcount
= uap
->bufsize
/ sizeof(struct statfs64
);
2298 fst
.flags
= uap
->flags
;
2301 fst
.maxcount
= maxcount
;
2303 vfs_iterate(0, getfsstat64_callback
, &fst
);
2306 KAUTH_DEBUG("ERROR - %s gets %d", p
->p_comm
, fst
.error
);
2310 if (fst
.sfsp
&& fst
.count
> fst
.maxcount
)
2311 *retval
= fst
.maxcount
;
2313 *retval
= fst
.count
;
2319 * Change current working directory to a given file descriptor.
2323 common_fchdir(proc_t p
, struct fchdir_args
*uap
, int per_thread
)
2325 struct filedesc
*fdp
= p
->p_fd
;
2331 vfs_context_t ctx
= vfs_context_current();
2333 AUDIT_ARG(fd
, uap
->fd
);
2334 if (per_thread
&& uap
->fd
== -1) {
2336 * Switching back from per-thread to per process CWD; verify we
2337 * in fact have one before proceeding. The only success case
2338 * for this code path is to return 0 preemptively after zapping
2339 * the thread structure contents.
2341 thread_t th
= vfs_context_thread(ctx
);
2343 uthread_t uth
= get_bsdthread_info(th
);
2345 uth
->uu_cdir
= NULLVP
;
2346 if (tvp
!= NULLVP
) {
2354 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
2356 if ( (error
= vnode_getwithref(vp
)) ) {
2361 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2363 if (vp
->v_type
!= VDIR
) {
2369 error
= mac_vnode_check_chdir(ctx
, vp
);
2373 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, ctx
);
2377 while (!error
&& (mp
= vp
->v_mountedhere
) != NULL
) {
2378 if (vfs_busy(mp
, LK_NOWAIT
)) {
2382 error
= VFS_ROOT(mp
, &tdp
, ctx
);
2391 if ( (error
= vnode_ref(vp
)) )
2396 thread_t th
= vfs_context_thread(ctx
);
2398 uthread_t uth
= get_bsdthread_info(th
);
2401 OSBitOrAtomic(P_THCWD
, &p
->p_flag
);
2426 fchdir(proc_t p
, struct fchdir_args
*uap
, __unused
int32_t *retval
)
2428 return common_fchdir(p
, uap
, 0);
2432 __pthread_fchdir(proc_t p
, struct __pthread_fchdir_args
*uap
, __unused
int32_t *retval
)
2434 return common_fchdir(p
, (void *)uap
, 1);
2438 * Change current working directory (".").
2440 * Returns: 0 Success
2441 * change_dir:ENOTDIR
2443 * vnode_ref:ENOENT No such file or directory
2447 common_chdir(proc_t p
, struct chdir_args
*uap
, int per_thread
)
2449 struct filedesc
*fdp
= p
->p_fd
;
2451 struct nameidata nd
;
2453 vfs_context_t ctx
= vfs_context_current();
2455 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2456 UIO_USERSPACE
, uap
->path
, ctx
);
2457 error
= change_dir(&nd
, ctx
);
2460 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
2461 vnode_put(nd
.ni_vp
);
2465 * drop the iocount we picked up in change_dir
2467 vnode_put(nd
.ni_vp
);
2470 thread_t th
= vfs_context_thread(ctx
);
2472 uthread_t uth
= get_bsdthread_info(th
);
2474 uth
->uu_cdir
= nd
.ni_vp
;
2475 OSBitOrAtomic(P_THCWD
, &p
->p_flag
);
2477 vnode_rele(nd
.ni_vp
);
2483 fdp
->fd_cdir
= nd
.ni_vp
;
2497 * Change current working directory (".") for the entire process
2499 * Parameters: p Process requesting the call
2500 * uap User argument descriptor (see below)
2503 * Indirect parameters: uap->path Directory path
2505 * Returns: 0 Success
2506 * common_chdir: ENOTDIR
2507 * common_chdir: ENOENT No such file or directory
2512 chdir(proc_t p
, struct chdir_args
*uap
, __unused
int32_t *retval
)
2514 return common_chdir(p
, (void *)uap
, 0);
2520 * Change current working directory (".") for a single thread
2522 * Parameters: p Process requesting the call
2523 * uap User argument descriptor (see below)
2526 * Indirect parameters: uap->path Directory path
2528 * Returns: 0 Success
2529 * common_chdir: ENOTDIR
2530 * common_chdir: ENOENT No such file or directory
2535 __pthread_chdir(proc_t p
, struct __pthread_chdir_args
*uap
, __unused
int32_t *retval
)
2537 return common_chdir(p
, (void *)uap
, 1);
2542 * Change notion of root (``/'') directory.
2546 chroot(proc_t p
, struct chroot_args
*uap
, __unused
int32_t *retval
)
2548 struct filedesc
*fdp
= p
->p_fd
;
2550 struct nameidata nd
;
2552 vfs_context_t ctx
= vfs_context_current();
2554 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
2557 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2558 UIO_USERSPACE
, uap
->path
, ctx
);
2559 error
= change_dir(&nd
, ctx
);
2564 error
= mac_vnode_check_chroot(ctx
, nd
.ni_vp
,
2567 vnode_put(nd
.ni_vp
);
2572 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
2573 vnode_put(nd
.ni_vp
);
2576 vnode_put(nd
.ni_vp
);
2580 fdp
->fd_rdir
= nd
.ni_vp
;
2581 fdp
->fd_flags
|= FD_CHROOT
;
2591 * Common routine for chroot and chdir.
2593 * Returns: 0 Success
2594 * ENOTDIR Not a directory
2595 * namei:??? [anything namei can return]
2596 * vnode_authorize:??? [anything vnode_authorize can return]
2599 change_dir(struct nameidata
*ndp
, vfs_context_t ctx
)
2604 if ((error
= namei(ndp
)))
2609 if (vp
->v_type
!= VDIR
) {
2615 error
= mac_vnode_check_chdir(ctx
, vp
);
2622 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, ctx
);
2632 * Check permissions, allocate an open file structure,
2633 * and call the device open routine if any.
2635 * Returns: 0 Success
2646 * XXX Need to implement uid, gid
2649 open1(vfs_context_t ctx
, struct nameidata
*ndp
, int uflags
, struct vnode_attr
*vap
, int32_t *retval
)
2651 proc_t p
= vfs_context_proc(ctx
);
2652 uthread_t uu
= get_bsdthread_info(vfs_context_thread(ctx
));
2653 struct filedesc
*fdp
= p
->p_fd
;
2654 struct fileproc
*fp
;
2657 struct fileproc
*nfp
;
2658 int type
, indx
, error
;
2660 int no_controlling_tty
= 0;
2661 int deny_controlling_tty
= 0;
2662 struct session
*sessp
= SESSION_NULL
;
2663 struct vfs_context context
= *vfs_context_current(); /* local copy */
2667 if ((oflags
& O_ACCMODE
) == O_ACCMODE
)
2669 flags
= FFLAGS(uflags
);
2671 AUDIT_ARG(fflags
, oflags
);
2672 AUDIT_ARG(mode
, vap
->va_mode
);
2674 if ( (error
= falloc(p
, &nfp
, &indx
, ctx
)) ) {
2678 uu
->uu_dupfd
= -indx
- 1;
2680 if (!(p
->p_flag
& P_CONTROLT
)) {
2681 sessp
= proc_session(p
);
2682 no_controlling_tty
= 1;
2684 * If conditions would warrant getting a controlling tty if
2685 * the device being opened is a tty (see ttyopen in tty.c),
2686 * but the open flags deny it, set a flag in the session to
2689 if (SESS_LEADER(p
, sessp
) &&
2690 sessp
->s_ttyvp
== NULL
&&
2691 (flags
& O_NOCTTY
)) {
2692 session_lock(sessp
);
2693 sessp
->s_flags
|= S_NOCTTY
;
2694 session_unlock(sessp
);
2695 deny_controlling_tty
= 1;
2699 if ((error
= vn_open_auth(ndp
, &flags
, vap
))) {
2700 if ((error
== ENODEV
|| error
== ENXIO
) && (uu
->uu_dupfd
>= 0)){ /* XXX from fdopen */
2701 if ((error
= dupfdopen(fdp
, indx
, uu
->uu_dupfd
, flags
, error
)) == 0) {
2702 fp_drop(p
, indx
, NULL
, 0);
2704 if (deny_controlling_tty
) {
2705 session_lock(sessp
);
2706 sessp
->s_flags
&= ~S_NOCTTY
;
2707 session_unlock(sessp
);
2709 if (sessp
!= SESSION_NULL
)
2710 session_rele(sessp
);
2714 if (error
== ERESTART
)
2716 fp_free(p
, indx
, fp
);
2718 if (deny_controlling_tty
) {
2719 session_lock(sessp
);
2720 sessp
->s_flags
&= ~S_NOCTTY
;
2721 session_unlock(sessp
);
2723 if (sessp
!= SESSION_NULL
)
2724 session_rele(sessp
);
2730 fp
->f_fglob
->fg_flag
= flags
& (FMASK
| O_EVTONLY
);
2731 fp
->f_fglob
->fg_type
= DTYPE_VNODE
;
2732 fp
->f_fglob
->fg_ops
= &vnops
;
2733 fp
->f_fglob
->fg_data
= (caddr_t
)vp
;
2735 if (flags
& (O_EXLOCK
| O_SHLOCK
)) {
2736 lf
.l_whence
= SEEK_SET
;
2739 if (flags
& O_EXLOCK
)
2740 lf
.l_type
= F_WRLCK
;
2742 lf
.l_type
= F_RDLCK
;
2744 if ((flags
& FNONBLOCK
) == 0)
2747 error
= mac_file_check_lock(vfs_context_ucred(ctx
), fp
->f_fglob
,
2752 if ((error
= VNOP_ADVLOCK(vp
, (caddr_t
)fp
->f_fglob
, F_SETLK
, &lf
, type
, ctx
)))
2754 fp
->f_fglob
->fg_flag
|= FHASLOCK
;
2757 /* try to truncate by setting the size attribute */
2758 if ((flags
& O_TRUNC
) && ((error
= vnode_setsize(vp
, (off_t
)0, 0, ctx
)) != 0))
2762 * If the open flags denied the acquisition of a controlling tty,
2763 * clear the flag in the session structure that prevented the lower
2764 * level code from assigning one.
2766 if (deny_controlling_tty
) {
2767 session_lock(sessp
);
2768 sessp
->s_flags
&= ~S_NOCTTY
;
2769 session_unlock(sessp
);
2773 * If a controlling tty was set by the tty line discipline, then we
2774 * want to set the vp of the tty into the session structure. We have
2775 * a race here because we can't get to the vp for the tp in ttyopen,
2776 * because it's not passed as a parameter in the open path.
2778 if (no_controlling_tty
&& (p
->p_flag
& P_CONTROLT
)) {
2781 session_lock(sessp
);
2782 ttyvp
= sessp
->s_ttyvp
;
2783 sessp
->s_ttyvp
= vp
;
2784 sessp
->s_ttyvid
= vnode_vid(vp
);
2785 session_unlock(sessp
);
2786 if (ttyvp
!= NULLVP
)
2793 procfdtbl_releasefd(p
, indx
, NULL
);
2794 fp_drop(p
, indx
, fp
, 1);
2799 if (sessp
!= SESSION_NULL
)
2800 session_rele(sessp
);
2803 if (deny_controlling_tty
) {
2804 session_lock(sessp
);
2805 sessp
->s_flags
&= ~S_NOCTTY
;
2806 session_unlock(sessp
);
2808 if (sessp
!= SESSION_NULL
)
2809 session_rele(sessp
);
2811 /* Modify local copy (to not damage thread copy) */
2812 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
2814 vn_close(vp
, fp
->f_fglob
->fg_flag
, &context
);
2816 fp_free(p
, indx
, fp
);
2823 * open_extended: open a file given a path name; with extended argument list (including extended security (ACL)).
2825 * Parameters: p Process requesting the open
2826 * uap User argument descriptor (see below)
2827 * retval Pointer to an area to receive the
2828 * return calue from the system call
2830 * Indirect: uap->path Path to open (same as 'open')
2831 * uap->flags Flags to open (same as 'open'
2832 * uap->uid UID to set, if creating
2833 * uap->gid GID to set, if creating
2834 * uap->mode File mode, if creating (same as 'open')
2835 * uap->xsecurity ACL to set, if creating
2837 * Returns: 0 Success
2840 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
2842 * XXX: We should enummerate the possible errno values here, and where
2843 * in the code they originated.
2846 open_extended(proc_t p
, struct open_extended_args
*uap
, int32_t *retval
)
2848 struct filedesc
*fdp
= p
->p_fd
;
2850 kauth_filesec_t xsecdst
;
2851 struct vnode_attr va
;
2852 struct nameidata nd
;
2855 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
2858 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
2859 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
2863 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
2864 VATTR_SET(&va
, va_mode
, cmode
);
2865 if (uap
->uid
!= KAUTH_UID_NONE
)
2866 VATTR_SET(&va
, va_uid
, uap
->uid
);
2867 if (uap
->gid
!= KAUTH_GID_NONE
)
2868 VATTR_SET(&va
, va_gid
, uap
->gid
);
2869 if (xsecdst
!= NULL
)
2870 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2872 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, vfs_context_current());
2874 ciferror
= open1(vfs_context_current(), &nd
, uap
->flags
, &va
, retval
);
2875 if (xsecdst
!= NULL
)
2876 kauth_filesec_free(xsecdst
);
2882 open(proc_t p
, struct open_args
*uap
, int32_t *retval
)
2884 __pthread_testcancel(1);
2885 return(open_nocancel(p
, (struct open_nocancel_args
*)uap
, retval
));
2889 open_nocancel(proc_t p
, struct open_nocancel_args
*uap
, int32_t *retval
)
2891 struct filedesc
*fdp
= p
->p_fd
;
2892 struct vnode_attr va
;
2893 struct nameidata nd
;
2897 /* Mask off all but regular access permissions */
2898 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
2899 VATTR_SET(&va
, va_mode
, cmode
& ACCESSPERMS
);
2901 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, vfs_context_current());
2903 return(open1(vfs_context_current(), &nd
, uap
->flags
, &va
, retval
));
2908 * Create a special file.
2910 static int mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
);
2913 mknod(proc_t p
, struct mknod_args
*uap
, __unused
int32_t *retval
)
2915 struct vnode_attr va
;
2916 vfs_context_t ctx
= vfs_context_current();
2919 struct nameidata nd
;
2923 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
2924 VATTR_SET(&va
, va_rdev
, uap
->dev
);
2926 /* If it's a mknod() of a FIFO, call mkfifo1() instead */
2927 if ((uap
->mode
& S_IFMT
) == S_IFIFO
)
2928 return(mkfifo1(ctx
, uap
->path
, &va
));
2930 AUDIT_ARG(mode
, uap
->mode
);
2931 AUDIT_ARG(value32
, uap
->dev
);
2933 if ((error
= suser(vfs_context_ucred(ctx
), &p
->p_acflag
)))
2935 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
2936 UIO_USERSPACE
, uap
->path
, ctx
);
2948 switch (uap
->mode
& S_IFMT
) {
2949 case S_IFMT
: /* used by badsect to flag bad sectors */
2950 VATTR_SET(&va
, va_type
, VBAD
);
2953 VATTR_SET(&va
, va_type
, VCHR
);
2956 VATTR_SET(&va
, va_type
, VBLK
);
2968 error
= mac_vnode_check_create(ctx
,
2969 nd
.ni_dvp
, &nd
.ni_cnd
, &va
);
2975 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
2979 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, CREATE
, ctx
);
2981 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, &va
, 0, ctx
);
2987 int update_flags
= 0;
2989 // Make sure the name & parent pointers are hooked up
2990 if (vp
->v_name
== NULL
)
2991 update_flags
|= VNODE_UPDATE_NAME
;
2992 if (vp
->v_parent
== NULLVP
)
2993 update_flags
|= VNODE_UPDATE_PARENT
;
2996 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
2999 add_fsevent(FSE_CREATE_FILE
, ctx
,
3007 * nameidone has to happen before we vnode_put(dvp)
3008 * since it may need to release the fs_nodelock on the dvp
3020 * Create a named pipe.
3022 * Returns: 0 Success
3025 * vnode_authorize:???
3029 mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
)
3033 struct nameidata nd
;
3035 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
3036 UIO_USERSPACE
, upath
, ctx
);
3043 /* check that this is a new file and authorize addition */
3048 VATTR_SET(vap
, va_type
, VFIFO
);
3051 error
= mac_vnode_check_create(ctx
, nd
.ni_dvp
,
3058 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
3062 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
);
3065 * nameidone has to happen before we vnode_put(dvp)
3066 * since it may need to release the fs_nodelock on the dvp
3079 * mkfifo_extended: Create a named pipe; with extended argument list (including extended security (ACL)).
3081 * Parameters: p Process requesting the open
3082 * uap User argument descriptor (see below)
3085 * Indirect: uap->path Path to fifo (same as 'mkfifo')
3086 * uap->uid UID to set
3087 * uap->gid GID to set
3088 * uap->mode File mode to set (same as 'mkfifo')
3089 * uap->xsecurity ACL to set, if creating
3091 * Returns: 0 Success
3094 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
3096 * XXX: We should enummerate the possible errno values here, and where
3097 * in the code they originated.
3100 mkfifo_extended(proc_t p
, struct mkfifo_extended_args
*uap
, __unused
int32_t *retval
)
3103 kauth_filesec_t xsecdst
;
3104 struct vnode_attr va
;
3106 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
3108 xsecdst
= KAUTH_FILESEC_NONE
;
3109 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
3110 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
3115 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
3116 if (uap
->uid
!= KAUTH_UID_NONE
)
3117 VATTR_SET(&va
, va_uid
, uap
->uid
);
3118 if (uap
->gid
!= KAUTH_GID_NONE
)
3119 VATTR_SET(&va
, va_gid
, uap
->gid
);
3120 if (xsecdst
!= KAUTH_FILESEC_NONE
)
3121 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
3123 ciferror
= mkfifo1(vfs_context_current(), uap
->path
, &va
);
3125 if (xsecdst
!= KAUTH_FILESEC_NONE
)
3126 kauth_filesec_free(xsecdst
);
3132 mkfifo(proc_t p
, struct mkfifo_args
*uap
, __unused
int32_t *retval
)
3134 struct vnode_attr va
;
3137 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
3139 return(mkfifo1(vfs_context_current(), uap
->path
, &va
));
3144 my_strrchr(char *p
, int ch
)
3148 for (save
= NULL
;; ++p
) {
3157 extern int safe_getpath(struct vnode
*dvp
, char *leafname
, char *path
, int _len
, int *truncated_path
);
3160 safe_getpath(struct vnode
*dvp
, char *leafname
, char *path
, int _len
, int *truncated_path
)
3162 int ret
, len
= _len
;
3164 *truncated_path
= 0;
3165 ret
= vn_getpath(dvp
, path
, &len
);
3166 if (ret
== 0 && len
< (MAXPATHLEN
- 1)) {
3169 len
+= strlcpy(&path
[len
], leafname
, MAXPATHLEN
-len
) + 1;
3170 if (len
> MAXPATHLEN
) {
3173 // the string got truncated!
3174 *truncated_path
= 1;
3175 ptr
= my_strrchr(path
, '/');
3177 *ptr
= '\0'; // chop off the string at the last directory component
3179 len
= strlen(path
) + 1;
3182 } else if (ret
== 0) {
3183 *truncated_path
= 1;
3184 } else if (ret
!= 0) {
3185 struct vnode
*mydvp
=dvp
;
3187 if (ret
!= ENOSPC
) {
3188 printf("safe_getpath: failed to get the path for vp %p (%s) : err %d\n",
3189 dvp
, dvp
->v_name
? dvp
->v_name
: "no-name", ret
);
3191 *truncated_path
= 1;
3194 if (mydvp
->v_parent
!= NULL
) {
3195 mydvp
= mydvp
->v_parent
;
3196 } else if (mydvp
->v_mount
) {
3197 strlcpy(path
, mydvp
->v_mount
->mnt_vfsstat
.f_mntonname
, _len
);
3200 // no parent and no mount point? only thing is to punt and say "/" changed
3201 strlcpy(path
, "/", _len
);
3206 if (mydvp
== NULL
) {
3211 ret
= vn_getpath(mydvp
, path
, &len
);
3212 } while (ret
== ENOSPC
);
3220 * Make a hard file link.
3222 * Returns: 0 Success
3227 * vnode_authorize:???
3232 link(__unused proc_t p
, struct link_args
*uap
, __unused
int32_t *retval
)
3234 vnode_t vp
, dvp
, lvp
;
3235 struct nameidata nd
;
3236 vfs_context_t ctx
= vfs_context_current();
3241 int need_event
, has_listeners
;
3242 char *target_path
= NULL
;
3245 vp
= dvp
= lvp
= NULLVP
;
3247 /* look up the object we are linking to */
3248 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3249 UIO_USERSPACE
, uap
->path
, ctx
);
3258 * Normally, linking to directories is not supported.
3259 * However, some file systems may have limited support.
3261 if (vp
->v_type
== VDIR
) {
3262 if (!(vp
->v_mount
->mnt_vtable
->vfc_vfsflags
& VFC_VFSDIRLINKS
)) {
3263 error
= EPERM
; /* POSIX */
3266 /* Linking to a directory requires ownership. */
3267 if (!kauth_cred_issuser(vfs_context_ucred(ctx
))) {
3268 struct vnode_attr dva
;
3271 VATTR_WANTED(&dva
, va_uid
);
3272 if (vnode_getattr(vp
, &dva
, ctx
) != 0 ||
3273 !VATTR_IS_SUPPORTED(&dva
, va_uid
) ||
3274 (dva
.va_uid
!= kauth_cred_getuid(vfs_context_ucred(ctx
)))) {
3281 /* lookup the target node */
3282 nd
.ni_cnd
.cn_nameiop
= CREATE
;
3283 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| AUDITVNPATH2
| CN_NBMOUNTLOOK
;
3284 nd
.ni_dirp
= uap
->link
;
3292 if ((error
= mac_vnode_check_link(ctx
, dvp
, vp
, &nd
.ni_cnd
)) != 0)
3296 /* or to anything that kauth doesn't want us to (eg. immutable items) */
3297 if ((error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_LINKTARGET
, ctx
)) != 0)
3300 /* target node must not exist */
3301 if (lvp
!= NULLVP
) {
3305 /* cannot link across mountpoints */
3306 if (vnode_mount(vp
) != vnode_mount(dvp
)) {
3311 /* authorize creation of the target note */
3312 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
3315 /* and finally make the link */
3316 error
= VNOP_LINK(vp
, dvp
, &nd
.ni_cnd
, ctx
);
3321 need_event
= need_fsevent(FSE_CREATE_FILE
, dvp
);
3325 has_listeners
= kauth_authorize_fileop_has_listeners();
3327 if (need_event
|| has_listeners
) {
3328 char *link_to_path
= NULL
;
3329 int len
, link_name_len
;
3331 /* build the path to the new link file */
3332 GET_PATH(target_path
);
3333 if (target_path
== NULL
) {
3338 len
= safe_getpath(dvp
, nd
.ni_cnd
.cn_nameptr
, target_path
, MAXPATHLEN
, &truncated
);
3340 if (has_listeners
) {
3341 /* build the path to file we are linking to */
3342 GET_PATH(link_to_path
);
3343 if (link_to_path
== NULL
) {
3348 link_name_len
= MAXPATHLEN
;
3349 vn_getpath(vp
, link_to_path
, &link_name_len
);
3352 * Call out to allow 3rd party notification of rename.
3353 * Ignore result of kauth_authorize_fileop call.
3355 kauth_authorize_fileop(vfs_context_ucred(ctx
), KAUTH_FILEOP_LINK
,
3356 (uintptr_t)link_to_path
, (uintptr_t)target_path
);
3357 if (link_to_path
!= NULL
) {
3358 RELEASE_PATH(link_to_path
);
3363 /* construct fsevent */
3364 if (get_fse_info(vp
, &finfo
, ctx
) == 0) {
3366 finfo
.mode
|= FSE_TRUNCATED_PATH
;
3369 // build the path to the destination of the link
3370 add_fsevent(FSE_CREATE_FILE
, ctx
,
3371 FSE_ARG_STRING
, len
, target_path
,
3372 FSE_ARG_FINFO
, &finfo
,
3376 add_fsevent(FSE_STAT_CHANGED
, ctx
,
3377 FSE_ARG_VNODE
, vp
->v_parent
,
3385 * nameidone has to happen before we vnode_put(dvp)
3386 * since it may need to release the fs_nodelock on the dvp
3389 if (target_path
!= NULL
) {
3390 RELEASE_PATH(target_path
);
3402 * Make a symbolic link.
3404 * We could add support for ACLs here too...
3408 symlink(proc_t p
, struct symlink_args
*uap
, __unused
int32_t *retval
)
3410 struct vnode_attr va
;
3413 struct nameidata nd
;
3414 vfs_context_t ctx
= vfs_context_current();
3418 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
3419 error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
);
3422 AUDIT_ARG(text
, path
); /* This is the link string */
3424 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
3425 UIO_USERSPACE
, uap
->link
, ctx
);
3433 VATTR_SET(&va
, va_type
, VLNK
);
3434 VATTR_SET(&va
, va_mode
, ACCESSPERMS
& ~p
->p_fd
->fd_cmask
);
3436 error
= mac_vnode_check_create(ctx
,
3437 dvp
, &nd
.ni_cnd
, &va
);
3450 error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
);
3451 /* get default ownership, etc. */
3453 error
= vnode_authattr_new(dvp
, &va
, 0, ctx
);
3455 error
= VNOP_SYMLINK(dvp
, &vp
, &nd
.ni_cnd
, &va
, path
, ctx
);
3457 /* do fallback attribute handling */
3459 error
= vnode_setattr_fallback(vp
, &va
, ctx
);
3462 int update_flags
= 0;
3465 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
3466 nd
.ni_cnd
.cn_flags
= 0;
3474 #if 0 /* XXX - kauth_todo - is KAUTH_FILEOP_SYMLINK needed? */
3475 /* call out to allow 3rd party notification of rename.
3476 * Ignore result of kauth_authorize_fileop call.
3478 if (kauth_authorize_fileop_has_listeners() &&
3480 char *new_link_path
= NULL
;
3483 /* build the path to the new link file */
3484 new_link_path
= get_pathbuff();
3486 vn_getpath(dvp
, new_link_path
, &len
);
3487 if ((len
+ 1 + nd
.ni_cnd
.cn_namelen
+ 1) < MAXPATHLEN
) {
3488 new_link_path
[len
- 1] = '/';
3489 strlcpy(&new_link_path
[len
], nd
.ni_cnd
.cn_nameptr
, MAXPATHLEN
-len
);
3492 kauth_authorize_fileop(vfs_context_ucred(ctx
), KAUTH_FILEOP_SYMLINK
,
3493 (uintptr_t)path
, (uintptr_t)new_link_path
);
3494 if (new_link_path
!= NULL
)
3495 release_pathbuff(new_link_path
);
3498 // Make sure the name & parent pointers are hooked up
3499 if (vp
->v_name
== NULL
)
3500 update_flags
|= VNODE_UPDATE_NAME
;
3501 if (vp
->v_parent
== NULLVP
)
3502 update_flags
|= VNODE_UPDATE_PARENT
;
3505 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
3508 add_fsevent(FSE_CREATE_FILE
, ctx
,
3516 * nameidone has to happen before we vnode_put(dvp)
3517 * since it may need to release the fs_nodelock on the dvp
3525 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
3531 * Delete a whiteout from the filesystem.
3532 * XXX authorization not implmented for whiteouts
3535 undelete(__unused proc_t p
, struct undelete_args
*uap
, __unused
int32_t *retval
)
3538 struct nameidata nd
;
3539 vfs_context_t ctx
= vfs_context_current();
3542 NDINIT(&nd
, DELETE
, LOCKPARENT
|DOWHITEOUT
|AUDITVNPATH1
,
3543 UIO_USERSPACE
, uap
->path
, ctx
);
3550 if (vp
== NULLVP
&& (nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
3551 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, DELETE
, ctx
);
3556 * nameidone has to happen before we vnode_put(dvp)
3557 * since it may need to release the fs_nodelock on the dvp
3570 * Delete a name from the filesystem.
3574 unlink1(vfs_context_t ctx
, struct nameidata
*ndp
, int nodelbusy
)
3578 struct componentname
*cnp
;
3586 int has_listeners
= 0;
3587 int truncated_path
=0;
3589 /* unlink or delete is allowed on rsrc forks and named streams */
3590 ndp
->ni_cnd
.cn_flags
|= CN_ALLOWRSRCFORK
;
3593 ndp
->ni_cnd
.cn_flags
|= LOCKPARENT
;
3603 /* With Carbon delete semantics, busy files cannot be deleted */
3605 flags
|= VNODE_REMOVE_NODELETEBUSY
;
3609 * Normally, unlinking of directories is not supported.
3610 * However, some file systems may have limited support.
3612 if ((vp
->v_type
== VDIR
) &&
3613 !(vp
->v_mount
->mnt_vtable
->vfc_vfsflags
& VFC_VFSDIRLINKS
)) {
3614 error
= EPERM
; /* POSIX */
3618 * The root of a mounted filesystem cannot be deleted.
3620 if (vp
->v_flag
& VROOT
) {
3627 /* authorize the delete operation */
3630 error
= mac_vnode_check_unlink(ctx
,
3634 error
= vnode_authorize(vp
, ndp
->ni_dvp
, KAUTH_VNODE_DELETE
, ctx
);
3639 need_event
= need_fsevent(FSE_DELETE
, dvp
);
3641 if ((vp
->v_flag
& VISHARDLINK
) == 0) {
3642 get_fse_info(vp
, &finfo
, ctx
);
3646 has_listeners
= kauth_authorize_fileop_has_listeners();
3647 if (need_event
|| has_listeners
) {
3654 len
= safe_getpath(dvp
, ndp
->ni_cnd
.cn_nameptr
, path
, MAXPATHLEN
, &truncated_path
);
3658 if (ndp
->ni_cnd
.cn_flags
& CN_WANTSRSRCFORK
)
3659 error
= vnode_removenamedstream(dvp
, vp
, XATTR_RESOURCEFORK_NAME
, 0, ctx
);
3662 error
= VNOP_REMOVE(dvp
, vp
, &ndp
->ni_cnd
, flags
, ctx
);
3665 * Call out to allow 3rd party notification of delete.
3666 * Ignore result of kauth_authorize_fileop call.
3669 if (has_listeners
) {
3670 kauth_authorize_fileop(vfs_context_ucred(ctx
),
3671 KAUTH_FILEOP_DELETE
,
3676 if (vp
->v_flag
& VISHARDLINK
) {
3678 // if a hardlink gets deleted we want to blow away the
3679 // v_parent link because the path that got us to this
3680 // instance of the link is no longer valid. this will
3681 // force the next call to get the path to ask the file
3682 // system instead of just following the v_parent link.
3684 vnode_update_identity(vp
, NULL
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
3689 if (vp
->v_flag
& VISHARDLINK
) {
3690 get_fse_info(vp
, &finfo
, ctx
);
3692 if (truncated_path
) {
3693 finfo
.mode
|= FSE_TRUNCATED_PATH
;
3695 add_fsevent(FSE_DELETE
, ctx
,
3696 FSE_ARG_STRING
, len
, path
,
3697 FSE_ARG_FINFO
, &finfo
,
3706 * nameidone has to happen before we vnode_put(dvp)
3707 * since it may need to release the fs_nodelock on the dvp
3711 /* recycle the deleted rsrc fork vnode to force a reclaim, which
3712 * will cause its shadow file to go away if necessary.
3714 if ((vnode_isnamedstream(ndp
->ni_vp
)) &&
3715 (ndp
->ni_vp
->v_parent
!= NULLVP
) &&
3716 vnode_isshadow(ndp
->ni_vp
)) {
3717 vnode_recycle(ndp
->ni_vp
);
3727 * Delete a name from the filesystem using POSIX semantics.
3730 unlink(__unused proc_t p
, struct unlink_args
*uap
, __unused
int32_t *retval
)
3732 struct nameidata nd
;
3733 vfs_context_t ctx
= vfs_context_current();
3735 NDINIT(&nd
, DELETE
, AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, ctx
);
3736 return unlink1(ctx
, &nd
, 0);
3740 * Delete a name from the filesystem using Carbon semantics.
3743 delete(__unused proc_t p
, struct delete_args
*uap
, __unused
int32_t *retval
)
3745 struct nameidata nd
;
3746 vfs_context_t ctx
= vfs_context_current();
3748 NDINIT(&nd
, DELETE
, AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, ctx
);
3749 return unlink1(ctx
, &nd
, 1);
3753 * Reposition read/write file offset.
3756 lseek(proc_t p
, struct lseek_args
*uap
, off_t
*retval
)
3758 struct fileproc
*fp
;
3760 struct vfs_context
*ctx
;
3761 off_t offset
= uap
->offset
, file_size
;
3764 if ( (error
= fp_getfvp(p
,uap
->fd
, &fp
, &vp
)) ) {
3765 if (error
== ENOTSUP
)
3769 if (vnode_isfifo(vp
)) {
3775 ctx
= vfs_context_current();
3777 if (uap
->whence
== L_INCR
&& uap
->offset
== 0)
3778 error
= mac_file_check_get_offset(vfs_context_ucred(ctx
),
3781 error
= mac_file_check_change_offset(vfs_context_ucred(ctx
),
3788 if ( (error
= vnode_getwithref(vp
)) ) {
3793 switch (uap
->whence
) {
3795 offset
+= fp
->f_fglob
->fg_offset
;
3798 if ((error
= vnode_size(vp
, &file_size
, ctx
)) != 0)
3800 offset
+= file_size
;
3808 if (uap
->offset
> 0 && offset
< 0) {
3809 /* Incremented/relative move past max size */
3813 * Allow negative offsets on character devices, per
3814 * POSIX 1003.1-2001. Most likely for writing disk
3817 if (offset
< 0 && vp
->v_type
!= VCHR
) {
3818 /* Decremented/relative move before start */
3822 fp
->f_fglob
->fg_offset
= offset
;
3823 *retval
= fp
->f_fglob
->fg_offset
;
3829 * An lseek can affect whether data is "available to read." Use
3830 * hint of NOTE_NONE so no EVFILT_VNODE events fire
3832 post_event_if_success(vp
, error
, NOTE_NONE
);
3833 (void)vnode_put(vp
);
3840 * Check access permissions.
3842 * Returns: 0 Success
3843 * vnode_authorize:???
3846 access1(vnode_t vp
, vnode_t dvp
, int uflags
, vfs_context_t ctx
)
3848 kauth_action_t action
;
3852 * If just the regular access bits, convert them to something
3853 * that vnode_authorize will understand.
3855 if (!(uflags
& _ACCESS_EXTENDED_MASK
)) {
3858 action
|= KAUTH_VNODE_READ_DATA
; /* aka KAUTH_VNODE_LIST_DIRECTORY */
3859 if (uflags
& W_OK
) {
3860 if (vnode_isdir(vp
)) {
3861 action
|= KAUTH_VNODE_ADD_FILE
|
3862 KAUTH_VNODE_ADD_SUBDIRECTORY
;
3863 /* might want delete rights here too */
3865 action
|= KAUTH_VNODE_WRITE_DATA
;
3868 if (uflags
& X_OK
) {
3869 if (vnode_isdir(vp
)) {
3870 action
|= KAUTH_VNODE_SEARCH
;
3872 action
|= KAUTH_VNODE_EXECUTE
;
3876 /* take advantage of definition of uflags */
3877 action
= uflags
>> 8;
3881 error
= mac_vnode_check_access(ctx
, vp
, uflags
);
3886 /* action == 0 means only check for existence */
3888 error
= vnode_authorize(vp
, dvp
, action
| KAUTH_VNODE_ACCESS
, ctx
);
3899 * access_extended: Check access permissions in bulk.
3901 * Description: uap->entries Pointer to an array of accessx
3902 * descriptor structs, plus one or
3903 * more NULL terminated strings (see
3904 * "Notes" section below).
3905 * uap->size Size of the area pointed to by
3907 * uap->results Pointer to the results array.
3909 * Returns: 0 Success
3910 * ENOMEM Insufficient memory
3911 * EINVAL Invalid arguments
3912 * namei:EFAULT Bad address
3913 * namei:ENAMETOOLONG Filename too long
3914 * namei:ENOENT No such file or directory
3915 * namei:ELOOP Too many levels of symbolic links
3916 * namei:EBADF Bad file descriptor
3917 * namei:ENOTDIR Not a directory
3922 * uap->results Array contents modified
3924 * Notes: The uap->entries are structured as an arbitrary length array
3925 * of accessx descriptors, followed by one or more NULL terminated
3928 * struct accessx_descriptor[0]
3930 * struct accessx_descriptor[n]
3931 * char name_data[0];
3933 * We determine the entry count by walking the buffer containing
3934 * the uap->entries argument descriptor. For each descriptor we
3935 * see, the valid values for the offset ad_name_offset will be
3936 * in the byte range:
3938 * [ uap->entries + sizeof(struct accessx_descriptor) ]
3940 * [ uap->entries + uap->size - 2 ]
3942 * since we must have at least one string, and the string must
3943 * be at least one character plus the NULL terminator in length.
3945 * XXX: Need to support the check-as uid argument
3948 access_extended(__unused proc_t p
, struct access_extended_args
*uap
, __unused
int32_t *retval
)
3950 struct accessx_descriptor
*input
= NULL
;
3951 errno_t
*result
= NULL
;
3954 unsigned int desc_max
, desc_actual
, i
, j
;
3955 struct vfs_context context
;
3956 struct nameidata nd
;
3960 #define ACCESSX_MAX_DESCR_ON_STACK 10
3961 struct accessx_descriptor stack_input
[ACCESSX_MAX_DESCR_ON_STACK
];
3963 context
.vc_ucred
= NULL
;
3966 * Validate parameters; if valid, copy the descriptor array and string
3967 * arguments into local memory. Before proceeding, the following
3968 * conditions must have been met:
3970 * o The total size is not permitted to exceed ACCESSX_MAX_TABLESIZE
3971 * o There must be sufficient room in the request for at least one
3972 * descriptor and a one yte NUL terminated string.
3973 * o The allocation of local storage must not fail.
3975 if (uap
->size
> ACCESSX_MAX_TABLESIZE
)
3977 if (uap
->size
< (sizeof(struct accessx_descriptor
) + 2))
3979 if (uap
->size
<= sizeof (stack_input
)) {
3980 input
= stack_input
;
3982 MALLOC(input
, struct accessx_descriptor
*, uap
->size
, M_TEMP
, M_WAITOK
);
3983 if (input
== NULL
) {
3988 error
= copyin(uap
->entries
, input
, uap
->size
);
3992 AUDIT_ARG(opaque
, input
, uap
->size
);
3995 * Force NUL termination of the copyin buffer to avoid nami() running
3996 * off the end. If the caller passes us bogus data, they may get a
3999 ((char *)input
)[uap
->size
- 1] = 0;
4002 * Access is defined as checking against the process' real identity,
4003 * even if operations are checking the effective identity. This
4004 * requires that we use a local vfs context.
4006 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
4007 context
.vc_thread
= current_thread();
4010 * Find out how many entries we have, so we can allocate the result
4011 * array by walking the list and adjusting the count downward by the
4012 * earliest string offset we see.
4014 desc_max
= (uap
->size
- 2) / sizeof(struct accessx_descriptor
);
4015 desc_actual
= desc_max
;
4016 for (i
= 0; i
< desc_actual
; i
++) {
4018 * Take the offset to the name string for this entry and
4019 * convert to an input array index, which would be one off
4020 * the end of the array if this entry was the lowest-addressed
4023 j
= input
[i
].ad_name_offset
/ sizeof(struct accessx_descriptor
);
4026 * An offset greater than the max allowable offset is an error.
4027 * It is also an error for any valid entry to point
4028 * to a location prior to the end of the current entry, if
4029 * it's not a reference to the string of the previous entry.
4031 if (j
> desc_max
|| (j
!= 0 && j
<= i
)) {
4037 * An offset of 0 means use the previous descriptor's offset;
4038 * this is used to chain multiple requests for the same file
4039 * to avoid multiple lookups.
4042 /* This is not valid for the first entry */
4051 * If the offset of the string for this descriptor is before
4052 * what we believe is the current actual last descriptor,
4053 * then we need to adjust our estimate downward; this permits
4054 * the string table following the last descriptor to be out
4055 * of order relative to the descriptor list.
4057 if (j
< desc_actual
)
4062 * We limit the actual number of descriptors we are willing to process
4063 * to a hard maximum of ACCESSX_MAX_DESCRIPTORS. If the number being
4064 * requested does not exceed this limit,
4066 if (desc_actual
> ACCESSX_MAX_DESCRIPTORS
) {
4070 MALLOC(result
, errno_t
*, desc_actual
* sizeof(errno_t
), M_TEMP
, M_WAITOK
);
4071 if (result
== NULL
) {
4077 * Do the work by iterating over the descriptor entries we know to
4078 * at least appear to contain valid data.
4081 for (i
= 0; i
< desc_actual
; i
++) {
4083 * If the ad_name_offset is 0, then we use the previous
4084 * results to make the check; otherwise, we are looking up
4087 if (input
[i
].ad_name_offset
!= 0) {
4088 /* discard old vnodes */
4099 * Scan forward in the descriptor list to see if we
4100 * need the parent vnode. We will need it if we are
4101 * deleting, since we must have rights to remove
4102 * entries in the parent directory, as well as the
4103 * rights to delete the object itself.
4105 wantdelete
= input
[i
].ad_flags
& _DELETE_OK
;
4106 for (j
= i
+ 1; (j
< desc_actual
) && (input
[j
].ad_name_offset
== 0); j
++)
4107 if (input
[j
].ad_flags
& _DELETE_OK
)
4110 niopts
= FOLLOW
| AUDITVNPATH1
;
4112 /* need parent for vnode_authorize for deletion test */
4114 niopts
|= WANTPARENT
;
4117 NDINIT(&nd
, LOOKUP
, niopts
, UIO_SYSSPACE
, CAST_USER_ADDR_T(((const char *)input
) + input
[i
].ad_name_offset
), &context
);
4128 * Handle lookup errors.
4138 /* run this access check */
4139 result
[i
] = access1(vp
, dvp
, input
[i
].ad_flags
, &context
);
4142 /* fatal lookup error */
4148 AUDIT_ARG(data
, result
, sizeof(errno_t
), desc_actual
);
4150 /* copy out results */
4151 error
= copyout(result
, uap
->results
, desc_actual
* sizeof(errno_t
));
4154 if (input
&& input
!= stack_input
)
4155 FREE(input
, M_TEMP
);
4157 FREE(result
, M_TEMP
);
4162 if (IS_VALID_CRED(context
.vc_ucred
))
4163 kauth_cred_unref(&context
.vc_ucred
);
4169 * Returns: 0 Success
4170 * namei:EFAULT Bad address
4171 * namei:ENAMETOOLONG Filename too long
4172 * namei:ENOENT No such file or directory
4173 * namei:ELOOP Too many levels of symbolic links
4174 * namei:EBADF Bad file descriptor
4175 * namei:ENOTDIR Not a directory
4180 access(__unused proc_t p
, struct access_args
*uap
, __unused
int32_t *retval
)
4183 struct nameidata nd
;
4185 struct vfs_context context
;
4187 int is_namedstream
= 0;
4191 * Access is defined as checking against the process'
4192 * real identity, even if operations are checking the
4193 * effective identity. So we need to tweak the credential
4196 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
4197 context
.vc_thread
= current_thread();
4199 niopts
= FOLLOW
| AUDITVNPATH1
;
4200 /* need parent for vnode_authorize for deletion test */
4201 if (uap
->flags
& _DELETE_OK
)
4202 niopts
|= WANTPARENT
;
4203 NDINIT(&nd
, LOOKUP
, niopts
, UIO_USERSPACE
, uap
->path
, &context
);
4206 /* access(F_OK) calls are allowed for resource forks. */
4207 if (uap
->flags
== F_OK
)
4208 nd
.ni_cnd
.cn_flags
|= CN_ALLOWRSRCFORK
;
4215 /* Grab reference on the shadow stream file vnode to
4216 * force an inactive on release which will mark it
4219 if (vnode_isnamedstream(nd
.ni_vp
) &&
4220 (nd
.ni_vp
->v_parent
!= NULLVP
) &&
4221 vnode_isshadow(nd
.ni_vp
)) {
4223 vnode_ref(nd
.ni_vp
);
4227 error
= access1(nd
.ni_vp
, nd
.ni_dvp
, uap
->flags
, &context
);
4230 if (is_namedstream
) {
4231 vnode_rele(nd
.ni_vp
);
4235 vnode_put(nd
.ni_vp
);
4236 if (uap
->flags
& _DELETE_OK
)
4237 vnode_put(nd
.ni_dvp
);
4241 kauth_cred_unref(&context
.vc_ucred
);
4247 * Returns: 0 Success
4254 stat2(vfs_context_t ctx
, struct nameidata
*ndp
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
, int isstat64
)
4261 struct user64_stat user64_sb
;
4262 struct user32_stat user32_sb
;
4263 struct user64_stat64 user64_sb64
;
4264 struct user32_stat64 user32_sb64
;
4268 kauth_filesec_t fsec
;
4269 size_t xsecurity_bufsize
;
4273 int is_namedstream
= 0;
4274 /* stat calls are allowed for resource forks. */
4275 ndp
->ni_cnd
.cn_flags
|= CN_ALLOWRSRCFORK
;
4280 fsec
= KAUTH_FILESEC_NONE
;
4282 statptr
= (void *)&source
;
4285 /* Grab reference on the shadow stream file vnode to
4286 * force an inactive on release which will mark it
4289 if (vnode_isnamedstream(ndp
->ni_vp
) &&
4290 (ndp
->ni_vp
->v_parent
!= NULLVP
) &&
4291 vnode_isshadow(ndp
->ni_vp
)) {
4293 vnode_ref(ndp
->ni_vp
);
4297 error
= vn_stat(ndp
->ni_vp
, statptr
, (xsecurity
!= USER_ADDR_NULL
? &fsec
: NULL
), isstat64
, ctx
);
4300 if (is_namedstream
) {
4301 vnode_rele(ndp
->ni_vp
);
4304 vnode_put(ndp
->ni_vp
);
4309 /* Zap spare fields */
4310 if (isstat64
!= 0) {
4311 source
.sb64
.st_lspare
= 0;
4312 source
.sb64
.st_qspare
[0] = 0LL;
4313 source
.sb64
.st_qspare
[1] = 0LL;
4314 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
4315 munge_user64_stat64(&source
.sb64
, &dest
.user64_sb64
);
4316 my_size
= sizeof(dest
.user64_sb64
);
4317 sbp
= (caddr_t
)&dest
.user64_sb64
;
4319 munge_user32_stat64(&source
.sb64
, &dest
.user32_sb64
);
4320 my_size
= sizeof(dest
.user32_sb64
);
4321 sbp
= (caddr_t
)&dest
.user32_sb64
;
4324 * Check if we raced (post lookup) against the last unlink of a file.
4326 if ((source
.sb64
.st_nlink
== 0) && S_ISREG(source
.sb64
.st_mode
)) {
4327 source
.sb64
.st_nlink
= 1;
4330 source
.sb
.st_lspare
= 0;
4331 source
.sb
.st_qspare
[0] = 0LL;
4332 source
.sb
.st_qspare
[1] = 0LL;
4333 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
4334 munge_user64_stat(&source
.sb
, &dest
.user64_sb
);
4335 my_size
= sizeof(dest
.user64_sb
);
4336 sbp
= (caddr_t
)&dest
.user64_sb
;
4338 munge_user32_stat(&source
.sb
, &dest
.user32_sb
);
4339 my_size
= sizeof(dest
.user32_sb
);
4340 sbp
= (caddr_t
)&dest
.user32_sb
;
4344 * Check if we raced (post lookup) against the last unlink of a file.
4346 if ((source
.sb
.st_nlink
== 0) && S_ISREG(source
.sb
.st_mode
)) {
4347 source
.sb
.st_nlink
= 1;
4350 if ((error
= copyout(sbp
, ub
, my_size
)) != 0)
4353 /* caller wants extended security information? */
4354 if (xsecurity
!= USER_ADDR_NULL
) {
4356 /* did we get any? */
4357 if (fsec
== KAUTH_FILESEC_NONE
) {
4358 if (susize(xsecurity_size
, 0) != 0) {
4363 /* find the user buffer size */
4364 xsecurity_bufsize
= fusize(xsecurity_size
);
4366 /* copy out the actual data size */
4367 if (susize(xsecurity_size
, KAUTH_FILESEC_COPYSIZE(fsec
)) != 0) {
4372 /* if the caller supplied enough room, copy out to it */
4373 if (xsecurity_bufsize
>= KAUTH_FILESEC_COPYSIZE(fsec
))
4374 error
= copyout(fsec
, xsecurity
, KAUTH_FILESEC_COPYSIZE(fsec
));
4378 if (fsec
!= KAUTH_FILESEC_NONE
)
4379 kauth_filesec_free(fsec
);
4384 * Get file status; this version follows links.
4386 * Returns: 0 Success
4387 * stat2:??? [see stat2() in this file]
4390 stat1(user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
, int isstat64
)
4392 struct nameidata nd
;
4393 vfs_context_t ctx
= vfs_context_current();
4395 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
4396 UIO_USERSPACE
, path
, ctx
);
4397 return(stat2(ctx
, &nd
, ub
, xsecurity
, xsecurity_size
, isstat64
));
4401 * stat_extended: Get file status; with extended security (ACL).
4403 * Parameters: p (ignored)
4404 * uap User argument descriptor (see below)
4407 * Indirect: uap->path Path of file to get status from
4408 * uap->ub User buffer (holds file status info)
4409 * uap->xsecurity ACL to get (extended security)
4410 * uap->xsecurity_size Size of ACL
4412 * Returns: 0 Success
4417 stat_extended(__unused proc_t p
, struct stat_extended_args
*uap
, __unused
int32_t *retval
)
4419 return (stat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 0));
4423 * Returns: 0 Success
4424 * stat1:??? [see stat1() in this file]
4427 stat(__unused proc_t p
, struct stat_args
*uap
, __unused
int32_t *retval
)
4429 return(stat1(uap
->path
, uap
->ub
, 0, 0, 0));
4433 stat64(__unused proc_t p
, struct stat64_args
*uap
, __unused
int32_t *retval
)
4435 return(stat1(uap
->path
, uap
->ub
, 0, 0, 1));
4439 * stat64_extended: Get file status; can handle large inode numbers; with extended security (ACL).
4441 * Parameters: p (ignored)
4442 * uap User argument descriptor (see below)
4445 * Indirect: uap->path Path of file to get status from
4446 * uap->ub User buffer (holds file status info)
4447 * uap->xsecurity ACL to get (extended security)
4448 * uap->xsecurity_size Size of ACL
4450 * Returns: 0 Success
4455 stat64_extended(__unused proc_t p
, struct stat64_extended_args
*uap
, __unused
int32_t *retval
)
4457 return (stat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 1));
4460 * Get file status; this version does not follow links.
4463 lstat1(user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
, int isstat64
)
4465 struct nameidata nd
;
4466 vfs_context_t ctx
= vfs_context_current();
4468 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| NOFOLLOW
| AUDITVNPATH1
,
4469 UIO_USERSPACE
, path
, ctx
);
4471 return(stat2(ctx
, &nd
, ub
, xsecurity
, xsecurity_size
, isstat64
));
4475 * lstat_extended: Get file status; does not follow links; with extended security (ACL).
4477 * Parameters: p (ignored)
4478 * uap User argument descriptor (see below)
4481 * Indirect: uap->path Path of file to get status from
4482 * uap->ub User buffer (holds file status info)
4483 * uap->xsecurity ACL to get (extended security)
4484 * uap->xsecurity_size Size of ACL
4486 * Returns: 0 Success
4491 lstat_extended(__unused proc_t p
, struct lstat_extended_args
*uap
, __unused
int32_t *retval
)
4493 return (lstat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 0));
4497 lstat(__unused proc_t p
, struct lstat_args
*uap
, __unused
int32_t *retval
)
4499 return(lstat1(uap
->path
, uap
->ub
, 0, 0, 0));
4503 lstat64(__unused proc_t p
, struct lstat64_args
*uap
, __unused
int32_t *retval
)
4505 return(lstat1(uap
->path
, uap
->ub
, 0, 0, 1));
4509 * lstat64_extended: Get file status; can handle large inode numbers; does not
4510 * follow links; with extended security (ACL).
4512 * Parameters: p (ignored)
4513 * uap User argument descriptor (see below)
4516 * Indirect: uap->path Path of file to get status from
4517 * uap->ub User buffer (holds file status info)
4518 * uap->xsecurity ACL to get (extended security)
4519 * uap->xsecurity_size Size of ACL
4521 * Returns: 0 Success
4526 lstat64_extended(__unused proc_t p
, struct lstat64_extended_args
*uap
, __unused
int32_t *retval
)
4528 return (lstat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 1));
4532 * Get configurable pathname variables.
4534 * Returns: 0 Success
4538 * Notes: Global implementation constants are intended to be
4539 * implemented in this function directly; all other constants
4540 * are per-FS implementation, and therefore must be handled in
4541 * each respective FS, instead.
4543 * XXX We implement some things globally right now that should actually be
4544 * XXX per-FS; we will need to deal with this at some point.
4548 pathconf(__unused proc_t p
, struct pathconf_args
*uap
, int32_t *retval
)
4551 struct nameidata nd
;
4552 vfs_context_t ctx
= vfs_context_current();
4554 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4555 UIO_USERSPACE
, uap
->path
, ctx
);
4560 error
= vn_pathconf(nd
.ni_vp
, uap
->name
, retval
, ctx
);
4562 vnode_put(nd
.ni_vp
);
4568 * Return target name of a symbolic link.
4572 readlink(proc_t p
, struct readlink_args
*uap
, int32_t *retval
)
4576 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4578 struct nameidata nd
;
4579 vfs_context_t ctx
= vfs_context_current();
4580 char uio_buf
[ UIO_SIZEOF(1) ];
4582 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
4583 UIO_USERSPACE
, uap
->path
, ctx
);
4591 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
4592 &uio_buf
[0], sizeof(uio_buf
));
4593 uio_addiov(auio
, uap
->buf
, uap
->count
);
4594 if (vp
->v_type
!= VLNK
)
4598 error
= mac_vnode_check_readlink(ctx
,
4602 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, ctx
);
4604 error
= VNOP_READLINK(vp
, auio
, ctx
);
4608 /* Safe: uio_resid() is bounded above by "count", and "count" is an int */
4609 *retval
= uap
->count
- (int)uio_resid(auio
);
4614 * Change file flags.
4617 chflags1(vnode_t vp
, int flags
, vfs_context_t ctx
)
4619 struct vnode_attr va
;
4620 kauth_action_t action
;
4624 VATTR_SET(&va
, va_flags
, flags
);
4627 error
= mac_vnode_check_setflags(ctx
, vp
, flags
);
4632 /* request authorisation, disregard immutability */
4633 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
4636 * Request that the auth layer disregard those file flags it's allowed to when
4637 * authorizing this operation; we need to do this in order to be able to
4638 * clear immutable flags.
4640 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
| KAUTH_VNODE_NOIMMUTABLE
, ctx
)) != 0))
4642 error
= vnode_setattr(vp
, &va
, ctx
);
4644 if ((error
== 0) && !VATTR_IS_SUPPORTED(&va
, va_flags
)) {
4653 * Change flags of a file given a path name.
4657 chflags(__unused proc_t p
, struct chflags_args
*uap
, __unused
int32_t *retval
)
4660 vfs_context_t ctx
= vfs_context_current();
4662 struct nameidata nd
;
4664 AUDIT_ARG(fflags
, uap
->flags
);
4665 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4666 UIO_USERSPACE
, uap
->path
, ctx
);
4673 error
= chflags1(vp
, uap
->flags
, ctx
);
4679 * Change flags of a file given a file descriptor.
4683 fchflags(__unused proc_t p
, struct fchflags_args
*uap
, __unused
int32_t *retval
)
4688 AUDIT_ARG(fd
, uap
->fd
);
4689 AUDIT_ARG(fflags
, uap
->flags
);
4690 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
4693 if ((error
= vnode_getwithref(vp
))) {
4698 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4700 error
= chflags1(vp
, uap
->flags
, vfs_context_current());
4707 * Change security information on a filesystem object.
4709 * Returns: 0 Success
4710 * EPERM Operation not permitted
4711 * vnode_authattr:??? [anything vnode_authattr can return]
4712 * vnode_authorize:??? [anything vnode_authorize can return]
4713 * vnode_setattr:??? [anything vnode_setattr can return]
4715 * Notes: If vnode_authattr or vnode_authorize return EACCES, it will be
4716 * translated to EPERM before being returned.
4719 chmod2(vfs_context_t ctx
, vnode_t vp
, struct vnode_attr
*vap
)
4721 kauth_action_t action
;
4724 AUDIT_ARG(mode
, vap
->va_mode
);
4725 /* XXX audit new args */
4728 /* chmod calls are not allowed for resource forks. */
4729 if (vp
->v_flag
& VISNAMEDSTREAM
) {
4735 error
= mac_vnode_check_setmode(ctx
, vp
, (mode_t
)vap
->va_mode
);
4740 /* make sure that the caller is allowed to set this security information */
4741 if (((error
= vnode_authattr(vp
, vap
, &action
, ctx
)) != 0) ||
4742 ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
4743 if (error
== EACCES
)
4748 error
= vnode_setattr(vp
, vap
, ctx
);
4755 * Change mode of a file given a path name.
4757 * Returns: 0 Success
4758 * namei:??? [anything namei can return]
4759 * chmod2:??? [anything chmod2 can return]
4762 chmod1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
4764 struct nameidata nd
;
4767 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4768 UIO_USERSPACE
, path
, ctx
);
4769 if ((error
= namei(&nd
)))
4771 error
= chmod2(ctx
, nd
.ni_vp
, vap
);
4772 vnode_put(nd
.ni_vp
);
4778 * chmod_extended: Change the mode of a file given a path name; with extended
4779 * argument list (including extended security (ACL)).
4781 * Parameters: p Process requesting the open
4782 * uap User argument descriptor (see below)
4785 * Indirect: uap->path Path to object (same as 'chmod')
4786 * uap->uid UID to set
4787 * uap->gid GID to set
4788 * uap->mode File mode to set (same as 'chmod')
4789 * uap->xsecurity ACL to set (or delete)
4791 * Returns: 0 Success
4794 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
4796 * XXX: We should enummerate the possible errno values here, and where
4797 * in the code they originated.
4800 chmod_extended(__unused proc_t p
, struct chmod_extended_args
*uap
, __unused
int32_t *retval
)
4803 struct vnode_attr va
;
4804 kauth_filesec_t xsecdst
;
4806 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
4809 if (uap
->mode
!= -1)
4810 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
4811 if (uap
->uid
!= KAUTH_UID_NONE
)
4812 VATTR_SET(&va
, va_uid
, uap
->uid
);
4813 if (uap
->gid
!= KAUTH_GID_NONE
)
4814 VATTR_SET(&va
, va_gid
, uap
->gid
);
4817 switch(uap
->xsecurity
) {
4818 /* explicit remove request */
4819 case CAST_USER_ADDR_T((void *)1): /* _FILESEC_REMOVE_ACL */
4820 VATTR_SET(&va
, va_acl
, NULL
);
4823 case USER_ADDR_NULL
:
4826 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
4828 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
4829 KAUTH_DEBUG("CHMOD - setting ACL with %d entries", va
.va_acl
->acl_entrycount
);
4832 error
= chmod1(vfs_context_current(), uap
->path
, &va
);
4834 if (xsecdst
!= NULL
)
4835 kauth_filesec_free(xsecdst
);
4840 * Returns: 0 Success
4841 * chmod1:??? [anything chmod1 can return]
4844 chmod(__unused proc_t p
, struct chmod_args
*uap
, __unused
int32_t *retval
)
4846 struct vnode_attr va
;
4849 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
4851 return(chmod1(vfs_context_current(), uap
->path
, &va
));
4855 * Change mode of a file given a file descriptor.
4858 fchmod1(__unused proc_t p
, int fd
, struct vnode_attr
*vap
)
4865 if ((error
= file_vnode(fd
, &vp
)) != 0)
4867 if ((error
= vnode_getwithref(vp
)) != 0) {
4871 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4873 error
= chmod2(vfs_context_current(), vp
, vap
);
4874 (void)vnode_put(vp
);
4881 * fchmod_extended: Change mode of a file given a file descriptor; with
4882 * extended argument list (including extended security (ACL)).
4884 * Parameters: p Process requesting to change file mode
4885 * uap User argument descriptor (see below)
4888 * Indirect: uap->mode File mode to set (same as 'chmod')
4889 * uap->uid UID to set
4890 * uap->gid GID to set
4891 * uap->xsecurity ACL to set (or delete)
4892 * uap->fd File descriptor of file to change mode
4894 * Returns: 0 Success
4899 fchmod_extended(proc_t p
, struct fchmod_extended_args
*uap
, __unused
int32_t *retval
)
4902 struct vnode_attr va
;
4903 kauth_filesec_t xsecdst
;
4905 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
4908 if (uap
->mode
!= -1)
4909 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
4910 if (uap
->uid
!= KAUTH_UID_NONE
)
4911 VATTR_SET(&va
, va_uid
, uap
->uid
);
4912 if (uap
->gid
!= KAUTH_GID_NONE
)
4913 VATTR_SET(&va
, va_gid
, uap
->gid
);
4916 switch(uap
->xsecurity
) {
4917 case USER_ADDR_NULL
:
4918 VATTR_SET(&va
, va_acl
, NULL
);
4920 case CAST_USER_ADDR_T(-1):
4923 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
4925 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
4928 error
= fchmod1(p
, uap
->fd
, &va
);
4931 switch(uap
->xsecurity
) {
4932 case USER_ADDR_NULL
:
4933 case CAST_USER_ADDR_T(-1):
4936 if (xsecdst
!= NULL
)
4937 kauth_filesec_free(xsecdst
);
4943 fchmod(proc_t p
, struct fchmod_args
*uap
, __unused
int32_t *retval
)
4945 struct vnode_attr va
;
4948 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
4950 return(fchmod1(p
, uap
->fd
, &va
));
4955 * Set ownership given a path name.
4959 chown1(vfs_context_t ctx
, struct chown_args
*uap
, __unused
int32_t *retval
, int follow
)
4962 struct vnode_attr va
;
4964 struct nameidata nd
;
4965 kauth_action_t action
;
4967 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
4969 NDINIT(&nd
, LOOKUP
, (follow
? FOLLOW
: 0) | NOTRIGGER
| AUDITVNPATH1
,
4970 UIO_USERSPACE
, uap
->path
, ctx
);
4979 if (uap
->uid
!= VNOVAL
)
4980 VATTR_SET(&va
, va_uid
, uap
->uid
);
4981 if (uap
->gid
!= VNOVAL
)
4982 VATTR_SET(&va
, va_gid
, uap
->gid
);
4985 error
= mac_vnode_check_setowner(ctx
, vp
, uap
->uid
, uap
->gid
);
4990 /* preflight and authorize attribute changes */
4991 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
4993 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
4995 error
= vnode_setattr(vp
, &va
, ctx
);
4999 * EACCES is only allowed from namei(); permissions failure should
5000 * return EPERM, so we need to translate the error code.
5002 if (error
== EACCES
)
5010 chown(__unused proc_t p
, struct chown_args
*uap
, int32_t *retval
)
5012 return chown1(vfs_context_current(), uap
, retval
, 1);
5016 lchown(__unused proc_t p
, struct lchown_args
*uap
, int32_t *retval
)
5018 /* Argument list identical, but machine generated; cast for chown1() */
5019 return chown1(vfs_context_current(), (struct chown_args
*)uap
, retval
, 0);
5023 * Set ownership given a file descriptor.
5027 fchown(__unused proc_t p
, struct fchown_args
*uap
, __unused
int32_t *retval
)
5029 struct vnode_attr va
;
5030 vfs_context_t ctx
= vfs_context_current();
5033 kauth_action_t action
;
5035 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
5036 AUDIT_ARG(fd
, uap
->fd
);
5038 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
5041 if ( (error
= vnode_getwithref(vp
)) ) {
5045 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
5048 if (uap
->uid
!= VNOVAL
)
5049 VATTR_SET(&va
, va_uid
, uap
->uid
);
5050 if (uap
->gid
!= VNOVAL
)
5051 VATTR_SET(&va
, va_gid
, uap
->gid
);
5054 /* chown calls are not allowed for resource forks. */
5055 if (vp
->v_flag
& VISNAMEDSTREAM
) {
5062 error
= mac_vnode_check_setowner(ctx
, vp
, uap
->uid
, uap
->gid
);
5067 /* preflight and authorize attribute changes */
5068 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
5070 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
5071 if (error
== EACCES
)
5075 error
= vnode_setattr(vp
, &va
, ctx
);
5078 (void)vnode_put(vp
);
5084 getutimes(user_addr_t usrtvp
, struct timespec
*tsp
)
5088 if (usrtvp
== USER_ADDR_NULL
) {
5089 struct timeval old_tv
;
5090 /* XXX Y2038 bug because of microtime argument */
5092 TIMEVAL_TO_TIMESPEC(&old_tv
, &tsp
[0]);
5095 if (IS_64BIT_PROCESS(current_proc())) {
5096 struct user64_timeval tv
[2];
5097 error
= copyin(usrtvp
, (void *)tv
, sizeof(tv
));
5100 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
5101 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
5103 struct user32_timeval tv
[2];
5104 error
= copyin(usrtvp
, (void *)tv
, sizeof(tv
));
5107 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
5108 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
5115 setutimes(vfs_context_t ctx
, vnode_t vp
, const struct timespec
*ts
,
5119 struct vnode_attr va
;
5120 kauth_action_t action
;
5122 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
5125 VATTR_SET(&va
, va_access_time
, ts
[0]);
5126 VATTR_SET(&va
, va_modify_time
, ts
[1]);
5128 va
.va_vaflags
|= VA_UTIMES_NULL
;
5131 /* utimes calls are not allowed for resource forks. */
5132 if (vp
->v_flag
& VISNAMEDSTREAM
) {
5139 error
= mac_vnode_check_setutimes(ctx
, vp
, ts
[0], ts
[1]);
5143 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0) {
5144 if (!nullflag
&& error
== EACCES
)
5149 /* since we may not need to auth anything, check here */
5150 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
5151 if (!nullflag
&& error
== EACCES
)
5155 error
= vnode_setattr(vp
, &va
, ctx
);
5162 * Set the access and modification times of a file.
5166 utimes(__unused proc_t p
, struct utimes_args
*uap
, __unused
int32_t *retval
)
5168 struct timespec ts
[2];
5171 struct nameidata nd
;
5172 vfs_context_t ctx
= vfs_context_current();
5175 * AUDIT: Needed to change the order of operations to do the
5176 * name lookup first because auditing wants the path.
5178 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
5179 UIO_USERSPACE
, uap
->path
, ctx
);
5186 * Fetch the user-supplied time. If usrtvp is USER_ADDR_NULL, we fetch
5187 * the current time instead.
5190 if ((error
= getutimes(usrtvp
, ts
)) != 0)
5193 error
= setutimes(ctx
, nd
.ni_vp
, ts
, usrtvp
== USER_ADDR_NULL
);
5196 vnode_put(nd
.ni_vp
);
5201 * Set the access and modification times of a file.
5205 futimes(__unused proc_t p
, struct futimes_args
*uap
, __unused
int32_t *retval
)
5207 struct timespec ts
[2];
5212 AUDIT_ARG(fd
, uap
->fd
);
5214 if ((error
= getutimes(usrtvp
, ts
)) != 0)
5216 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
5218 if((error
= vnode_getwithref(vp
))) {
5223 error
= setutimes(vfs_context_current(), vp
, ts
, usrtvp
== 0);
5230 * Truncate a file given its path name.
5234 truncate(__unused proc_t p
, struct truncate_args
*uap
, __unused
int32_t *retval
)
5237 struct vnode_attr va
;
5238 vfs_context_t ctx
= vfs_context_current();
5240 struct nameidata nd
;
5241 kauth_action_t action
;
5243 if (uap
->length
< 0)
5245 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
5246 UIO_USERSPACE
, uap
->path
, ctx
);
5247 if ((error
= namei(&nd
)))
5254 VATTR_SET(&va
, va_data_size
, uap
->length
);
5257 error
= mac_vnode_check_truncate(ctx
, NOCRED
, vp
);
5262 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
5264 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
5266 error
= vnode_setattr(vp
, &va
, ctx
);
5273 * Truncate a file given a file descriptor.
5277 ftruncate(proc_t p
, struct ftruncate_args
*uap
, int32_t *retval
)
5279 vfs_context_t ctx
= vfs_context_current();
5280 struct vnode_attr va
;
5282 struct fileproc
*fp
;
5286 AUDIT_ARG(fd
, uap
->fd
);
5287 if (uap
->length
< 0)
5290 if ( (error
= fp_lookup(p
,fd
,&fp
,0)) ) {
5294 if (fp
->f_fglob
->fg_type
== DTYPE_PSXSHM
) {
5295 error
= pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
);
5298 if (fp
->f_fglob
->fg_type
!= DTYPE_VNODE
) {
5303 vp
= (vnode_t
)fp
->f_fglob
->fg_data
;
5305 if ((fp
->f_fglob
->fg_flag
& FWRITE
) == 0) {
5306 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
5311 if ((error
= vnode_getwithref(vp
)) != 0) {
5315 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
5318 error
= mac_vnode_check_truncate(ctx
,
5319 fp
->f_fglob
->fg_cred
, vp
);
5321 (void)vnode_put(vp
);
5326 VATTR_SET(&va
, va_data_size
, uap
->length
);
5327 error
= vnode_setattr(vp
, &va
, ctx
);
5328 (void)vnode_put(vp
);
5336 * Sync an open file with synchronized I/O _file_ integrity completion
5340 fsync(proc_t p
, struct fsync_args
*uap
, __unused
int32_t *retval
)
5342 __pthread_testcancel(1);
5343 return(fsync_common(p
, uap
, MNT_WAIT
));
5348 * Sync an open file with synchronized I/O _file_ integrity completion
5350 * Notes: This is a legacy support function that does not test for
5351 * thread cancellation points.
5355 fsync_nocancel(proc_t p
, struct fsync_nocancel_args
*uap
, __unused
int32_t *retval
)
5357 return(fsync_common(p
, (struct fsync_args
*)uap
, MNT_WAIT
));
5362 * Sync an open file with synchronized I/O _data_ integrity completion
5366 fdatasync(proc_t p
, struct fdatasync_args
*uap
, __unused
int32_t *retval
)
5368 __pthread_testcancel(1);
5369 return(fsync_common(p
, (struct fsync_args
*)uap
, MNT_DWAIT
));
5376 * Common fsync code to support both synchronized I/O file integrity completion
5377 * (normal fsync) and synchronized I/O data integrity completion (fdatasync).
5379 * If 'flags' is MNT_DWAIT, the caller is requesting data integrity, which
5380 * will only guarantee that the file data contents are retrievable. If
5381 * 'flags' is MNT_WAIT, the caller is rewuesting file integrity, which also
5382 * includes additional metadata unnecessary for retrieving the file data
5383 * contents, such as atime, mtime, ctime, etc., also be committed to stable
5386 * Parameters: p The process
5387 * uap->fd The descriptor to synchronize
5388 * flags The data integrity flags
5390 * Returns: int Success
5391 * fp_getfvp:EBADF Bad file descriptor
5392 * fp_getfvp:ENOTSUP fd does not refer to a vnode
5393 * VNOP_FSYNC:??? unspecified
5395 * Notes: We use struct fsync_args because it is a short name, and all
5396 * caller argument structures are otherwise identical.
5399 fsync_common(proc_t p
, struct fsync_args
*uap
, int flags
)
5402 struct fileproc
*fp
;
5403 vfs_context_t ctx
= vfs_context_current();
5406 AUDIT_ARG(fd
, uap
->fd
);
5408 if ( (error
= fp_getfvp(p
, uap
->fd
, &fp
, &vp
)) )
5410 if ( (error
= vnode_getwithref(vp
)) ) {
5415 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
5417 error
= VNOP_FSYNC(vp
, flags
, ctx
);
5420 /* Sync resource fork shadow file if necessary. */
5422 (vp
->v_flag
& VISNAMEDSTREAM
) &&
5423 (vp
->v_parent
!= NULLVP
) &&
5424 vnode_isshadow(vp
) &&
5425 (fp
->f_flags
& FP_WRITTEN
)) {
5426 (void) vnode_flushnamedstream(vp
->v_parent
, vp
, ctx
);
5430 (void)vnode_put(vp
);
5436 * Duplicate files. Source must be a file, target must be a file or
5439 * XXX Copyfile authorisation checking is woefully inadequate, and will not
5440 * perform inheritance correctly.
5444 copyfile(__unused proc_t p
, struct copyfile_args
*uap
, __unused
int32_t *retval
)
5446 vnode_t tvp
, fvp
, tdvp
, sdvp
;
5447 struct nameidata fromnd
, tond
;
5449 vfs_context_t ctx
= vfs_context_current();
5451 /* Check that the flags are valid. */
5453 if (uap
->flags
& ~CPF_MASK
) {
5457 NDINIT(&fromnd
, LOOKUP
, SAVESTART
| AUDITVNPATH1
,
5458 UIO_USERSPACE
, uap
->from
, ctx
);
5459 if ((error
= namei(&fromnd
)))
5463 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
| AUDITVNPATH2
| CN_NBMOUNTLOOK
,
5464 UIO_USERSPACE
, uap
->to
, ctx
);
5465 if ((error
= namei(&tond
))) {
5472 if (!(uap
->flags
& CPF_OVERWRITE
)) {
5477 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
5482 if ((error
= vnode_authorize(tdvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
5488 * If source is the same as the destination (that is the
5489 * same inode number) then there is nothing to do.
5490 * (fixed to have POSIX semantics - CSM 3/2/98)
5495 error
= VNOP_COPYFILE(fvp
, tdvp
, tvp
, &tond
.ni_cnd
, uap
->mode
, uap
->flags
, ctx
);
5497 sdvp
= tond
.ni_startdir
;
5499 * nameidone has to happen before we vnode_put(tdvp)
5500 * since it may need to release the fs_nodelock on the tdvp
5511 if (fromnd
.ni_startdir
)
5512 vnode_put(fromnd
.ni_startdir
);
5522 * Rename files. Source and destination must either both be directories,
5523 * or both not be directories. If target is a directory, it must be empty.
5527 rename(__unused proc_t p
, struct rename_args
*uap
, __unused
int32_t *retval
)
5531 struct nameidata fromnd
, tond
;
5532 vfs_context_t ctx
= vfs_context_current();
5538 char *from_name
= NULL
, *to_name
= NULL
;
5539 int from_len
=0, to_len
=0;
5540 int holding_mntlock
;
5541 mount_t locked_mp
= NULL
;
5544 fse_info from_finfo
, to_finfo
;
5546 int from_truncated
=0, to_truncated
;
5548 holding_mntlock
= 0;
5555 NDINIT(&fromnd
, DELETE
, WANTPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->from
, ctx
);
5557 if ( (error
= namei(&fromnd
)) )
5559 fdvp
= fromnd
.ni_dvp
;
5563 error
= mac_vnode_check_rename_from(ctx
, fdvp
, fvp
, &fromnd
.ni_cnd
);
5568 NDINIT(&tond
, RENAME
, WANTPARENT
| AUDITVNPATH2
| CN_NBMOUNTLOOK
, UIO_USERSPACE
, uap
->to
, ctx
);
5569 if (fvp
->v_type
== VDIR
)
5570 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
5572 if ( (error
= namei(&tond
)) ) {
5574 * Translate error code for rename("dir1", "dir2/.").
5576 if (error
== EISDIR
&& fvp
->v_type
== VDIR
)
5584 error
= mac_vnode_check_rename_to(ctx
,
5585 tdvp
, tvp
, fdvp
== tdvp
, &tond
.ni_cnd
);
5591 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
5594 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
5604 * If the source and destination are the same (i.e. they're
5605 * links to the same vnode) and the target file system is
5606 * case sensitive, then there is nothing to do.
5612 * Note: if _PC_CASE_SENSITIVE selector isn't supported,
5613 * then assume that this file system is case sensitive.
5615 if (VNOP_PATHCONF(fvp
, _PC_CASE_SENSITIVE
, &pathconf_val
, ctx
) != 0 ||
5616 pathconf_val
!= 0) {
5624 * If tvp is a directory and not the same as fdvp, or tdvp is not
5625 * the same as fdvp, the node is moving between directories and we
5626 * need rights to remove from the old and add to the new.
5628 * If tvp already exists and is not a directory, we need to be
5629 * allowed to delete it.
5631 * Note that we do not inherit when renaming.
5633 * XXX This needs to be revisited to implement the deferred-inherit bit
5639 if ((tvp
!= NULL
) && vnode_isdir(tvp
)) {
5642 } else if (tdvp
!= fdvp
) {
5646 * must have delete rights to remove the old name even in
5647 * the simple case of fdvp == tdvp.
5649 * If fvp is a directory, and we are changing it's parent,
5650 * then we also need rights to rewrite its ".." entry as well.
5652 if (vnode_isdir(fvp
)) {
5653 if ((error
= vnode_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
| KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
)) != 0)
5656 if ((error
= vnode_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
, ctx
)) != 0)
5660 /* moving into tdvp or tvp, must have rights to add */
5661 if ((error
= vnode_authorize(((tvp
!= NULL
) && vnode_isdir(tvp
)) ? tvp
: tdvp
,
5663 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
5666 * We could encounter a race where after doing the namei, tvp stops
5667 * being valid. If so, simply re-drive the rename call from the
5670 if (error
== ENOENT
) {
5676 /* node staying in same directory, must be allowed to add new name */
5677 if ((error
= vnode_authorize(fdvp
, NULL
,
5678 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
5681 /* overwriting tvp */
5682 if ((tvp
!= NULL
) && !vnode_isdir(tvp
) &&
5683 ((error
= vnode_authorize(tvp
, tdvp
, KAUTH_VNODE_DELETE
, ctx
)) != 0)) {
5685 * We could encounter a race where after doing the namei, tvp stops
5686 * being valid. If so, simply re-drive the rename call from the
5689 if (error
== ENOENT
) {
5695 /* XXX more checks? */
5698 /* authorization denied */
5703 * Allow the renaming of mount points.
5704 * - target must not exist
5705 * - target must reside in the same directory as source
5706 * - union mounts cannot be renamed
5707 * - "/" cannot be renamed
5709 if ((fvp
->v_flag
& VROOT
) &&
5710 (fvp
->v_type
== VDIR
) &&
5712 (fvp
->v_mountedhere
== NULL
) &&
5714 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
5715 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
5718 /* switch fvp to the covered vnode */
5719 coveredvp
= fvp
->v_mount
->mnt_vnodecovered
;
5720 if ( (vnode_getwithref(coveredvp
)) ) {
5730 * Check for cross-device rename.
5732 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
5733 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
5738 * Avoid renaming "." and "..".
5740 if (fvp
->v_type
== VDIR
&&
5742 (fromnd
.ni_cnd
.cn_namelen
== 1 && fromnd
.ni_cnd
.cn_nameptr
[0] == '.') ||
5743 ((fromnd
.ni_cnd
.cn_flags
| tond
.ni_cnd
.cn_flags
) & ISDOTDOT
)) ) {
5748 * The following edge case is caught here:
5749 * (to cannot be a descendent of from)
5762 if (tdvp
->v_parent
== fvp
) {
5768 * If source is the same as the destination (that is the
5769 * same inode number) then there is nothing to do...
5770 * EXCEPT if the underlying file system supports case
5771 * insensitivity and is case preserving. In this case
5772 * the file system needs to handle the special case of
5773 * getting the same vnode as target (fvp) and source (tvp).
5775 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
5776 * and _PC_CASE_PRESERVING can have this exception, and they need to
5777 * handle the special case of getting the same vnode as target and
5778 * source. NOTE: Then the target is unlocked going into vnop_rename,
5779 * so not to cause locking problems. There is a single reference on tvp.
5781 * NOTE - that fvp == tvp also occurs if they are hard linked and
5782 * that correct behaviour then is just to return success without doing
5785 if (fvp
== tvp
&& fdvp
== tdvp
) {
5786 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
5787 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
5788 fromnd
.ni_cnd
.cn_namelen
)) {
5793 if (holding_mntlock
&& fvp
->v_mount
!= locked_mp
) {
5795 * we're holding a reference and lock
5796 * on locked_mp, but it no longer matches
5797 * what we want to do... so drop our hold
5799 mount_unlock_renames(locked_mp
);
5800 mount_drop(locked_mp
, 0);
5801 holding_mntlock
= 0;
5803 if (tdvp
!= fdvp
&& fvp
->v_type
== VDIR
) {
5805 * serialize renames that re-shape
5806 * the tree... if holding_mntlock is
5807 * set, then we're ready to go...
5809 * first need to drop the iocounts
5810 * we picked up, second take the
5811 * lock to serialize the access,
5812 * then finally start the lookup
5813 * process over with the lock held
5815 if (!holding_mntlock
) {
5817 * need to grab a reference on
5818 * the mount point before we
5819 * drop all the iocounts... once
5820 * the iocounts are gone, the mount
5823 locked_mp
= fvp
->v_mount
;
5824 mount_ref(locked_mp
, 0);
5827 * nameidone has to happen before we vnode_put(tvp)
5828 * since it may need to release the fs_nodelock on the tvp
5837 * nameidone has to happen before we vnode_put(fdvp)
5838 * since it may need to release the fs_nodelock on the fvp
5845 mount_lock_renames(locked_mp
);
5846 holding_mntlock
= 1;
5852 * when we dropped the iocounts to take
5853 * the lock, we allowed the identity of
5854 * the various vnodes to change... if they did,
5855 * we may no longer be dealing with a rename
5856 * that reshapes the tree... once we're holding
5857 * the iocounts, the vnodes can't change type
5858 * so we're free to drop the lock at this point
5861 if (holding_mntlock
) {
5862 mount_unlock_renames(locked_mp
);
5863 mount_drop(locked_mp
, 0);
5864 holding_mntlock
= 0;
5867 // save these off so we can later verify that fvp is the same
5868 oname
= fvp
->v_name
;
5869 oparent
= fvp
->v_parent
;
5872 need_event
= need_fsevent(FSE_RENAME
, fvp
);
5874 get_fse_info(fvp
, &from_finfo
, ctx
);
5877 get_fse_info(tvp
, &to_finfo
, ctx
);
5882 #endif /* CONFIG_FSE */
5884 if (need_event
|| kauth_authorize_fileop_has_listeners()) {
5885 GET_PATH(from_name
);
5886 if (from_name
== NULL
) {
5891 from_len
= safe_getpath(fdvp
, fromnd
.ni_cnd
.cn_nameptr
, from_name
, MAXPATHLEN
, &from_truncated
);
5894 if (to_name
== NULL
) {
5899 to_len
= safe_getpath(tdvp
, tond
.ni_cnd
.cn_nameptr
, to_name
, MAXPATHLEN
, &to_truncated
);
5902 error
= VNOP_RENAME(fdvp
, fvp
, &fromnd
.ni_cnd
,
5903 tdvp
, tvp
, &tond
.ni_cnd
,
5906 if (holding_mntlock
) {
5908 * we can drop our serialization
5911 mount_unlock_renames(locked_mp
);
5912 mount_drop(locked_mp
, 0);
5913 holding_mntlock
= 0;
5917 * We may encounter a race in the VNOP where the destination didn't
5918 * exist when we did the namei, but it does by the time we go and
5919 * try to create the entry. In this case, we should re-drive this rename
5920 * call from the top again. Currently, only HFS bubbles out ERECYCLE,
5921 * but other filesystems susceptible to this race could return it, too.
5923 if (error
== ERECYCLE
) {
5930 /* call out to allow 3rd party notification of rename.
5931 * Ignore result of kauth_authorize_fileop call.
5933 kauth_authorize_fileop(vfs_context_ucred(ctx
),
5934 KAUTH_FILEOP_RENAME
,
5935 (uintptr_t)from_name
, (uintptr_t)to_name
);
5938 if (from_name
!= NULL
&& to_name
!= NULL
) {
5939 if (from_truncated
|| to_truncated
) {
5940 // set it here since only the from_finfo gets reported up to user space
5941 from_finfo
.mode
|= FSE_TRUNCATED_PATH
;
5944 add_fsevent(FSE_RENAME
, ctx
,
5945 FSE_ARG_STRING
, from_len
, from_name
,
5946 FSE_ARG_FINFO
, &from_finfo
,
5947 FSE_ARG_STRING
, to_len
, to_name
,
5948 FSE_ARG_FINFO
, &to_finfo
,
5951 add_fsevent(FSE_RENAME
, ctx
,
5952 FSE_ARG_STRING
, from_len
, from_name
,
5953 FSE_ARG_FINFO
, &from_finfo
,
5954 FSE_ARG_STRING
, to_len
, to_name
,
5958 #endif /* CONFIG_FSE */
5961 * update filesystem's mount point data
5964 char *cp
, *pathend
, *mpname
;
5970 mp
= fvp
->v_mountedhere
;
5972 if (vfs_busy(mp
, LK_NOWAIT
)) {
5976 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
5978 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
5980 /* find current mount point prefix */
5981 pathend
= &mp
->mnt_vfsstat
.f_mntonname
[0];
5982 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
5986 /* find last component of target name */
5987 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
5991 /* append name to prefix */
5992 maxlen
= MAXPATHLEN
- (pathend
- mp
->mnt_vfsstat
.f_mntonname
);
5993 bzero(pathend
, maxlen
);
5994 strlcpy(pathend
, mpname
, maxlen
);
5996 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
6001 * fix up name & parent pointers. note that we first
6002 * check that fvp has the same name/parent pointers it
6003 * had before the rename call... this is a 'weak' check
6006 if (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
) {
6009 update_flags
= VNODE_UPDATE_NAME
;
6012 update_flags
|= VNODE_UPDATE_PARENT
;
6014 vnode_update_identity(fvp
, tdvp
, tond
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_namelen
, tond
.ni_cnd
.cn_hash
, update_flags
);
6017 if (to_name
!= NULL
) {
6018 RELEASE_PATH(to_name
);
6021 if (from_name
!= NULL
) {
6022 RELEASE_PATH(from_name
);
6025 if (holding_mntlock
) {
6026 mount_unlock_renames(locked_mp
);
6027 mount_drop(locked_mp
, 0);
6028 holding_mntlock
= 0;
6032 * nameidone has to happen before we vnode_put(tdvp)
6033 * since it may need to release the fs_nodelock on the tdvp
6043 * nameidone has to happen before we vnode_put(fdvp)
6044 * since it may need to release the fs_nodelock on the fdvp
6054 * If things changed after we did the namei, then we will re-drive
6055 * this rename call from the top.
6066 * Make a directory file.
6068 * Returns: 0 Success
6071 * vnode_authorize:???
6076 mkdir1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
6080 int update_flags
= 0;
6081 struct nameidata nd
;
6083 AUDIT_ARG(mode
, vap
->va_mode
);
6084 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
6085 UIO_USERSPACE
, path
, ctx
);
6086 nd
.ni_cnd
.cn_flags
|= WILLBEDIR
;
6098 VATTR_SET(vap
, va_type
, VDIR
);
6101 error
= mac_vnode_check_create(ctx
,
6102 nd
.ni_dvp
, &nd
.ni_cnd
, vap
);
6107 /* authorize addition of a directory to the parent */
6108 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
)) != 0)
6112 /* make the directory */
6113 if ((error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
)) != 0)
6116 // Make sure the name & parent pointers are hooked up
6117 if (vp
->v_name
== NULL
)
6118 update_flags
|= VNODE_UPDATE_NAME
;
6119 if (vp
->v_parent
== NULLVP
)
6120 update_flags
|= VNODE_UPDATE_PARENT
;
6123 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
6126 add_fsevent(FSE_CREATE_DIR
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
6131 * nameidone has to happen before we vnode_put(dvp)
6132 * since it may need to release the fs_nodelock on the dvp
6144 * mkdir_extended: Create a directory; with extended security (ACL).
6146 * Parameters: p Process requesting to create the directory
6147 * uap User argument descriptor (see below)
6150 * Indirect: uap->path Path of directory to create
6151 * uap->mode Access permissions to set
6152 * uap->xsecurity ACL to set
6154 * Returns: 0 Success
6159 mkdir_extended(proc_t p
, struct mkdir_extended_args
*uap
, __unused
int32_t *retval
)
6162 kauth_filesec_t xsecdst
;
6163 struct vnode_attr va
;
6165 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
6168 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
6169 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
6173 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
6174 if (xsecdst
!= NULL
)
6175 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
6177 ciferror
= mkdir1(vfs_context_current(), uap
->path
, &va
);
6178 if (xsecdst
!= NULL
)
6179 kauth_filesec_free(xsecdst
);
6184 mkdir(proc_t p
, struct mkdir_args
*uap
, __unused
int32_t *retval
)
6186 struct vnode_attr va
;
6189 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
6191 return(mkdir1(vfs_context_current(), uap
->path
, &va
));
6195 * Remove a directory file.
6199 rmdir(__unused proc_t p
, struct rmdir_args
*uap
, __unused
int32_t *retval
)
6203 struct nameidata nd
;
6204 vfs_context_t ctx
= vfs_context_current();
6207 uint32_t oldvp_id
= UINT32_MAX
;
6210 * This loop exists to restart rmdir in the unlikely case that two
6211 * processes are simultaneously trying to remove the same directory
6212 * containing orphaned appleDouble files.
6217 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
6218 UIO_USERSPACE
, uap
->path
, ctx
);
6228 * If being restarted check if the new vp
6229 * still has the same v_id.
6231 if (oldvp_id
!= UINT32_MAX
&& oldvp_id
!= vp
->v_id
) {
6236 if (vp
->v_type
!= VDIR
) {
6238 * rmdir only deals with directories
6241 } else if (dvp
== vp
) {
6243 * No rmdir "." please.
6246 } else if (vp
->v_flag
& VROOT
) {
6248 * The root of a mounted filesystem cannot be deleted.
6253 error
= mac_vnode_check_unlink(ctx
, dvp
,
6257 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, ctx
);
6262 int has_listeners
= 0;
6268 need_event
= need_fsevent(FSE_DELETE
, dvp
);
6270 get_fse_info(vp
, &finfo
, ctx
);
6273 has_listeners
= kauth_authorize_fileop_has_listeners();
6274 if (need_event
|| has_listeners
) {
6281 len
= safe_getpath(vp
, NULL
, path
, MAXPATHLEN
, &truncated
);
6284 finfo
.mode
|= FSE_TRUNCATED_PATH
;
6289 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, ctx
);
6292 * Special case to remove orphaned AppleDouble
6293 * files. I don't like putting this in the kernel,
6294 * but carbon does not like putting this in carbon either,
6297 if (error
== ENOTEMPTY
) {
6298 error
= rmdir_remove_orphaned_appleDouble(vp
, ctx
, &restart_flag
);
6299 if (error
== EBUSY
) {
6300 oldvp_id
= vp
->v_id
;
6306 * Assuming everything went well, we will try the RMDIR again
6309 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, ctx
);
6313 * Call out to allow 3rd party notification of delete.
6314 * Ignore result of kauth_authorize_fileop call.
6317 if (has_listeners
) {
6318 kauth_authorize_fileop(vfs_context_ucred(ctx
),
6319 KAUTH_FILEOP_DELETE
,
6324 if (vp
->v_flag
& VISHARDLINK
) {
6325 // see the comment in unlink1() about why we update
6326 // the parent of a hard link when it is removed
6327 vnode_update_identity(vp
, NULL
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
6332 add_fsevent(FSE_DELETE
, ctx
,
6333 FSE_ARG_STRING
, len
, path
,
6334 FSE_ARG_FINFO
, &finfo
,
6345 * nameidone has to happen before we vnode_put(dvp)
6346 * since it may need to release the fs_nodelock on the dvp
6353 if (restart_flag
== 0) {
6354 wakeup_one((caddr_t
)vp
);
6357 tsleep(vp
, PVFS
, "rm AD", 1);
6359 } while (restart_flag
!= 0);
6365 /* Get direntry length padded to 8 byte alignment */
6366 #define DIRENT64_LEN(namlen) \
6367 ((sizeof(struct direntry) + (namlen) - (MAXPATHLEN-1) + 7) & ~7)
6370 vnode_readdir64(struct vnode
*vp
, struct uio
*uio
, int flags
, int *eofflag
,
6371 int *numdirent
, vfs_context_t ctxp
)
6373 /* Check if fs natively supports VNODE_READDIR_EXTENDED */
6374 if (vp
->v_mount
->mnt_vtable
->vfc_vfsflags
& VFC_VFSREADDIR_EXTENDED
) {
6375 return VNOP_READDIR(vp
, uio
, flags
, eofflag
, numdirent
, ctxp
);
6380 struct direntry entry64
;
6386 * Our kernel buffer needs to be smaller since re-packing
6387 * will expand each dirent. The worse case (when the name
6388 * length is 3) corresponds to a struct direntry size of 32
6389 * bytes (8-byte aligned) and a struct dirent size of 12 bytes
6390 * (4-byte aligned). So having a buffer that is 3/8 the size
6391 * will prevent us from reading more than we can pack.
6393 * Since this buffer is wired memory, we will limit the
6394 * buffer size to a maximum of 32K. We would really like to
6395 * use 32K in the MIN(), but we use magic number 87371 to
6396 * prevent uio_resid() * 3 / 8 from overflowing.
6398 bufsize
= 3 * MIN(uio_resid(uio
), 87371) / 8;
6399 MALLOC(bufptr
, void *, bufsize
, M_TEMP
, M_WAITOK
);
6400 if (bufptr
== NULL
) {
6404 auio
= uio_create(1, 0, UIO_SYSSPACE
, UIO_READ
);
6405 uio_addiov(auio
, (uintptr_t)bufptr
, bufsize
);
6406 auio
->uio_offset
= uio
->uio_offset
;
6408 error
= VNOP_READDIR(vp
, auio
, 0, eofflag
, numdirent
, ctxp
);
6410 dep
= (struct dirent
*)bufptr
;
6411 bytesread
= bufsize
- uio_resid(auio
);
6414 * Convert all the entries and copy them out to user's buffer.
6416 while (error
== 0 && (char *)dep
< ((char *)bufptr
+ bytesread
)) {
6417 /* Convert a dirent to a dirent64. */
6418 entry64
.d_ino
= dep
->d_ino
;
6419 entry64
.d_seekoff
= 0;
6420 entry64
.d_reclen
= DIRENT64_LEN(dep
->d_namlen
);
6421 entry64
.d_namlen
= dep
->d_namlen
;
6422 entry64
.d_type
= dep
->d_type
;
6423 bcopy(dep
->d_name
, entry64
.d_name
, dep
->d_namlen
+ 1);
6425 /* Move to next entry. */
6426 dep
= (struct dirent
*)((char *)dep
+ dep
->d_reclen
);
6428 /* Copy entry64 to user's buffer. */
6429 error
= uiomove((caddr_t
)&entry64
, entry64
.d_reclen
, uio
);
6432 /* Update the real offset using the offset we got from VNOP_READDIR. */
6434 uio
->uio_offset
= auio
->uio_offset
;
6437 FREE(bufptr
, M_TEMP
);
6443 * Read a block of directory entries in a file system independent format.
6446 getdirentries_common(int fd
, user_addr_t bufp
, user_size_t bufsize
, ssize_t
*bytesread
,
6447 off_t
*offset
, int flags
)
6450 struct vfs_context context
= *vfs_context_current(); /* local copy */
6451 struct fileproc
*fp
;
6453 int spacetype
= proc_is64bit(vfs_context_proc(&context
)) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6455 int error
, eofflag
, numdirent
;
6456 char uio_buf
[ UIO_SIZEOF(1) ];
6458 error
= fp_getfvp(vfs_context_proc(&context
), fd
, &fp
, &vp
);
6462 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
6463 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
6469 error
= mac_file_check_change_offset(vfs_context_ucred(&context
), fp
->f_fglob
);
6473 if ( (error
= vnode_getwithref(vp
)) ) {
6476 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
6479 if (vp
->v_type
!= VDIR
) {
6480 (void)vnode_put(vp
);
6486 error
= mac_vnode_check_readdir(&context
, vp
);
6488 (void)vnode_put(vp
);
6493 loff
= fp
->f_fglob
->fg_offset
;
6494 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
6495 uio_addiov(auio
, bufp
, bufsize
);
6497 if (flags
& VNODE_READDIR_EXTENDED
) {
6498 error
= vnode_readdir64(vp
, auio
, flags
, &eofflag
, &numdirent
, &context
);
6499 fp
->f_fglob
->fg_offset
= uio_offset(auio
);
6501 error
= VNOP_READDIR(vp
, auio
, 0, &eofflag
, &numdirent
, &context
);
6502 fp
->f_fglob
->fg_offset
= uio_offset(auio
);
6505 (void)vnode_put(vp
);
6509 if ((user_ssize_t
)bufsize
== uio_resid(auio
)){
6510 if (union_dircheckp
) {
6511 error
= union_dircheckp(&vp
, fp
, &context
);
6518 if ((vp
->v_flag
& VROOT
) && (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
6519 struct vnode
*tvp
= vp
;
6520 vp
= vp
->v_mount
->mnt_vnodecovered
;
6521 vnode_getwithref(vp
);
6523 fp
->f_fglob
->fg_data
= (caddr_t
) vp
;
6524 fp
->f_fglob
->fg_offset
= 0;
6536 *bytesread
= bufsize
- uio_resid(auio
);
6544 getdirentries(__unused
struct proc
*p
, struct getdirentries_args
*uap
, int32_t *retval
)
6550 AUDIT_ARG(fd
, uap
->fd
);
6551 error
= getdirentries_common(uap
->fd
, uap
->buf
, uap
->count
, &bytesread
, &offset
, 0);
6554 if (proc_is64bit(p
)) {
6555 user64_long_t base
= (user64_long_t
)offset
;
6556 error
= copyout((caddr_t
)&base
, uap
->basep
, sizeof(user64_long_t
));
6558 user32_long_t base
= (user32_long_t
)offset
;
6559 error
= copyout((caddr_t
)&base
, uap
->basep
, sizeof(user32_long_t
));
6561 *retval
= bytesread
;
6567 getdirentries64(__unused
struct proc
*p
, struct getdirentries64_args
*uap
, user_ssize_t
*retval
)
6573 AUDIT_ARG(fd
, uap
->fd
);
6574 error
= getdirentries_common(uap
->fd
, uap
->buf
, uap
->bufsize
, &bytesread
, &offset
, VNODE_READDIR_EXTENDED
);
6577 *retval
= bytesread
;
6578 error
= copyout((caddr_t
)&offset
, uap
->position
, sizeof(off_t
));
6585 * Set the mode mask for creation of filesystem nodes.
6586 * XXX implement xsecurity
6588 #define UMASK_NOXSECURITY (void *)1 /* leave existing xsecurity alone */
6590 umask1(proc_t p
, int newmask
, __unused kauth_filesec_t fsec
, int32_t *retval
)
6592 struct filedesc
*fdp
;
6594 AUDIT_ARG(mask
, newmask
);
6597 *retval
= fdp
->fd_cmask
;
6598 fdp
->fd_cmask
= newmask
& ALLPERMS
;
6604 * umask_extended: Set the mode mask for creation of filesystem nodes; with extended security (ACL).
6606 * Parameters: p Process requesting to set the umask
6607 * uap User argument descriptor (see below)
6608 * retval umask of the process (parameter p)
6610 * Indirect: uap->newmask umask to set
6611 * uap->xsecurity ACL to set
6613 * Returns: 0 Success
6618 umask_extended(proc_t p
, struct umask_extended_args
*uap
, int32_t *retval
)
6621 kauth_filesec_t xsecdst
;
6623 xsecdst
= KAUTH_FILESEC_NONE
;
6624 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
6625 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
6628 xsecdst
= KAUTH_FILESEC_NONE
;
6631 ciferror
= umask1(p
, uap
->newmask
, xsecdst
, retval
);
6633 if (xsecdst
!= KAUTH_FILESEC_NONE
)
6634 kauth_filesec_free(xsecdst
);
6639 umask(proc_t p
, struct umask_args
*uap
, int32_t *retval
)
6641 return(umask1(p
, uap
->newmask
, UMASK_NOXSECURITY
, retval
));
6645 * Void all references to file by ripping underlying filesystem
6650 revoke(proc_t p
, struct revoke_args
*uap
, __unused
int32_t *retval
)
6653 struct vnode_attr va
;
6654 vfs_context_t ctx
= vfs_context_current();
6656 struct nameidata nd
;
6658 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
6659 UIO_USERSPACE
, uap
->path
, ctx
);
6667 if (!(vnode_ischr(vp
) || vnode_isblk(vp
))) {
6672 if (vnode_isblk(vp
) && vnode_ismountedon(vp
)) {
6678 error
= mac_vnode_check_revoke(ctx
, vp
);
6684 VATTR_WANTED(&va
, va_uid
);
6685 if ((error
= vnode_getattr(vp
, &va
, ctx
)))
6687 if (kauth_cred_getuid(vfs_context_ucred(ctx
)) != va
.va_uid
&&
6688 (error
= suser(vfs_context_ucred(ctx
), &p
->p_acflag
)))
6690 if (vp
->v_usecount
> 0 || (vnode_isaliased(vp
)))
6691 VNOP_REVOKE(vp
, REVOKEALL
, ctx
);
6699 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
6700 * The following system calls are designed to support features
6701 * which are specific to the HFS & HFS Plus volume formats
6704 #ifdef __APPLE_API_OBSOLETE
6706 /************************************************/
6707 /* *** Following calls will be deleted soon *** */
6708 /************************************************/
6711 * Make a complex file. A complex file is one with multiple forks (data streams)
6715 mkcomplex(__unused proc_t p
, __unused
struct mkcomplex_args
*uap
, __unused
int32_t *retval
)
6721 * Extended stat call which returns volumeid and vnodeid as well as other info
6725 statv(__unused proc_t p
,
6726 __unused
struct statv_args
*uap
,
6727 __unused
int32_t *retval
)
6729 return (ENOTSUP
); /* We'll just return an error for now */
6731 } /* end of statv system call */
6734 * Extended lstat call which returns volumeid and vnodeid as well as other info
6738 lstatv(__unused proc_t p
,
6739 __unused
struct lstatv_args
*uap
,
6740 __unused
int32_t *retval
)
6742 return (ENOTSUP
); /* We'll just return an error for now */
6743 } /* end of lstatv system call */
6746 * Extended fstat call which returns volumeid and vnodeid as well as other info
6750 fstatv(__unused proc_t p
,
6751 __unused
struct fstatv_args
*uap
,
6752 __unused
int32_t *retval
)
6754 return (ENOTSUP
); /* We'll just return an error for now */
6755 } /* end of fstatv system call */
6758 /************************************************/
6759 /* *** Preceding calls will be deleted soon *** */
6760 /************************************************/
6762 #endif /* __APPLE_API_OBSOLETE */
6765 * Obtain attribute information on objects in a directory while enumerating
6766 * the directory. This call does not yet support union mounted directories.
6768 * 1.union mounted directories.
6773 getdirentriesattr (proc_t p
, struct getdirentriesattr_args
*uap
, int32_t *retval
)
6776 struct fileproc
*fp
;
6778 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6783 struct attrlist attributelist
;
6784 vfs_context_t ctx
= vfs_context_current();
6786 char uio_buf
[ UIO_SIZEOF(1) ];
6787 kauth_action_t action
;
6791 /* Get the attributes into kernel space */
6792 if ((error
= copyin(uap
->alist
, (caddr_t
)&attributelist
, sizeof(attributelist
)))) {
6795 if ((error
= copyin(uap
->count
, (caddr_t
)&count
, sizeof(count
)))) {
6798 if ( (error
= fp_getfvp(p
, fd
, &fp
, &vp
)) ) {
6801 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
6802 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
6809 error
= mac_file_check_change_offset(vfs_context_ucred(ctx
),
6816 if ( (error
= vnode_getwithref(vp
)) )
6819 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
6821 if (vp
->v_type
!= VDIR
) {
6822 (void)vnode_put(vp
);
6828 error
= mac_vnode_check_readdir(ctx
, vp
);
6830 (void)vnode_put(vp
);
6835 /* set up the uio structure which will contain the users return buffer */
6836 loff
= fp
->f_fglob
->fg_offset
;
6837 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
6838 &uio_buf
[0], sizeof(uio_buf
));
6839 uio_addiov(auio
, uap
->buffer
, uap
->buffersize
);
6842 * If the only item requested is file names, we can let that past with
6843 * just LIST_DIRECTORY. If they want any other attributes, that means
6844 * they need SEARCH as well.
6846 action
= KAUTH_VNODE_LIST_DIRECTORY
;
6847 if ((attributelist
.commonattr
& ~ATTR_CMN_NAME
) ||
6848 attributelist
.fileattr
|| attributelist
.dirattr
)
6849 action
|= KAUTH_VNODE_SEARCH
;
6851 if ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) == 0) {
6853 /* Believe it or not, uap->options only has 32-bits of valid
6854 * info, so truncate before extending again */
6855 error
= VNOP_READDIRATTR(vp
, &attributelist
, auio
,
6857 (u_long
)(uint32_t)uap
->options
, &newstate
, &eofflag
,
6860 (void)vnode_put(vp
);
6864 fp
->f_fglob
->fg_offset
= uio_offset(auio
); /* should be multiple of dirent, not variable */
6866 if ((error
= copyout((caddr_t
) &count
, uap
->count
, sizeof(count
))))
6868 if ((error
= copyout((caddr_t
) &newstate
, uap
->newstate
, sizeof(newstate
))))
6870 if ((error
= copyout((caddr_t
) &loff
, uap
->basep
, sizeof(loff
))))
6873 *retval
= eofflag
; /* similar to getdirentries */
6877 return (error
); /* return error earlier, an retval of 0 or 1 now */
6879 } /* end of getdirentryattr system call */
6882 * Exchange data between two files
6887 exchangedata (__unused proc_t p
, struct exchangedata_args
*uap
, __unused
int32_t *retval
)
6890 struct nameidata fnd
, snd
;
6891 vfs_context_t ctx
= vfs_context_current();
6895 u_int32_t nameiflags
;
6899 int from_truncated
=0, to_truncated
=0;
6901 fse_info f_finfo
, s_finfo
;
6905 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
6907 NDINIT(&fnd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
6908 UIO_USERSPACE
, uap
->path1
, ctx
);
6910 error
= namei(&fnd
);
6917 NDINIT(&snd
, LOOKUP
| CN_NBMOUNTLOOK
, nameiflags
| AUDITVNPATH2
,
6918 UIO_USERSPACE
, uap
->path2
, ctx
);
6920 error
= namei(&snd
);
6929 * if the files are the same, return an inval error
6937 * if the files are on different volumes, return an error
6939 if (svp
->v_mount
!= fvp
->v_mount
) {
6945 error
= mac_vnode_check_exchangedata(ctx
,
6950 if (((error
= vnode_authorize(fvp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, ctx
)) != 0) ||
6951 ((error
= vnode_authorize(svp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, ctx
)) != 0))
6956 need_fsevent(FSE_EXCHANGE
, fvp
) ||
6958 kauth_authorize_fileop_has_listeners()) {
6961 if (fpath
== NULL
|| spath
== NULL
) {
6966 flen
= safe_getpath(fvp
, NULL
, fpath
, MAXPATHLEN
, &from_truncated
);
6967 slen
= safe_getpath(svp
, NULL
, spath
, MAXPATHLEN
, &to_truncated
);
6970 get_fse_info(fvp
, &f_finfo
, ctx
);
6971 get_fse_info(svp
, &s_finfo
, ctx
);
6972 if (from_truncated
|| to_truncated
) {
6973 // set it here since only the f_finfo gets reported up to user space
6974 f_finfo
.mode
|= FSE_TRUNCATED_PATH
;
6978 /* Ok, make the call */
6979 error
= VNOP_EXCHANGE(fvp
, svp
, 0, ctx
);
6982 const char *tmpname
;
6984 if (fpath
!= NULL
&& spath
!= NULL
) {
6985 /* call out to allow 3rd party notification of exchangedata.
6986 * Ignore result of kauth_authorize_fileop call.
6988 kauth_authorize_fileop(vfs_context_ucred(ctx
), KAUTH_FILEOP_EXCHANGE
,
6989 (uintptr_t)fpath
, (uintptr_t)spath
);
6993 tmpname
= fvp
->v_name
;
6994 fvp
->v_name
= svp
->v_name
;
6995 svp
->v_name
= tmpname
;
6997 if (fvp
->v_parent
!= svp
->v_parent
) {
7000 tmp
= fvp
->v_parent
;
7001 fvp
->v_parent
= svp
->v_parent
;
7002 svp
->v_parent
= tmp
;
7004 name_cache_unlock();
7007 if (fpath
!= NULL
&& spath
!= NULL
) {
7008 add_fsevent(FSE_EXCHANGE
, ctx
,
7009 FSE_ARG_STRING
, flen
, fpath
,
7010 FSE_ARG_FINFO
, &f_finfo
,
7011 FSE_ARG_STRING
, slen
, spath
,
7012 FSE_ARG_FINFO
, &s_finfo
,
7020 RELEASE_PATH(fpath
);
7022 RELEASE_PATH(spath
);
7033 searchfs(proc_t p
, struct searchfs_args
*uap
, __unused
int32_t *retval
)
7038 struct nameidata nd
;
7039 struct user64_fssearchblock searchblock
;
7040 struct searchstate
*state
;
7041 struct attrlist
*returnattrs
;
7042 struct timeval timelimit
;
7043 void *searchparams1
,*searchparams2
;
7045 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
7046 uint32_t nummatches
;
7048 uint32_t nameiflags
;
7049 vfs_context_t ctx
= vfs_context_current();
7050 char uio_buf
[ UIO_SIZEOF(1) ];
7052 /* Start by copying in fsearchblock paramater list */
7053 if (IS_64BIT_PROCESS(p
)) {
7054 error
= copyin(uap
->searchblock
, (caddr_t
) &searchblock
, sizeof(searchblock
));
7055 timelimit
.tv_sec
= searchblock
.timelimit
.tv_sec
;
7056 timelimit
.tv_usec
= searchblock
.timelimit
.tv_usec
;
7059 struct user32_fssearchblock tmp_searchblock
;
7061 error
= copyin(uap
->searchblock
, (caddr_t
) &tmp_searchblock
, sizeof(tmp_searchblock
));
7062 // munge into 64-bit version
7063 searchblock
.returnattrs
= CAST_USER_ADDR_T(tmp_searchblock
.returnattrs
);
7064 searchblock
.returnbuffer
= CAST_USER_ADDR_T(tmp_searchblock
.returnbuffer
);
7065 searchblock
.returnbuffersize
= tmp_searchblock
.returnbuffersize
;
7066 searchblock
.maxmatches
= tmp_searchblock
.maxmatches
;
7068 * These casts are safe. We will promote the tv_sec into a 64 bit long if necessary
7069 * from a 32 bit long, and tv_usec is already a signed 32 bit int.
7071 timelimit
.tv_sec
= (__darwin_time_t
) tmp_searchblock
.timelimit
.tv_sec
;
7072 timelimit
.tv_usec
= (__darwin_useconds_t
) tmp_searchblock
.timelimit
.tv_usec
;
7073 searchblock
.searchparams1
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams1
);
7074 searchblock
.sizeofsearchparams1
= tmp_searchblock
.sizeofsearchparams1
;
7075 searchblock
.searchparams2
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams2
);
7076 searchblock
.sizeofsearchparams2
= tmp_searchblock
.sizeofsearchparams2
;
7077 searchblock
.searchattrs
= tmp_searchblock
.searchattrs
;
7082 /* Do a sanity check on sizeofsearchparams1 and sizeofsearchparams2.
7084 if (searchblock
.sizeofsearchparams1
> SEARCHFS_MAX_SEARCHPARMS
||
7085 searchblock
.sizeofsearchparams2
> SEARCHFS_MAX_SEARCHPARMS
)
7088 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
7089 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
7090 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
7093 mallocsize
= searchblock
.sizeofsearchparams1
+ searchblock
.sizeofsearchparams2
+
7094 sizeof(struct attrlist
) + sizeof(struct searchstate
);
7096 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
7098 /* Now set up the various pointers to the correct place in our newly allocated memory */
7100 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
7101 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
7102 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
7104 /* Now copy in the stuff given our local variables. */
7106 if ((error
= copyin(searchblock
.searchparams1
, searchparams1
, searchblock
.sizeofsearchparams1
)))
7109 if ((error
= copyin(searchblock
.searchparams2
, searchparams2
, searchblock
.sizeofsearchparams2
)))
7112 if ((error
= copyin(searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
))))
7115 if ((error
= copyin(uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
))))
7120 * Because searchparams1 and searchparams2 may contain an ATTR_CMN_NAME search parameter,
7121 * which is passed in with an attrreference_t, we need to inspect the buffer manually here.
7122 * The KPI does not provide us the ability to pass in the length of the buffers searchparams1
7123 * and searchparams2. To obviate the need for all searchfs-supporting filesystems to
7124 * validate the user-supplied data offset of the attrreference_t, we'll do it here.
7127 if (searchblock
.searchattrs
.commonattr
& ATTR_CMN_NAME
) {
7128 attrreference_t
* string_ref
;
7129 u_int32_t
* start_length
;
7130 user64_size_t param_length
;
7132 /* validate searchparams1 */
7133 param_length
= searchblock
.sizeofsearchparams1
;
7134 /* skip the word that specifies length of the buffer */
7135 start_length
= (u_int32_t
*) searchparams1
;
7136 start_length
= start_length
+1;
7137 string_ref
= (attrreference_t
*) start_length
;
7139 /* ensure no negative offsets or too big offsets */
7140 if (string_ref
->attr_dataoffset
< 0 ) {
7144 if (string_ref
->attr_length
> MAXPATHLEN
) {
7149 /* Check for pointer overflow in the string ref */
7150 if (((char*) string_ref
+ string_ref
->attr_dataoffset
) < (char*) string_ref
) {
7155 if (((char*) string_ref
+ string_ref
->attr_dataoffset
) > ((char*)searchparams1
+ param_length
)) {
7159 if (((char*)string_ref
+ string_ref
->attr_dataoffset
+ string_ref
->attr_length
) > ((char*)searchparams1
+ param_length
)) {
7165 /* set up the uio structure which will contain the users return buffer */
7166 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
7167 &uio_buf
[0], sizeof(uio_buf
));
7168 uio_addiov(auio
, searchblock
.returnbuffer
, searchblock
.returnbuffersize
);
7171 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
7172 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
7173 UIO_USERSPACE
, uap
->path
, ctx
);
7184 * If searchblock.maxmatches == 0, then skip the search. This has happened
7185 * before and sometimes the underlyning code doesnt deal with it well.
7187 if (searchblock
.maxmatches
== 0) {
7193 Allright, we have everything we need, so lets make that call.
7195 We keep special track of the return value from the file system:
7196 EAGAIN is an acceptable error condition that shouldn't keep us
7197 from copying out any results...
7200 fserror
= VNOP_SEARCHFS(vp
,
7203 &searchblock
.searchattrs
,
7204 (u_long
)searchblock
.maxmatches
,
7208 (u_long
)uap
->scriptcode
,
7209 (u_long
)uap
->options
,
7218 /* Now copy out the stuff that needs copying out. That means the number of matches, the
7219 search state. Everything was already put into he return buffer by the vop call. */
7221 if ((error
= copyout((caddr_t
) state
, uap
->state
, sizeof(struct searchstate
))) != 0)
7224 if ((error
= suulong(uap
->nummatches
, (uint64_t)nummatches
)) != 0)
7231 FREE(searchparams1
,M_TEMP
);
7236 } /* end of searchfs system call */
7240 * Make a filesystem-specific control call:
7244 fsctl_internal(proc_t p
, vnode_t
*arg_vp
, u_long cmd
, user_addr_t udata
, u_long options
, vfs_context_t ctx
)
7249 #define STK_PARAMS 128
7250 char stkbuf
[STK_PARAMS
];
7252 vnode_t vp
= *arg_vp
;
7254 size
= IOCPARM_LEN(cmd
);
7255 if (size
> IOCPARM_MAX
) return (EINVAL
);
7257 is64bit
= proc_is64bit(p
);
7260 if (size
> sizeof (stkbuf
)) {
7261 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
7269 error
= copyin(udata
, data
, size
);
7270 if (error
) goto FSCtl_Exit
;
7273 *(user_addr_t
*)data
= udata
;
7276 *(uint32_t *)data
= (uint32_t)udata
;
7279 } else if ((cmd
& IOC_OUT
) && size
) {
7281 * Zero the buffer so the user always
7282 * gets back something deterministic.
7285 } else if (cmd
& IOC_VOID
) {
7287 *(user_addr_t
*)data
= udata
;
7290 *(uint32_t *)data
= (uint32_t)udata
;
7294 /* Check to see if it's a generic command */
7295 if (IOCBASECMD(cmd
) == FSCTL_SYNC_VOLUME
) {
7296 mount_t mp
= vp
->v_mount
;
7297 int arg
= *(uint32_t*)data
;
7299 /* record vid of vp so we can drop it below. */
7300 uint32_t vvid
= vp
->v_id
;
7303 * Then grab mount_iterref so that we can release the vnode.
7304 * Without this, a thread may call vnode_iterate_prepare then
7305 * get into a deadlock because we've never released the root vp
7307 error
= mount_iterref (mp
, 0);
7313 /* issue the sync for this volume */
7314 (void)sync_callback(mp
, (arg
& FSCTL_SYNC_WAIT
) ? &arg
: NULL
);
7317 * Then release the mount_iterref once we're done syncing; it's not
7318 * needed for the VNOP_IOCTL below
7322 if (arg
& FSCTL_SYNC_FULLSYNC
) {
7323 /* re-obtain vnode iocount on the root vp, if possible */
7324 error
= vnode_getwithvid (vp
, vvid
);
7326 error
= VNOP_IOCTL(vp
, F_FULLFSYNC
, (caddr_t
)NULL
, 0, ctx
);
7330 /* mark the argument VP as having been released */
7333 } else if (IOCBASECMD(cmd
) == FSCTL_SET_PACKAGE_EXTS
) {
7334 user_addr_t ext_strings
;
7335 uint32_t num_entries
;
7338 if ( (is64bit
&& size
!= sizeof(user64_package_ext_info
))
7339 || (is64bit
== 0 && size
!= sizeof(user32_package_ext_info
))) {
7341 // either you're 64-bit and passed a 64-bit struct or
7342 // you're 32-bit and passed a 32-bit struct. otherwise
7349 ext_strings
= ((user64_package_ext_info
*)data
)->strings
;
7350 num_entries
= ((user64_package_ext_info
*)data
)->num_entries
;
7351 max_width
= ((user64_package_ext_info
*)data
)->max_width
;
7353 ext_strings
= CAST_USER_ADDR_T(((user32_package_ext_info
*)data
)->strings
);
7354 num_entries
= ((user32_package_ext_info
*)data
)->num_entries
;
7355 max_width
= ((user32_package_ext_info
*)data
)->max_width
;
7358 error
= set_package_extensions_table(ext_strings
, num_entries
, max_width
);
7360 } else if (IOCBASECMD(cmd
) == FSCTL_WAIT_FOR_SYNC
) {
7361 error
= tsleep((caddr_t
)&sync_wait_time
, PVFS
|PCATCH
, "sync-wait", 0);
7363 *(uint32_t *)data
= (uint32_t)sync_wait_time
;
7370 /* Invoke the filesystem-specific code */
7371 error
= VNOP_IOCTL(vp
, IOCBASECMD(cmd
), data
, options
, ctx
);
7376 * Copy any data to user, size was
7377 * already set and checked above.
7379 if (error
== 0 && (cmd
& IOC_OUT
) && size
)
7380 error
= copyout(data
, udata
, size
);
7383 if (memp
) kfree(memp
, size
);
7390 fsctl (proc_t p
, struct fsctl_args
*uap
, __unused
int32_t *retval
)
7393 struct nameidata nd
;
7396 vfs_context_t ctx
= vfs_context_current();
7398 AUDIT_ARG(cmd
, uap
->cmd
);
7399 AUDIT_ARG(value32
, uap
->options
);
7400 /* Get the vnode for the file we are getting info on: */
7402 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
7403 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
, UIO_USERSPACE
,
7405 if ((error
= namei(&nd
))) goto done
;
7410 error
= mac_mount_check_fsctl(ctx
, vnode_mount(vp
), uap
->cmd
);
7416 error
= fsctl_internal(p
, &vp
, uap
->cmd
, (user_addr_t
)uap
->data
, uap
->options
, ctx
);
7425 ffsctl (proc_t p
, struct ffsctl_args
*uap
, __unused
int32_t *retval
)
7429 vfs_context_t ctx
= vfs_context_current();
7432 AUDIT_ARG(fd
, uap
->fd
);
7433 AUDIT_ARG(cmd
, uap
->cmd
);
7434 AUDIT_ARG(value32
, uap
->options
);
7436 /* Get the vnode for the file we are getting info on: */
7437 if ((error
= file_vnode(uap
->fd
, &vp
)))
7440 if ((error
= vnode_getwithref(vp
))) {
7445 error
= mac_mount_check_fsctl(ctx
, vnode_mount(vp
), uap
->cmd
);
7451 error
= fsctl_internal(p
, &vp
, uap
->cmd
, (user_addr_t
)uap
->data
, uap
->options
, ctx
);
7461 /* end of fsctl system call */
7464 * An in-kernel sync for power management to call.
7466 __private_extern__
int
7471 struct sync_args data
;
7476 error
= sync(current_proc(), &data
, &retval
[0]);
7480 } /* end of sync_internal call */
7484 * Retrieve the data of an extended attribute.
7487 getxattr(proc_t p
, struct getxattr_args
*uap
, user_ssize_t
*retval
)
7490 struct nameidata nd
;
7491 char attrname
[XATTR_MAXNAMELEN
+1];
7492 vfs_context_t ctx
= vfs_context_current();
7494 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
7495 size_t attrsize
= 0;
7497 u_int32_t nameiflags
;
7499 char uio_buf
[ UIO_SIZEOF(1) ];
7501 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
7504 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
7505 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, ctx
);
7506 if ((error
= namei(&nd
))) {
7512 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
7515 if (xattr_protected(attrname
)) {
7520 * the specific check for 0xffffffff is a hack to preserve
7521 * binaray compatibilty in K64 with applications that discovered
7522 * that passing in a buf pointer and a size of -1 resulted in
7523 * just the size of the indicated extended attribute being returned.
7524 * this isn't part of the documented behavior, but because of the
7525 * original implemtation's check for "uap->size > 0", this behavior
7526 * was allowed. In K32 that check turned into a signed comparison
7527 * even though uap->size is unsigned... in K64, we blow by that
7528 * check because uap->size is unsigned and doesn't get sign smeared
7529 * in the munger for a 32 bit user app. we also need to add a
7530 * check to limit the maximum size of the buffer being passed in...
7531 * unfortunately, the underlying fileystems seem to just malloc
7532 * the requested size even if the actual extended attribute is tiny.
7533 * because that malloc is for kernel wired memory, we have to put a
7536 * U32 running on K64 will yield 0x00000000ffffffff for uap->size
7537 * U64 running on K64 will yield -1 (64 bits wide)
7538 * U32/U64 running on K32 will yield -1 (32 bits wide)
7540 if (uap
->size
== 0xffffffff || uap
->size
== (size_t)-1)
7543 if (uap
->size
> (size_t)XATTR_MAXSIZE
)
7544 uap
->size
= XATTR_MAXSIZE
;
7547 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
7548 &uio_buf
[0], sizeof(uio_buf
));
7549 uio_addiov(auio
, uap
->value
, uap
->size
);
7552 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, ctx
);
7557 *retval
= uap
->size
- uio_resid(auio
);
7559 *retval
= (user_ssize_t
)attrsize
;
7566 * Retrieve the data of an extended attribute.
7569 fgetxattr(proc_t p
, struct fgetxattr_args
*uap
, user_ssize_t
*retval
)
7572 char attrname
[XATTR_MAXNAMELEN
+1];
7574 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
7575 size_t attrsize
= 0;
7578 char uio_buf
[ UIO_SIZEOF(1) ];
7580 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
7583 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
7586 if ( (error
= vnode_getwithref(vp
)) ) {
7590 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
7593 if (xattr_protected(attrname
)) {
7597 if (uap
->value
&& uap
->size
> 0) {
7598 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
7599 &uio_buf
[0], sizeof(uio_buf
));
7600 uio_addiov(auio
, uap
->value
, uap
->size
);
7603 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, vfs_context_current());
7605 (void)vnode_put(vp
);
7609 *retval
= uap
->size
- uio_resid(auio
);
7611 *retval
= (user_ssize_t
)attrsize
;
7617 * Set the data of an extended attribute.
7620 setxattr(proc_t p
, struct setxattr_args
*uap
, int *retval
)
7623 struct nameidata nd
;
7624 char attrname
[XATTR_MAXNAMELEN
+1];
7625 vfs_context_t ctx
= vfs_context_current();
7627 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
7629 u_int32_t nameiflags
;
7631 char uio_buf
[ UIO_SIZEOF(1) ];
7633 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
7636 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
7639 if (xattr_protected(attrname
))
7641 if (uap
->size
!= 0 && uap
->value
== 0) {
7645 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
7646 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, ctx
);
7647 if ((error
= namei(&nd
))) {
7653 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
7654 &uio_buf
[0], sizeof(uio_buf
));
7655 uio_addiov(auio
, uap
->value
, uap
->size
);
7657 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, ctx
);
7660 add_fsevent(FSE_XATTR_MODIFIED
, ctx
,
7671 * Set the data of an extended attribute.
7674 fsetxattr(proc_t p
, struct fsetxattr_args
*uap
, int *retval
)
7677 char attrname
[XATTR_MAXNAMELEN
+1];
7679 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
7682 char uio_buf
[ UIO_SIZEOF(1) ];
7683 vfs_context_t ctx
= vfs_context_current();
7685 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
7688 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
7691 if (xattr_protected(attrname
))
7693 if (uap
->size
!= 0 && uap
->value
== 0) {
7696 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
7699 if ( (error
= vnode_getwithref(vp
)) ) {
7703 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
7704 &uio_buf
[0], sizeof(uio_buf
));
7705 uio_addiov(auio
, uap
->value
, uap
->size
);
7707 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, vfs_context_current());
7710 add_fsevent(FSE_XATTR_MODIFIED
, ctx
,
7722 * Remove an extended attribute.
7723 * XXX Code duplication here.
7726 removexattr(proc_t p
, struct removexattr_args
*uap
, int *retval
)
7729 struct nameidata nd
;
7730 char attrname
[XATTR_MAXNAMELEN
+1];
7731 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
7732 vfs_context_t ctx
= vfs_context_current();
7734 u_int32_t nameiflags
;
7737 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
7740 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
7744 if (xattr_protected(attrname
))
7746 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
7747 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, ctx
);
7748 if ((error
= namei(&nd
))) {
7754 error
= vn_removexattr(vp
, attrname
, uap
->options
, ctx
);
7757 add_fsevent(FSE_XATTR_REMOVED
, ctx
,
7768 * Remove an extended attribute.
7769 * XXX Code duplication here.
7772 fremovexattr(__unused proc_t p
, struct fremovexattr_args
*uap
, int *retval
)
7775 char attrname
[XATTR_MAXNAMELEN
+1];
7778 vfs_context_t ctx
= vfs_context_current();
7780 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
7783 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
7787 if (xattr_protected(attrname
))
7789 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
7792 if ( (error
= vnode_getwithref(vp
)) ) {
7797 error
= vn_removexattr(vp
, attrname
, uap
->options
, vfs_context_current());
7800 add_fsevent(FSE_XATTR_REMOVED
, ctx
,
7812 * Retrieve the list of extended attribute names.
7813 * XXX Code duplication here.
7816 listxattr(proc_t p
, struct listxattr_args
*uap
, user_ssize_t
*retval
)
7819 struct nameidata nd
;
7820 vfs_context_t ctx
= vfs_context_current();
7822 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
7823 size_t attrsize
= 0;
7824 u_int32_t nameiflags
;
7826 char uio_buf
[ UIO_SIZEOF(1) ];
7828 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
7831 nameiflags
= ((uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
) | NOTRIGGER
;
7832 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, ctx
);
7833 if ((error
= namei(&nd
))) {
7838 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
7839 auio
= uio_createwithbuffer(1, 0, spacetype
,
7840 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
7841 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
7844 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, ctx
);
7848 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
7850 *retval
= (user_ssize_t
)attrsize
;
7856 * Retrieve the list of extended attribute names.
7857 * XXX Code duplication here.
7860 flistxattr(proc_t p
, struct flistxattr_args
*uap
, user_ssize_t
*retval
)
7864 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
7865 size_t attrsize
= 0;
7867 char uio_buf
[ UIO_SIZEOF(1) ];
7869 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
7872 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
7875 if ( (error
= vnode_getwithref(vp
)) ) {
7879 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
7880 auio
= uio_createwithbuffer(1, 0, spacetype
,
7881 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
7882 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
7885 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, vfs_context_current());
7890 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
7892 *retval
= (user_ssize_t
)attrsize
;
7898 * Obtain the full pathname of a file system object by id.
7900 * This is a private SPI used by the File Manager.
7904 fsgetpath(__unused proc_t p
, struct fsgetpath_args
*uap
, user_ssize_t
*retval
)
7907 struct mount
*mp
= NULL
;
7908 vfs_context_t ctx
= vfs_context_current();
7915 if ((error
= copyin(uap
->fsid
, (caddr_t
)&fsid
, sizeof(fsid
)))) {
7918 AUDIT_ARG(value32
, fsid
.val
[0]);
7919 AUDIT_ARG(value64
, uap
->objid
);
7920 /* Restrict output buffer size for now. */
7921 if (uap
->bufsize
> PAGE_SIZE
) {
7924 MALLOC(realpath
, char *, uap
->bufsize
, M_TEMP
, M_WAITOK
);
7925 if (realpath
== NULL
) {
7928 /* Find the target mountpoint. */
7929 if ((mp
= mount_lookupby_volfsid(fsid
.val
[0], 1)) == NULL
) {
7930 error
= ENOTSUP
; /* unexpected failure */
7933 /* Find the target vnode. */
7934 if (uap
->objid
== 2) {
7935 error
= VFS_ROOT(mp
, &vp
, ctx
);
7937 error
= VFS_VGET(mp
, (ino64_t
)uap
->objid
, &vp
, ctx
);
7943 /* Obtain the absolute path to this vnode. */
7944 bpflags
= vfs_context_suser(ctx
) ? BUILDPATH_CHECKACCESS
: 0;
7945 error
= build_path(vp
, realpath
, uap
->bufsize
, &length
, bpflags
, ctx
);
7950 AUDIT_ARG(text
, realpath
);
7951 error
= copyout((caddr_t
)realpath
, uap
->buf
, length
);
7953 *retval
= (user_ssize_t
)length
; /* may be superseded by error */
7956 FREE(realpath
, M_TEMP
);
7962 * Common routine to handle various flavors of statfs data heading out
7965 * Returns: 0 Success
7969 munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
7970 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
7971 boolean_t partial_copy
)
7974 int my_size
, copy_size
;
7977 struct user64_statfs sfs
;
7978 my_size
= copy_size
= sizeof(sfs
);
7979 bzero(&sfs
, my_size
);
7980 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
7981 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
7982 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
7983 sfs
.f_bsize
= (user64_long_t
)sfsp
->f_bsize
;
7984 sfs
.f_iosize
= (user64_long_t
)sfsp
->f_iosize
;
7985 sfs
.f_blocks
= (user64_long_t
)sfsp
->f_blocks
;
7986 sfs
.f_bfree
= (user64_long_t
)sfsp
->f_bfree
;
7987 sfs
.f_bavail
= (user64_long_t
)sfsp
->f_bavail
;
7988 sfs
.f_files
= (user64_long_t
)sfsp
->f_files
;
7989 sfs
.f_ffree
= (user64_long_t
)sfsp
->f_ffree
;
7990 sfs
.f_fsid
= sfsp
->f_fsid
;
7991 sfs
.f_owner
= sfsp
->f_owner
;
7992 strlcpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
);
7993 strlcpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
);
7994 strlcpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
);
7997 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
7999 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
8002 struct user32_statfs sfs
;
8004 my_size
= copy_size
= sizeof(sfs
);
8005 bzero(&sfs
, my_size
);
8007 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
8008 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
8009 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
8012 * It's possible for there to be more than 2^^31 blocks in the filesystem, so we
8013 * have to fudge the numbers here in that case. We inflate the blocksize in order
8014 * to reflect the filesystem size as best we can.
8016 if ((sfsp
->f_blocks
> INT_MAX
)
8017 /* Hack for 4061702 . I think the real fix is for Carbon to
8018 * look for some volume capability and not depend on hidden
8019 * semantics agreed between a FS and carbon.
8020 * f_blocks, f_bfree, and f_bavail set to -1 is the trigger
8021 * for Carbon to set bNoVolumeSizes volume attribute.
8022 * Without this the webdavfs files cannot be copied onto
8023 * disk as they look huge. This change should not affect
8024 * XSAN as they should not setting these to -1..
8026 && (sfsp
->f_blocks
!= 0xffffffffffffffffULL
)
8027 && (sfsp
->f_bfree
!= 0xffffffffffffffffULL
)
8028 && (sfsp
->f_bavail
!= 0xffffffffffffffffULL
)) {
8032 * Work out how far we have to shift the block count down to make it fit.
8033 * Note that it's possible to have to shift so far that the resulting
8034 * blocksize would be unreportably large. At that point, we will clip
8035 * any values that don't fit.
8037 * For safety's sake, we also ensure that f_iosize is never reported as
8038 * being smaller than f_bsize.
8040 for (shift
= 0; shift
< 32; shift
++) {
8041 if ((sfsp
->f_blocks
>> shift
) <= INT_MAX
)
8043 if ((sfsp
->f_bsize
<< (shift
+ 1)) > INT_MAX
)
8046 #define __SHIFT_OR_CLIP(x, s) ((((x) >> (s)) > INT_MAX) ? INT_MAX : ((x) >> (s)))
8047 sfs
.f_blocks
= (user32_long_t
)__SHIFT_OR_CLIP(sfsp
->f_blocks
, shift
);
8048 sfs
.f_bfree
= (user32_long_t
)__SHIFT_OR_CLIP(sfsp
->f_bfree
, shift
);
8049 sfs
.f_bavail
= (user32_long_t
)__SHIFT_OR_CLIP(sfsp
->f_bavail
, shift
);
8050 #undef __SHIFT_OR_CLIP
8051 sfs
.f_bsize
= (user32_long_t
)(sfsp
->f_bsize
<< shift
);
8052 sfs
.f_iosize
= lmax(sfsp
->f_iosize
, sfsp
->f_bsize
);
8054 /* filesystem is small enough to be reported honestly */
8055 sfs
.f_bsize
= (user32_long_t
)sfsp
->f_bsize
;
8056 sfs
.f_iosize
= (user32_long_t
)sfsp
->f_iosize
;
8057 sfs
.f_blocks
= (user32_long_t
)sfsp
->f_blocks
;
8058 sfs
.f_bfree
= (user32_long_t
)sfsp
->f_bfree
;
8059 sfs
.f_bavail
= (user32_long_t
)sfsp
->f_bavail
;
8061 sfs
.f_files
= (user32_long_t
)sfsp
->f_files
;
8062 sfs
.f_ffree
= (user32_long_t
)sfsp
->f_ffree
;
8063 sfs
.f_fsid
= sfsp
->f_fsid
;
8064 sfs
.f_owner
= sfsp
->f_owner
;
8065 strlcpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
);
8066 strlcpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
);
8067 strlcpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
);
8070 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
8072 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
8075 if (sizep
!= NULL
) {
8082 * copy stat structure into user_stat structure.
8084 void munge_user64_stat(struct stat
*sbp
, struct user64_stat
*usbp
)
8086 bzero(usbp
, sizeof(*usbp
));
8088 usbp
->st_dev
= sbp
->st_dev
;
8089 usbp
->st_ino
= sbp
->st_ino
;
8090 usbp
->st_mode
= sbp
->st_mode
;
8091 usbp
->st_nlink
= sbp
->st_nlink
;
8092 usbp
->st_uid
= sbp
->st_uid
;
8093 usbp
->st_gid
= sbp
->st_gid
;
8094 usbp
->st_rdev
= sbp
->st_rdev
;
8095 #ifndef _POSIX_C_SOURCE
8096 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
8097 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
8098 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
8099 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
8100 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
8101 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
8103 usbp
->st_atime
= sbp
->st_atime
;
8104 usbp
->st_atimensec
= sbp
->st_atimensec
;
8105 usbp
->st_mtime
= sbp
->st_mtime
;
8106 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
8107 usbp
->st_ctime
= sbp
->st_ctime
;
8108 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
8110 usbp
->st_size
= sbp
->st_size
;
8111 usbp
->st_blocks
= sbp
->st_blocks
;
8112 usbp
->st_blksize
= sbp
->st_blksize
;
8113 usbp
->st_flags
= sbp
->st_flags
;
8114 usbp
->st_gen
= sbp
->st_gen
;
8115 usbp
->st_lspare
= sbp
->st_lspare
;
8116 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
8117 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];
8120 void munge_user32_stat(struct stat
*sbp
, struct user32_stat
*usbp
)
8122 bzero(usbp
, sizeof(*usbp
));
8124 usbp
->st_dev
= sbp
->st_dev
;
8125 usbp
->st_ino
= sbp
->st_ino
;
8126 usbp
->st_mode
= sbp
->st_mode
;
8127 usbp
->st_nlink
= sbp
->st_nlink
;
8128 usbp
->st_uid
= sbp
->st_uid
;
8129 usbp
->st_gid
= sbp
->st_gid
;
8130 usbp
->st_rdev
= sbp
->st_rdev
;
8131 #ifndef _POSIX_C_SOURCE
8132 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
8133 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
8134 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
8135 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
8136 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
8137 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
8139 usbp
->st_atime
= sbp
->st_atime
;
8140 usbp
->st_atimensec
= sbp
->st_atimensec
;
8141 usbp
->st_mtime
= sbp
->st_mtime
;
8142 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
8143 usbp
->st_ctime
= sbp
->st_ctime
;
8144 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
8146 usbp
->st_size
= sbp
->st_size
;
8147 usbp
->st_blocks
= sbp
->st_blocks
;
8148 usbp
->st_blksize
= sbp
->st_blksize
;
8149 usbp
->st_flags
= sbp
->st_flags
;
8150 usbp
->st_gen
= sbp
->st_gen
;
8151 usbp
->st_lspare
= sbp
->st_lspare
;
8152 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
8153 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];
8157 * copy stat64 structure into user_stat64 structure.
8159 void munge_user64_stat64(struct stat64
*sbp
, struct user64_stat64
*usbp
)
8161 bzero(usbp
, sizeof(*usbp
));
8163 usbp
->st_dev
= sbp
->st_dev
;
8164 usbp
->st_ino
= sbp
->st_ino
;
8165 usbp
->st_mode
= sbp
->st_mode
;
8166 usbp
->st_nlink
= sbp
->st_nlink
;
8167 usbp
->st_uid
= sbp
->st_uid
;
8168 usbp
->st_gid
= sbp
->st_gid
;
8169 usbp
->st_rdev
= sbp
->st_rdev
;
8170 #ifndef _POSIX_C_SOURCE
8171 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
8172 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
8173 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
8174 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
8175 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
8176 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
8177 usbp
->st_birthtimespec
.tv_sec
= sbp
->st_birthtimespec
.tv_sec
;
8178 usbp
->st_birthtimespec
.tv_nsec
= sbp
->st_birthtimespec
.tv_nsec
;
8180 usbp
->st_atime
= sbp
->st_atime
;
8181 usbp
->st_atimensec
= sbp
->st_atimensec
;
8182 usbp
->st_mtime
= sbp
->st_mtime
;
8183 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
8184 usbp
->st_ctime
= sbp
->st_ctime
;
8185 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
8186 usbp
->st_birthtime
= sbp
->st_birthtime
;
8187 usbp
->st_birthtimensec
= sbp
->st_birthtimensec
;
8189 usbp
->st_size
= sbp
->st_size
;
8190 usbp
->st_blocks
= sbp
->st_blocks
;
8191 usbp
->st_blksize
= sbp
->st_blksize
;
8192 usbp
->st_flags
= sbp
->st_flags
;
8193 usbp
->st_gen
= sbp
->st_gen
;
8194 usbp
->st_lspare
= sbp
->st_lspare
;
8195 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
8196 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];
8199 void munge_user32_stat64(struct stat64
*sbp
, struct user32_stat64
*usbp
)
8201 bzero(usbp
, sizeof(*usbp
));
8203 usbp
->st_dev
= sbp
->st_dev
;
8204 usbp
->st_ino
= sbp
->st_ino
;
8205 usbp
->st_mode
= sbp
->st_mode
;
8206 usbp
->st_nlink
= sbp
->st_nlink
;
8207 usbp
->st_uid
= sbp
->st_uid
;
8208 usbp
->st_gid
= sbp
->st_gid
;
8209 usbp
->st_rdev
= sbp
->st_rdev
;
8210 #ifndef _POSIX_C_SOURCE
8211 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
8212 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
8213 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
8214 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
8215 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
8216 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
8217 usbp
->st_birthtimespec
.tv_sec
= sbp
->st_birthtimespec
.tv_sec
;
8218 usbp
->st_birthtimespec
.tv_nsec
= sbp
->st_birthtimespec
.tv_nsec
;
8220 usbp
->st_atime
= sbp
->st_atime
;
8221 usbp
->st_atimensec
= sbp
->st_atimensec
;
8222 usbp
->st_mtime
= sbp
->st_mtime
;
8223 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
8224 usbp
->st_ctime
= sbp
->st_ctime
;
8225 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
8226 usbp
->st_birthtime
= sbp
->st_birthtime
;
8227 usbp
->st_birthtimensec
= sbp
->st_birthtimensec
;
8229 usbp
->st_size
= sbp
->st_size
;
8230 usbp
->st_blocks
= sbp
->st_blocks
;
8231 usbp
->st_blksize
= sbp
->st_blksize
;
8232 usbp
->st_flags
= sbp
->st_flags
;
8233 usbp
->st_gen
= sbp
->st_gen
;
8234 usbp
->st_lspare
= sbp
->st_lspare
;
8235 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
8236 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];