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
);
156 int (*union_dircheckp
)(struct vnode
**, struct fileproc
*, vfs_context_t
);
159 int sync_internal(void);
162 int open1(vfs_context_t
, struct nameidata
*, int, struct vnode_attr
*, int32_t *);
165 int unlink1(vfs_context_t
, struct nameidata
*, int);
168 #ifdef __APPLE_API_OBSOLETE
170 int fd
; /* file descriptor of the target file */
171 struct vstat
*vsb
; /* vstat structure for returned info */
174 const char *path
; /* pathname of the target file */
175 struct vstat
*vsb
; /* vstat structure for returned info */
177 struct mkcomplex_args
{
178 const char *path
; /* pathname of the file to be created */
179 mode_t mode
; /* access mode for the newly created file */
180 u_int32_t type
; /* format of the complex file */
183 const char *path
; /* pathname of the target file */
184 struct vstat
*vsb
; /* vstat structure for returned info */
187 int fstatv(proc_t p
, struct fstatv_args
*uap
, int32_t *retval
);
188 int lstatv(proc_t p
, struct lstatv_args
*uap
, int32_t *retval
);
189 int mkcomplex(proc_t p
, struct mkcomplex_args
*uap
, int32_t *retval
);
190 int statv(proc_t p
, struct statv_args
*uap
, int32_t *retval
);
192 #endif /* __APPLE_API_OBSOLETE */
195 * incremented each time a mount or unmount operation occurs
196 * used to invalidate the cached value of the rootvp in the
197 * mount structure utilized by cache_lookup_path
199 uint32_t mount_generation
= 0;
201 /* counts number of mount and unmount operations */
202 unsigned int vfs_nummntops
=0;
204 extern struct fileops vnops
;
205 extern errno_t
rmdir_remove_orphaned_appleDouble(vnode_t
, vfs_context_t
, int *);
209 * Virtual File System System Calls
213 * Mount a file system.
217 mount(proc_t p
, struct mount_args
*uap
, __unused
int32_t *retval
)
219 struct __mac_mount_args muap
;
221 muap
.type
= uap
->type
;
222 muap
.path
= uap
->path
;
223 muap
.flags
= uap
->flags
;
224 muap
.data
= uap
->data
;
225 muap
.mac_p
= USER_ADDR_NULL
;
226 return (__mac_mount(p
, &muap
, retval
));
231 * Mount a file system taking into account MAC label behavior.
232 * See mount(2) man page for more information
234 * Parameters: p Process requesting the mount
235 * uap User argument descriptor (see below)
238 * Indirect: uap->type Filesystem type
239 * uap->path Path to mount
240 * uap->data Mount arguments
241 * uap->mac_p MAC info
242 * uap->flags Mount flags
249 __mac_mount(struct proc
*p
, register struct __mac_mount_args
*uap
, __unused
int32_t *retval
)
251 struct vnode
*vp
, *pvp
;
252 struct vnode
*devvp
= NULLVP
;
253 struct vnode
*device_vnode
= NULLVP
;
258 struct vfstable
*vfsp
= (struct vfstable
*)0;
260 struct vnode_attr va
;
261 vfs_context_t ctx
= vfs_context_current();
263 struct nameidata nd1
;
264 char fstypename
[MFSNAMELEN
];
266 user_addr_t devpath
= USER_ADDR_NULL
;
267 user_addr_t fsmountargs
= uap
->data
;
270 boolean_t vfsp_ref
= FALSE
;
273 boolean_t is_rwlock_locked
= FALSE
;
274 boolean_t did_rele
= FALSE
;
275 boolean_t have_usecount
= FALSE
;
277 AUDIT_ARG(fflags
, uap
->flags
);
279 is_64bit
= proc_is64bit(p
);
282 * Get vnode to be covered
284 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
| WANTPARENT
,
285 UIO_USERSPACE
, uap
->path
, ctx
);
292 if ((vp
->v_flag
& VROOT
) &&
293 (vp
->v_mount
->mnt_flag
& MNT_ROOTFS
))
294 uap
->flags
|= MNT_UPDATE
;
296 error
= copyinstr(uap
->type
, fstypename
, MFSNAMELEN
, &dummy
);
300 if (uap
->flags
& MNT_UPDATE
) {
301 if ((vp
->v_flag
& VROOT
) == 0) {
307 /* unmount in progress return error */
309 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
315 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
316 is_rwlock_locked
= TRUE
;
318 * We only allow the filesystem to be reloaded if it
319 * is currently mounted read-only.
321 if ((uap
->flags
& MNT_RELOAD
) &&
322 ((mp
->mnt_flag
& MNT_RDONLY
) == 0)) {
327 * Only root, or the user that did the original mount is
328 * permitted to update it.
330 if (mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(vfs_context_ucred(ctx
)) &&
331 (error
= suser(vfs_context_ucred(ctx
), &p
->p_acflag
))) {
335 error
= mac_mount_check_remount(ctx
, mp
);
337 lck_rw_done(&mp
->mnt_rwlock
);
342 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV,
343 * and MNT_NOEXEC if mount point is already MNT_NOEXEC.
345 if (suser(vfs_context_ucred(ctx
), NULL
)) {
346 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
347 if (mp
->mnt_flag
& MNT_NOEXEC
)
348 uap
->flags
|= MNT_NOEXEC
;
353 uap
->flags
& (MNT_RELOAD
| MNT_FORCE
| MNT_UPDATE
);
355 vfsp
= mp
->mnt_vtable
;
359 * If the user is not root, ensure that they own the directory
360 * onto which we are attempting to mount.
363 VATTR_WANTED(&va
, va_uid
);
364 if ((error
= vnode_getattr(vp
, &va
, ctx
)) ||
365 (va
.va_uid
!= kauth_cred_getuid(vfs_context_ucred(ctx
)) &&
366 (error
= suser(vfs_context_ucred(ctx
), &p
->p_acflag
)))) {
370 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV, and
371 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
373 if (suser(vfs_context_ucred(ctx
), NULL
)) {
374 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
375 if (vp
->v_mount
->mnt_flag
& MNT_NOEXEC
)
376 uap
->flags
|= MNT_NOEXEC
;
378 if ( (error
= VNOP_FSYNC(vp
, MNT_WAIT
, ctx
)) )
381 if ( (error
= buf_invalidateblks(vp
, BUF_WRITE_DATA
, 0, 0)) )
384 if (vp
->v_type
!= VDIR
) {
389 /* XXXAUDIT: Should we capture the type on the error path as well? */
390 AUDIT_ARG(text
, fstypename
);
392 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
393 if (!strncmp(vfsp
->vfc_name
, fstypename
, MFSNAMELEN
)) {
394 vfsp
->vfc_refcount
++;
404 error
= mac_mount_check_mount(ctx
, vp
,
405 &nd
.ni_cnd
, vfsp
->vfc_name
);
409 if (ISSET(vp
->v_flag
, VMOUNT
) && (vp
->v_mountedhere
!= NULL
)) {
414 SET(vp
->v_flag
, VMOUNT
);
418 * Allocate and initialize the filesystem.
420 MALLOC_ZONE(mp
, struct mount
*, (u_int32_t
)sizeof(struct mount
),
422 bzero((char *)mp
, (u_int32_t
)sizeof(struct mount
));
425 /* Initialize the default IO constraints */
426 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
427 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
428 mp
->mnt_maxsegreadsize
= mp
->mnt_maxreadcnt
;
429 mp
->mnt_maxsegwritesize
= mp
->mnt_maxwritecnt
;
430 mp
->mnt_devblocksize
= DEV_BSIZE
;
431 mp
->mnt_alignmentmask
= PAGE_MASK
;
432 mp
->mnt_ioqueue_depth
= MNT_DEFAULT_IOQUEUE_DEPTH
;
435 mp
->mnt_realrootvp
= NULLVP
;
436 mp
->mnt_authcache_ttl
= CACHED_LOOKUP_RIGHT_TTL
;
438 TAILQ_INIT(&mp
->mnt_vnodelist
);
439 TAILQ_INIT(&mp
->mnt_workerqueue
);
440 TAILQ_INIT(&mp
->mnt_newvnodes
);
442 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
443 is_rwlock_locked
= TRUE
;
444 mp
->mnt_op
= vfsp
->vfc_vfsops
;
445 mp
->mnt_vtable
= vfsp
;
446 //mp->mnt_stat.f_type = vfsp->vfc_typenum;
447 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
448 strncpy(mp
->mnt_vfsstat
.f_fstypename
, vfsp
->vfc_name
, MFSTYPENAMELEN
);
449 strncpy(mp
->mnt_vfsstat
.f_mntonname
, nd
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
450 mp
->mnt_vnodecovered
= vp
;
451 mp
->mnt_vfsstat
.f_owner
= kauth_cred_getuid(vfs_context_ucred(ctx
));
452 mp
->mnt_devbsdunit
= LOWPRI_MAX_NUM_DEV
- 1;
454 /* XXX 3762912 hack to support HFS filesystem 'owner' - filesystem may update later */
455 vfs_setowner(mp
, KAUTH_UID_NONE
, KAUTH_GID_NONE
);
459 * Set the mount level flags.
461 if (uap
->flags
& MNT_RDONLY
)
462 mp
->mnt_flag
|= MNT_RDONLY
;
463 else if (mp
->mnt_flag
& MNT_RDONLY
)
464 mp
->mnt_kern_flag
|= MNTK_WANTRDWR
;
465 mp
->mnt_flag
&= ~(MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
466 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
467 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
|
468 MNT_DEFWRITE
| MNT_NOATIME
| MNT_QUARANTINE
);
469 mp
->mnt_flag
|= uap
->flags
& (MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
470 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
471 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
|
472 MNT_DEFWRITE
| MNT_NOATIME
| MNT_QUARANTINE
);
475 if (uap
->flags
& MNT_MULTILABEL
) {
476 if (vfsp
->vfc_vfsflags
& VFC_VFSNOMACLABEL
) {
480 mp
->mnt_flag
|= MNT_MULTILABEL
;
484 if (vfsp
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
486 if ( (error
= copyin(fsmountargs
, (caddr_t
)&devpath
, sizeof(devpath
))) )
488 fsmountargs
+= sizeof(devpath
);
491 if ( (error
= copyin(fsmountargs
, (caddr_t
)&tmp
, sizeof(tmp
))) )
493 /* munge into LP64 addr */
494 devpath
= CAST_USER_ADDR_T(tmp
);
495 fsmountargs
+= sizeof(tmp
);
498 /* if it is not update and device name needs to be parsed */
500 NDINIT(&nd1
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, devpath
, ctx
);
501 if ( (error
= namei(&nd1
)) )
504 strncpy(mp
->mnt_vfsstat
.f_mntfromname
, nd1
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
509 if (devvp
->v_type
!= VBLK
) {
513 if (major(devvp
->v_rdev
) >= nblkdev
) {
518 * If mount by non-root, then verify that user has necessary
519 * permissions on the device.
521 if (suser(vfs_context_ucred(ctx
), NULL
) != 0) {
522 accessmode
= KAUTH_VNODE_READ_DATA
;
523 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
524 accessmode
|= KAUTH_VNODE_WRITE_DATA
;
525 if ((error
= vnode_authorize(devvp
, NULL
, accessmode
, ctx
)) != 0)
529 if (devpath
&& ((uap
->flags
& MNT_UPDATE
) == 0)) {
530 if ( (error
= vnode_ref(devvp
)) )
533 * Disallow multiple mounts of the same device.
534 * Disallow mounting of a device that is currently in use
535 * (except for root, which might share swap device for miniroot).
536 * Flush out any old buffers remaining from a previous use.
538 if ( (error
= vfs_mountedon(devvp
)) )
541 if (vcount(devvp
) > 1 && !(vfs_flags(mp
) & MNT_ROOTFS
)) {
545 if ( (error
= VNOP_FSYNC(devvp
, MNT_WAIT
, ctx
)) ) {
549 if ( (error
= buf_invalidateblks(devvp
, BUF_WRITE_DATA
, 0, 0)) )
552 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
554 error
= mac_vnode_check_open(ctx
,
556 ronly
? FREAD
: FREAD
|FWRITE
);
560 if ( (error
= VNOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, ctx
)) )
563 mp
->mnt_devvp
= devvp
;
564 device_vnode
= devvp
;
566 if ((mp
->mnt_flag
& MNT_RDONLY
) && (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)) {
570 * If upgrade to read-write by non-root, then verify
571 * that user has necessary permissions on the device.
573 device_vnode
= mp
->mnt_devvp
;
576 vnode_getalways(device_vnode
);
578 if (suser(vfs_context_ucred(ctx
), NULL
)) {
579 if ((error
= vnode_authorize(device_vnode
, NULL
,
580 KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, ctx
)) != 0) {
581 vnode_put(device_vnode
);
586 /* Tell the device that we're upgrading */
587 dev
= (dev_t
)device_vnode
->v_rdev
;
590 if ((u_int
)maj
>= (u_int
)nblkdev
)
591 panic("Volume mounted on a device with invalid major number.\n");
593 error
= bdevsw
[maj
].d_open(dev
, FREAD
| FWRITE
, S_IFBLK
, p
);
595 vnode_put(device_vnode
);
601 device_vnode
= NULLVP
;
605 if ((uap
->flags
& MNT_UPDATE
) == 0) {
606 mac_mount_label_init(mp
);
607 mac_mount_label_associate(ctx
, mp
);
609 if (uap
->mac_p
!= USER_ADDR_NULL
) {
611 char *labelstr
= NULL
;
614 if ((uap
->flags
& MNT_UPDATE
) != 0) {
615 error
= mac_mount_check_label_update(
621 error
= copyin(uap
->mac_p
, &mac
, sizeof(mac
));
624 error
= copyin(uap
->mac_p
, &mac32
, sizeof(mac32
));
625 mac
.m_buflen
= mac32
.m_buflen
;
626 mac
.m_string
= CAST_USER_ADDR_T(mac32
.m_string
);
630 if ((mac
.m_buflen
> MAC_MAX_LABEL_BUF_LEN
) ||
631 (mac
.m_buflen
< 2)) {
635 MALLOC(labelstr
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
636 error
= copyinstr(mac
.m_string
, labelstr
, mac
.m_buflen
, &ulen
);
638 FREE(labelstr
, M_MACTEMP
);
641 AUDIT_ARG(mac_string
, labelstr
);
642 error
= mac_mount_label_internalize(mp
->mnt_mntlabel
, labelstr
);
643 FREE(labelstr
, M_MACTEMP
);
648 if (device_vnode
!= NULL
) {
649 VNOP_IOCTL(device_vnode
, DKIOCGETBSDUNIT
, (caddr_t
)&mp
->mnt_devbsdunit
, 0, NULL
);
650 mp
->mnt_devbsdunit
%= LOWPRI_MAX_NUM_DEV
;
654 * Mount the filesystem.
656 error
= VFS_MOUNT(mp
, device_vnode
, fsmountargs
, ctx
);
658 if (uap
->flags
& MNT_UPDATE
) {
659 if (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)
660 mp
->mnt_flag
&= ~MNT_RDONLY
;
662 (MNT_UPDATE
| MNT_RELOAD
| MNT_FORCE
);
663 mp
->mnt_kern_flag
&=~ MNTK_WANTRDWR
;
666 vfs_event_signal(NULL
, VQ_UPDATE
, (intptr_t)NULL
);
667 lck_rw_done(&mp
->mnt_rwlock
);
668 is_rwlock_locked
= FALSE
;
670 enablequotas(mp
, ctx
);
674 * Put the new filesystem on the mount list after root.
677 struct vfs_attr vfsattr
;
679 if (vfs_flags(mp
) & MNT_MULTILABEL
) {
680 error
= VFS_ROOT(mp
, &rvp
, ctx
);
682 printf("%s() VFS_ROOT returned %d\n", __func__
, error
);
685 error
= vnode_label(mp
, NULL
, rvp
, NULL
, 0, ctx
);
687 * drop reference provided by VFS_ROOT
697 CLR(vp
->v_flag
, VMOUNT
);
698 vp
->v_mountedhere
= mp
;
702 * taking the name_cache_lock exclusively will
703 * insure that everyone is out of the fast path who
704 * might be trying to use a now stale copy of
705 * vp->v_mountedhere->mnt_realrootvp
706 * bumping mount_generation causes the cached values
713 error
= vnode_ref(vp
);
718 have_usecount
= TRUE
;
720 error
= checkdirs(vp
, ctx
);
722 /* Unmount the filesystem as cdir/rdirs cannot be updated */
726 * there is no cleanup code here so I have made it void
727 * we need to revisit this
729 (void)VFS_START(mp
, 0, ctx
);
731 error
= mount_list_add(mp
);
736 lck_rw_done(&mp
->mnt_rwlock
);
737 is_rwlock_locked
= FALSE
;
739 /* Check if this mounted file system supports EAs or named streams. */
740 /* Skip WebDAV file systems for now since they hang in VFS_GETATTR here. */
741 VFSATTR_INIT(&vfsattr
);
742 VFSATTR_WANTED(&vfsattr
, f_capabilities
);
743 if (strncmp(mp
->mnt_vfsstat
.f_fstypename
, "webdav", sizeof("webdav")) != 0 &&
744 vfs_getattr(mp
, &vfsattr
, ctx
) == 0 &&
745 VFSATTR_IS_SUPPORTED(&vfsattr
, f_capabilities
)) {
746 if ((vfsattr
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] & VOL_CAP_INT_EXTENDED_ATTR
) &&
747 (vfsattr
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] & VOL_CAP_INT_EXTENDED_ATTR
)) {
748 mp
->mnt_kern_flag
|= MNTK_EXTENDED_ATTRS
;
751 if ((vfsattr
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] & VOL_CAP_INT_NAMEDSTREAMS
) &&
752 (vfsattr
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] & VOL_CAP_INT_NAMEDSTREAMS
)) {
753 mp
->mnt_kern_flag
|= MNTK_NAMED_STREAMS
;
756 /* Check if this file system supports path from id lookups. */
757 if ((vfsattr
.f_capabilities
.capabilities
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_PATH_FROM_ID
) &&
758 (vfsattr
.f_capabilities
.valid
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_PATH_FROM_ID
)) {
759 mp
->mnt_kern_flag
|= MNTK_PATH_FROM_ID
;
760 } else if (mp
->mnt_flag
& MNT_DOVOLFS
) {
761 /* Legacy MNT_DOVOLFS flag also implies path from id lookups. */
762 mp
->mnt_kern_flag
|= MNTK_PATH_FROM_ID
;
765 if (mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSNATIVEXATTR
) {
766 mp
->mnt_kern_flag
|= MNTK_EXTENDED_ATTRS
;
768 if (mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSPREFLIGHT
) {
769 mp
->mnt_kern_flag
|= MNTK_UNMOUNT_PREFLIGHT
;
771 /* increment the operations count */
772 OSAddAtomic(1, &vfs_nummntops
);
773 enablequotas(mp
, ctx
);
776 device_vnode
->v_specflags
|= SI_MOUNTEDON
;
779 * cache the IO attributes for the underlying physical media...
780 * an error return indicates the underlying driver doesn't
781 * support all the queries necessary... however, reasonable
782 * defaults will have been set, so no reason to bail or care
784 vfs_init_io_attributes(device_vnode
, mp
);
787 /* Now that mount is setup, notify the listeners */
788 vfs_event_signal(NULL
, VQ_MOUNT
, (intptr_t)NULL
);
791 CLR(vp
->v_flag
, VMOUNT
);
794 mp
->mnt_vtable
->vfc_refcount
--;
798 vnode_rele(device_vnode
);
799 VNOP_CLOSE(device_vnode
, ronly
? FREAD
: FREAD
|FWRITE
, ctx
);
801 lck_rw_done(&mp
->mnt_rwlock
);
802 is_rwlock_locked
= FALSE
;
803 mount_lock_destroy(mp
);
805 mac_mount_label_destroy(mp
);
807 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
812 * drop I/O count on covered 'vp' and
813 * on the device vp if there was one
815 if (devpath
&& devvp
)
819 /* Note that we've changed something in the parent directory */
820 post_event_if_success(pvp
, error
, NOTE_WRITE
);
826 (void)VFS_UNMOUNT(mp
, MNT_FORCE
, ctx
);
827 if (device_vnode
!= NULLVP
) {
828 vnode_rele(device_vnode
);
829 VNOP_CLOSE(device_vnode
, mp
->mnt_flag
& MNT_RDONLY
? FREAD
: FREAD
|FWRITE
,
834 vp
->v_mountedhere
= (mount_t
) 0;
841 if (devpath
&& ((uap
->flags
& MNT_UPDATE
) == 0) && (!did_rele
))
844 if (devpath
&& devvp
)
847 /* Release mnt_rwlock only when it was taken */
848 if (is_rwlock_locked
== TRUE
) {
849 lck_rw_done(&mp
->mnt_rwlock
);
853 mac_mount_label_destroy(mp
);
855 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
860 vfsp
->vfc_refcount
--;
871 enablequotas(struct mount
*mp
, vfs_context_t ctx
)
873 struct nameidata qnd
;
875 char qfpath
[MAXPATHLEN
];
876 const char *qfname
= QUOTAFILENAME
;
877 const char *qfopsname
= QUOTAOPSNAME
;
878 const char *qfextension
[] = INITQFNAMES
;
880 /* XXX Shoulkd be an MNTK_ flag, instead of strncmp()'s */
881 if (strncmp(mp
->mnt_vfsstat
.f_fstypename
, "hfs", sizeof("hfs")) != 0 ) {
885 * Enable filesystem disk quotas if necessary.
886 * We ignore errors as this should not interfere with final mount
888 for (type
=0; type
< MAXQUOTAS
; type
++) {
889 snprintf(qfpath
, sizeof(qfpath
), "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfopsname
, qfextension
[type
]);
890 NDINIT(&qnd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE
, CAST_USER_ADDR_T(qfpath
), ctx
);
891 if (namei(&qnd
) != 0)
892 continue; /* option file to trigger quotas is not present */
893 vnode_put(qnd
.ni_vp
);
895 snprintf(qfpath
, sizeof(qfpath
), "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfname
, qfextension
[type
]);
897 (void) VFS_QUOTACTL(mp
, QCMD(Q_QUOTAON
, type
), 0, qfpath
, ctx
);
904 checkdirs_callback(proc_t p
, void * arg
)
906 struct cdirargs
* cdrp
= (struct cdirargs
* )arg
;
907 vnode_t olddp
= cdrp
->olddp
;
908 vnode_t newdp
= cdrp
->newdp
;
909 struct filedesc
*fdp
;
913 int cdir_changed
= 0;
914 int rdir_changed
= 0;
917 * XXX Also needs to iterate each thread in the process to see if it
918 * XXX is using a per-thread current working directory, and, if so,
919 * XXX update that as well.
924 if (fdp
== (struct filedesc
*)0) {
926 return(PROC_RETURNED
);
928 fdp_cvp
= fdp
->fd_cdir
;
929 fdp_rvp
= fdp
->fd_rdir
;
932 if (fdp_cvp
== olddp
) {
939 if (fdp_rvp
== olddp
) {
946 if (cdir_changed
|| rdir_changed
) {
948 fdp
->fd_cdir
= fdp_cvp
;
949 fdp
->fd_rdir
= fdp_rvp
;
952 return(PROC_RETURNED
);
958 * Scan all active processes to see if any of them have a current
959 * or root directory onto which the new filesystem has just been
960 * mounted. If so, replace them with the new mount point.
963 checkdirs(vnode_t olddp
, vfs_context_t ctx
)
969 struct uthread
* uth
= get_bsdthread_info(current_thread());
971 if (olddp
->v_usecount
== 1)
973 if (uth
!= (struct uthread
*)0)
974 uth
->uu_notrigger
= 1;
975 err
= VFS_ROOT(olddp
->v_mountedhere
, &newdp
, ctx
);
976 if (uth
!= (struct uthread
*)0)
977 uth
->uu_notrigger
= 0;
981 panic("mount: lost mount: error %d", err
);
988 /* do not block for exec/fork trans as the vp in cwd & rootdir are not changing */
989 proc_iterate(PROC_ALLPROCLIST
| PROC_NOWAITTRANS
, checkdirs_callback
, (void *)&cdr
, NULL
, NULL
);
991 if (rootvnode
== olddp
) {
1003 * Unmount a file system.
1005 * Note: unmount takes a path to the vnode mounted on as argument,
1006 * not special file (as before).
1010 unmount(__unused proc_t p
, struct unmount_args
*uap
, __unused
int32_t *retval
)
1015 struct nameidata nd
;
1016 vfs_context_t ctx
= vfs_context_current();
1018 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
1019 UIO_USERSPACE
, uap
->path
, ctx
);
1028 error
= mac_mount_check_umount(ctx
, mp
);
1035 * Must be the root of the filesystem
1037 if ((vp
->v_flag
& VROOT
) == 0) {
1043 /* safedounmount consumes the mount ref */
1044 return (safedounmount(mp
, uap
->flags
, ctx
));
1048 vfs_unmountbyfsid(fsid_t
* fsid
, int flags
, vfs_context_t ctx
)
1052 mp
= mount_list_lookupby_fsid(fsid
, 0, 1);
1053 if (mp
== (mount_t
)0) {
1058 /* safedounmount consumes the mount ref */
1059 return(safedounmount(mp
, flags
, ctx
));
1064 * The mount struct comes with a mount ref which will be consumed.
1065 * Do the actual file system unmount, prevent some common foot shooting.
1068 safedounmount(struct mount
*mp
, int flags
, vfs_context_t ctx
)
1071 proc_t p
= vfs_context_proc(ctx
);
1074 * Only root, or the user that did the original mount is
1075 * permitted to unmount this filesystem.
1077 if ((mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(kauth_cred_get())) &&
1078 (error
= suser(kauth_cred_get(), &p
->p_acflag
)))
1082 * Don't allow unmounting the root file system.
1084 if (mp
->mnt_flag
& MNT_ROOTFS
) {
1085 error
= EBUSY
; /* the root is always busy */
1089 return (dounmount(mp
, flags
, 1, ctx
));
1097 * Do the actual file system unmount.
1100 dounmount(struct mount
*mp
, int flags
, int withref
, vfs_context_t ctx
)
1102 vnode_t coveredvp
= (vnode_t
)0;
1105 int forcedunmount
= 0;
1107 struct vnode
*devvp
= NULLVP
;
1109 if (flags
& MNT_FORCE
)
1112 /* XXX post jaguar fix LK_DRAIN - then clean this up */
1113 if ((flags
& MNT_FORCE
)) {
1114 mp
->mnt_kern_flag
|= MNTK_FRCUNMOUNT
;
1115 mp
->mnt_lflag
|= MNT_LFORCE
;
1117 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
1118 mp
->mnt_lflag
|= MNT_LWAIT
;
1121 msleep((caddr_t
)mp
, &mp
->mnt_mlock
, (PVFS
| PDROP
), "dounmount", NULL
);
1123 * The prior unmount attempt has probably succeeded.
1124 * Do not dereference mp here - returning EBUSY is safest.
1128 mp
->mnt_kern_flag
|= MNTK_UNMOUNT
;
1129 mp
->mnt_lflag
|= MNT_LUNMOUNT
;
1130 mp
->mnt_flag
&=~ MNT_ASYNC
;
1132 * anyone currently in the fast path that
1133 * trips over the cached rootvp will be
1134 * dumped out and forced into the slow path
1135 * to regenerate a new cached value
1137 mp
->mnt_realrootvp
= NULLVP
;
1141 * taking the name_cache_lock exclusively will
1142 * insure that everyone is out of the fast path who
1143 * might be trying to use a now stale copy of
1144 * vp->v_mountedhere->mnt_realrootvp
1145 * bumping mount_generation causes the cached values
1150 name_cache_unlock();
1153 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
1157 fsevent_unmount(mp
); /* has to come first! */
1160 if (forcedunmount
== 0) {
1161 ubc_umount(mp
); /* release cached vnodes */
1162 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
1163 error
= VFS_SYNC(mp
, MNT_WAIT
, ctx
);
1166 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
1167 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
1168 mp
->mnt_lflag
&= ~MNT_LFORCE
;
1175 lflags
|= FORCECLOSE
;
1176 error
= vflush(mp
, NULLVP
, SKIPSWAP
| SKIPSYSTEM
| SKIPROOT
| lflags
);
1177 if ((forcedunmount
== 0) && error
) {
1179 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
1180 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
1181 mp
->mnt_lflag
&= ~MNT_LFORCE
;
1185 /* make sure there are no one in the mount iterations or lookup */
1186 mount_iterdrain(mp
);
1188 error
= VFS_UNMOUNT(mp
, flags
, ctx
);
1190 mount_iterreset(mp
);
1192 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
1193 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
1194 mp
->mnt_lflag
&= ~MNT_LFORCE
;
1198 /* increment the operations count */
1200 OSAddAtomic(1, &vfs_nummntops
);
1202 if ( mp
->mnt_devvp
&& mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
1203 /* hold an io reference and drop the usecount before close */
1204 devvp
= mp
->mnt_devvp
;
1205 vnode_getalways(devvp
);
1207 VNOP_CLOSE(devvp
, mp
->mnt_flag
& MNT_RDONLY
? FREAD
: FREAD
|FWRITE
,
1209 vnode_clearmountedon(devvp
);
1212 lck_rw_done(&mp
->mnt_rwlock
);
1213 mount_list_remove(mp
);
1214 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
1216 /* mark the mount point hook in the vp but not drop the ref yet */
1217 if ((coveredvp
= mp
->mnt_vnodecovered
) != NULLVP
) {
1218 vnode_getwithref(coveredvp
);
1219 vnode_lock_spin(coveredvp
);
1220 coveredvp
->v_mountedhere
= (struct mount
*)0;
1221 vnode_unlock(coveredvp
);
1222 vnode_put(coveredvp
);
1226 mp
->mnt_vtable
->vfc_refcount
--;
1227 mount_list_unlock();
1229 cache_purgevfs(mp
); /* remove cache entries for this file sys */
1230 vfs_event_signal(NULL
, VQ_UNMOUNT
, (intptr_t)NULL
);
1232 mp
->mnt_lflag
|= MNT_LDEAD
;
1234 if (mp
->mnt_lflag
& MNT_LWAIT
) {
1236 * do the wakeup here
1237 * in case we block in mount_refdrain
1238 * which will drop the mount lock
1239 * and allow anyone blocked in vfs_busy
1240 * to wakeup and see the LDEAD state
1242 mp
->mnt_lflag
&= ~MNT_LWAIT
;
1243 wakeup((caddr_t
)mp
);
1247 if (mp
->mnt_lflag
& MNT_LWAIT
) {
1248 mp
->mnt_lflag
&= ~MNT_LWAIT
;
1252 lck_rw_done(&mp
->mnt_rwlock
);
1255 wakeup((caddr_t
)mp
);
1257 if ((coveredvp
!= NULLVP
)) {
1260 vnode_getwithref(coveredvp
);
1261 pvp
= vnode_getparent(coveredvp
);
1262 vnode_rele(coveredvp
);
1263 vnode_lock_spin(coveredvp
);
1264 if(mp
->mnt_crossref
== 0) {
1265 vnode_unlock(coveredvp
);
1266 mount_lock_destroy(mp
);
1268 mac_mount_label_destroy(mp
);
1270 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
1272 coveredvp
->v_lflag
|= VL_MOUNTDEAD
;
1273 vnode_unlock(coveredvp
);
1275 vnode_put(coveredvp
);
1278 lock_vnode_and_post(pvp
, NOTE_WRITE
);
1281 } else if (mp
->mnt_flag
& MNT_ROOTFS
) {
1282 mount_lock_destroy(mp
);
1284 mac_mount_label_destroy(mp
);
1286 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
1288 panic("dounmount: no coveredvp");
1294 mount_dropcrossref(mount_t mp
, vnode_t dp
, int need_put
)
1298 if (mp
->mnt_crossref
< 0)
1299 panic("mount cross refs -ve");
1300 if (((dp
->v_lflag
& VL_MOUNTDEAD
) == VL_MOUNTDEAD
) && (mp
->mnt_crossref
== 0)) {
1301 dp
->v_lflag
&= ~VL_MOUNTDEAD
;
1303 vnode_put_locked(dp
);
1305 mount_lock_destroy(mp
);
1307 mac_mount_label_destroy(mp
);
1309 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
1313 vnode_put_locked(dp
);
1319 * Sync each mounted filesystem.
1323 struct ctldebug debug0
= { "syncprt", &syncprt
};
1326 int print_vmpage_stat
=0;
1329 sync_callback(mount_t mp
, void * arg
)
1333 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
1334 asyncflag
= mp
->mnt_flag
& MNT_ASYNC
;
1335 mp
->mnt_flag
&= ~MNT_ASYNC
;
1336 VFS_SYNC(mp
, arg
? MNT_WAIT
: MNT_NOWAIT
, vfs_context_current());
1338 mp
->mnt_flag
|= MNT_ASYNC
;
1340 return(VFS_RETURNED
);
1344 #include <kern/clock.h>
1346 clock_sec_t sync_wait_time
= 0;
1350 sync(__unused proc_t p
, __unused
struct sync_args
*uap
, __unused
int32_t *retval
)
1354 vfs_iterate(LK_NOWAIT
, sync_callback
, (void *)0);
1357 static fsid_t fsid
= { { 0, 0 } };
1359 clock_get_calendar_microtime(&sync_wait_time
, &nsecs
);
1360 vfs_event_signal(&fsid
, VQ_SYNCEVENT
, (intptr_t)NULL
);
1361 wakeup((caddr_t
)&sync_wait_time
);
1365 if(print_vmpage_stat
) {
1366 vm_countdirtypages();
1372 #endif /* DIAGNOSTIC */
1377 * Change filesystem quotas.
1380 static int quotactl_funneled(proc_t p
, struct quotactl_args
*uap
, int32_t *retval
);
1383 quotactl(proc_t p
, struct quotactl_args
*uap
, int32_t *retval
)
1385 boolean_t funnel_state
;
1388 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
1389 error
= quotactl_funneled(p
, uap
, retval
);
1390 thread_funnel_set(kernel_flock
, funnel_state
);
1395 quotactl_funneled(proc_t p
, struct quotactl_args
*uap
, __unused
int32_t *retval
)
1398 int error
, quota_cmd
, quota_status
;
1401 struct nameidata nd
;
1402 vfs_context_t ctx
= vfs_context_current();
1403 struct dqblk my_dqblk
;
1405 AUDIT_ARG(uid
, uap
->uid
);
1406 AUDIT_ARG(cmd
, uap
->cmd
);
1407 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1408 UIO_USERSPACE
, uap
->path
, ctx
);
1412 mp
= nd
.ni_vp
->v_mount
;
1413 vnode_put(nd
.ni_vp
);
1416 /* copyin any data we will need for downstream code */
1417 quota_cmd
= uap
->cmd
>> SUBCMDSHIFT
;
1419 switch (quota_cmd
) {
1421 /* uap->arg specifies a file from which to take the quotas */
1422 fnamelen
= MAXPATHLEN
;
1423 datap
= kalloc(MAXPATHLEN
);
1424 error
= copyinstr(uap
->arg
, datap
, MAXPATHLEN
, &fnamelen
);
1427 /* uap->arg is a pointer to a dqblk structure. */
1428 datap
= (caddr_t
) &my_dqblk
;
1432 /* uap->arg is a pointer to a dqblk structure. */
1433 datap
= (caddr_t
) &my_dqblk
;
1434 if (proc_is64bit(p
)) {
1435 struct user_dqblk my_dqblk64
;
1436 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk64
, sizeof (my_dqblk64
));
1438 munge_dqblk(&my_dqblk
, &my_dqblk64
, FALSE
);
1442 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk
, sizeof (my_dqblk
));
1446 /* uap->arg is a pointer to an integer */
1447 datap
= (caddr_t
) "a_status
;
1455 error
= VFS_QUOTACTL(mp
, uap
->cmd
, uap
->uid
, datap
, ctx
);
1458 switch (quota_cmd
) {
1461 kfree(datap
, MAXPATHLEN
);
1464 /* uap->arg is a pointer to a dqblk structure we need to copy out to */
1466 if (proc_is64bit(p
)) {
1467 struct user_dqblk my_dqblk64
;
1468 munge_dqblk(&my_dqblk
, &my_dqblk64
, TRUE
);
1469 error
= copyout((caddr_t
)&my_dqblk64
, uap
->arg
, sizeof (my_dqblk64
));
1472 error
= copyout(datap
, uap
->arg
, sizeof (struct dqblk
));
1477 /* uap->arg is a pointer to an integer */
1479 error
= copyout(datap
, uap
->arg
, sizeof(quota_status
));
1490 quotactl(__unused proc_t p
, __unused
struct quotactl_args
*uap
, __unused
int32_t *retval
)
1492 return (EOPNOTSUPP
);
1497 * Get filesystem statistics.
1499 * Returns: 0 Success
1501 * vfs_update_vfsstat:???
1502 * munge_statfs:EFAULT
1506 statfs(__unused proc_t p
, struct statfs_args
*uap
, __unused
int32_t *retval
)
1509 struct vfsstatfs
*sp
;
1511 struct nameidata nd
;
1512 vfs_context_t ctx
= vfs_context_current();
1515 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
1516 UIO_USERSPACE
, uap
->path
, ctx
);
1522 sp
= &mp
->mnt_vfsstat
;
1525 error
= vfs_update_vfsstat(mp
, ctx
, VFS_USER_EVENT
);
1530 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1535 * Get filesystem statistics.
1539 fstatfs(__unused proc_t p
, struct fstatfs_args
*uap
, __unused
int32_t *retval
)
1543 struct vfsstatfs
*sp
;
1546 AUDIT_ARG(fd
, uap
->fd
);
1548 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1551 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
1558 sp
= &mp
->mnt_vfsstat
;
1559 if ((error
= vfs_update_vfsstat(mp
,vfs_context_current(),VFS_USER_EVENT
)) != 0) {
1565 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1571 * Common routine to handle copying of statfs64 data to user space
1574 statfs64_common(struct mount
*mp
, struct vfsstatfs
*sfsp
, user_addr_t bufp
)
1577 struct statfs64 sfs
;
1579 bzero(&sfs
, sizeof(sfs
));
1581 sfs
.f_bsize
= sfsp
->f_bsize
;
1582 sfs
.f_iosize
= (int32_t)sfsp
->f_iosize
;
1583 sfs
.f_blocks
= sfsp
->f_blocks
;
1584 sfs
.f_bfree
= sfsp
->f_bfree
;
1585 sfs
.f_bavail
= sfsp
->f_bavail
;
1586 sfs
.f_files
= sfsp
->f_files
;
1587 sfs
.f_ffree
= sfsp
->f_ffree
;
1588 sfs
.f_fsid
= sfsp
->f_fsid
;
1589 sfs
.f_owner
= sfsp
->f_owner
;
1590 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
1591 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
1592 sfs
.f_fssubtype
= sfsp
->f_fssubtype
;
1593 strlcpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSTYPENAMELEN
);
1594 strlcpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MAXPATHLEN
);
1595 strlcpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MAXPATHLEN
);
1597 error
= copyout((caddr_t
)&sfs
, bufp
, sizeof(sfs
));
1603 * Get file system statistics in 64-bit mode
1606 statfs64(__unused
struct proc
*p
, struct statfs64_args
*uap
, __unused
int32_t *retval
)
1609 struct vfsstatfs
*sp
;
1611 struct nameidata nd
;
1612 vfs_context_t ctxp
= vfs_context_current();
1615 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
1616 UIO_USERSPACE
, uap
->path
, ctxp
);
1622 sp
= &mp
->mnt_vfsstat
;
1625 error
= vfs_update_vfsstat(mp
, ctxp
, VFS_USER_EVENT
);
1630 error
= statfs64_common(mp
, sp
, uap
->buf
);
1636 * Get file system statistics in 64-bit mode
1639 fstatfs64(__unused
struct proc
*p
, struct fstatfs64_args
*uap
, __unused
int32_t *retval
)
1643 struct vfsstatfs
*sp
;
1646 AUDIT_ARG(fd
, uap
->fd
);
1648 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1651 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
1658 sp
= &mp
->mnt_vfsstat
;
1659 if ((error
= vfs_update_vfsstat(mp
, vfs_context_current(), VFS_USER_EVENT
)) != 0) {
1665 error
= statfs64_common(mp
, sp
, uap
->buf
);
1670 struct getfsstat_struct
{
1681 getfsstat_callback(mount_t mp
, void * arg
)
1684 struct getfsstat_struct
*fstp
= (struct getfsstat_struct
*)arg
;
1685 struct vfsstatfs
*sp
;
1687 vfs_context_t ctx
= vfs_context_current();
1689 if (fstp
->sfsp
&& fstp
->count
< fstp
->maxcount
) {
1690 sp
= &mp
->mnt_vfsstat
;
1692 * If MNT_NOWAIT is specified, do not refresh the
1693 * fsstat cache. MNT_WAIT/MNT_DWAIT overrides MNT_NOWAIT.
1695 if (((fstp
->flags
& MNT_NOWAIT
) == 0 || (fstp
->flags
& (MNT_WAIT
| MNT_DWAIT
))) &&
1696 (error
= vfs_update_vfsstat(mp
, ctx
,
1698 KAUTH_DEBUG("vfs_update_vfsstat returned %d", error
);
1699 return(VFS_RETURNED
);
1703 * Need to handle LP64 version of struct statfs
1705 error
= munge_statfs(mp
, sp
, fstp
->sfsp
, &my_size
, IS_64BIT_PROCESS(vfs_context_proc(ctx
)), FALSE
);
1707 fstp
->error
= error
;
1708 return(VFS_RETURNED_DONE
);
1710 fstp
->sfsp
+= my_size
;
1713 error
= mac_mount_label_get(mp
, *fstp
->mp
);
1715 fstp
->error
= error
;
1716 return(VFS_RETURNED_DONE
);
1722 return(VFS_RETURNED
);
1726 * Get statistics on all filesystems.
1729 getfsstat(__unused proc_t p
, struct getfsstat_args
*uap
, int *retval
)
1731 struct __mac_getfsstat_args muap
;
1733 muap
.buf
= uap
->buf
;
1734 muap
.bufsize
= uap
->bufsize
;
1735 muap
.mac
= USER_ADDR_NULL
;
1737 muap
.flags
= uap
->flags
;
1739 return (__mac_getfsstat(p
, &muap
, retval
));
1743 * __mac_getfsstat: Get MAC-related file system statistics
1745 * Parameters: p (ignored)
1746 * uap User argument descriptor (see below)
1747 * retval Count of file system statistics (N stats)
1749 * Indirect: uap->bufsize Buffer size
1750 * uap->macsize MAC info size
1751 * uap->buf Buffer where information will be returned
1753 * uap->flags File system flags
1756 * Returns: 0 Success
1761 __mac_getfsstat(__unused proc_t p
, struct __mac_getfsstat_args
*uap
, int *retval
)
1765 size_t count
, maxcount
, bufsize
, macsize
;
1766 struct getfsstat_struct fst
;
1768 bufsize
= (size_t) uap
->bufsize
;
1769 macsize
= (size_t) uap
->macsize
;
1771 if (IS_64BIT_PROCESS(p
)) {
1772 maxcount
= bufsize
/ sizeof(struct user64_statfs
);
1775 maxcount
= bufsize
/ sizeof(struct user32_statfs
);
1783 if (uap
->mac
!= USER_ADDR_NULL
) {
1788 count
= (macsize
/ (IS_64BIT_PROCESS(p
) ? 8 : 4));
1789 if (count
!= maxcount
)
1792 /* Copy in the array */
1793 MALLOC(mp0
, u_int32_t
*, macsize
, M_MACTEMP
, M_WAITOK
);
1798 error
= copyin(uap
->mac
, mp0
, macsize
);
1800 FREE(mp0
, M_MACTEMP
);
1804 /* Normalize to an array of user_addr_t */
1805 MALLOC(mp
, user_addr_t
*, count
* sizeof(user_addr_t
), M_MACTEMP
, M_WAITOK
);
1807 FREE(mp0
, M_MACTEMP
);
1811 for (i
= 0; i
< count
; i
++) {
1812 if (IS_64BIT_PROCESS(p
))
1813 mp
[i
] = ((user_addr_t
*)mp0
)[i
];
1815 mp
[i
] = (user_addr_t
)mp0
[i
];
1817 FREE(mp0
, M_MACTEMP
);
1824 fst
.flags
= uap
->flags
;
1827 fst
.maxcount
= maxcount
;
1830 vfs_iterate(0, getfsstat_callback
, &fst
);
1833 FREE(mp
, M_MACTEMP
);
1836 KAUTH_DEBUG("ERROR - %s gets %d", p
->p_comm
, fst
.error
);
1840 if (fst
.sfsp
&& fst
.count
> fst
.maxcount
)
1841 *retval
= fst
.maxcount
;
1843 *retval
= fst
.count
;
1848 getfsstat64_callback(mount_t mp
, void * arg
)
1850 struct getfsstat_struct
*fstp
= (struct getfsstat_struct
*)arg
;
1851 struct vfsstatfs
*sp
;
1854 if (fstp
->sfsp
&& fstp
->count
< fstp
->maxcount
) {
1855 sp
= &mp
->mnt_vfsstat
;
1857 * If MNT_NOWAIT is specified, do not refresh the fsstat
1858 * cache. MNT_WAIT overrides MNT_NOWAIT.
1860 * We treat MNT_DWAIT as MNT_WAIT for all instances of
1861 * getfsstat, since the constants are out of the same
1864 if (((fstp
->flags
& MNT_NOWAIT
) == 0 ||
1865 (fstp
->flags
& (MNT_WAIT
| MNT_DWAIT
))) &&
1866 (error
= vfs_update_vfsstat(mp
, vfs_context_current(), VFS_USER_EVENT
))) {
1867 KAUTH_DEBUG("vfs_update_vfsstat returned %d", error
);
1868 return(VFS_RETURNED
);
1871 error
= statfs64_common(mp
, sp
, fstp
->sfsp
);
1873 fstp
->error
= error
;
1874 return(VFS_RETURNED_DONE
);
1876 fstp
->sfsp
+= sizeof(struct statfs64
);
1879 return(VFS_RETURNED
);
1883 * Get statistics on all file systems in 64 bit mode.
1886 getfsstat64(__unused proc_t p
, struct getfsstat64_args
*uap
, int *retval
)
1889 int count
, maxcount
;
1890 struct getfsstat_struct fst
;
1892 maxcount
= uap
->bufsize
/ sizeof(struct statfs64
);
1898 fst
.flags
= uap
->flags
;
1901 fst
.maxcount
= maxcount
;
1903 vfs_iterate(0, getfsstat64_callback
, &fst
);
1906 KAUTH_DEBUG("ERROR - %s gets %d", p
->p_comm
, fst
.error
);
1910 if (fst
.sfsp
&& fst
.count
> fst
.maxcount
)
1911 *retval
= fst
.maxcount
;
1913 *retval
= fst
.count
;
1919 * Change current working directory to a given file descriptor.
1923 common_fchdir(proc_t p
, struct fchdir_args
*uap
, int per_thread
)
1925 struct filedesc
*fdp
= p
->p_fd
;
1931 vfs_context_t ctx
= vfs_context_current();
1933 AUDIT_ARG(fd
, uap
->fd
);
1934 if (per_thread
&& uap
->fd
== -1) {
1936 * Switching back from per-thread to per process CWD; verify we
1937 * in fact have one before proceeding. The only success case
1938 * for this code path is to return 0 preemptively after zapping
1939 * the thread structure contents.
1941 thread_t th
= vfs_context_thread(ctx
);
1943 uthread_t uth
= get_bsdthread_info(th
);
1945 uth
->uu_cdir
= NULLVP
;
1946 if (tvp
!= NULLVP
) {
1954 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1956 if ( (error
= vnode_getwithref(vp
)) ) {
1961 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
1963 if (vp
->v_type
!= VDIR
) {
1969 error
= mac_vnode_check_chdir(ctx
, vp
);
1973 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, ctx
);
1977 while (!error
&& (mp
= vp
->v_mountedhere
) != NULL
) {
1978 if (vfs_busy(mp
, LK_NOWAIT
)) {
1982 error
= VFS_ROOT(mp
, &tdp
, ctx
);
1991 if ( (error
= vnode_ref(vp
)) )
1996 thread_t th
= vfs_context_thread(ctx
);
1998 uthread_t uth
= get_bsdthread_info(th
);
2001 OSBitOrAtomic(P_THCWD
, &p
->p_flag
);
2026 fchdir(proc_t p
, struct fchdir_args
*uap
, __unused
int32_t *retval
)
2028 return common_fchdir(p
, uap
, 0);
2032 __pthread_fchdir(proc_t p
, struct __pthread_fchdir_args
*uap
, __unused
int32_t *retval
)
2034 return common_fchdir(p
, (void *)uap
, 1);
2038 * Change current working directory (".").
2040 * Returns: 0 Success
2041 * change_dir:ENOTDIR
2043 * vnode_ref:ENOENT No such file or directory
2047 common_chdir(proc_t p
, struct chdir_args
*uap
, int per_thread
)
2049 struct filedesc
*fdp
= p
->p_fd
;
2051 struct nameidata nd
;
2053 vfs_context_t ctx
= vfs_context_current();
2055 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2056 UIO_USERSPACE
, uap
->path
, ctx
);
2057 error
= change_dir(&nd
, ctx
);
2060 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
2061 vnode_put(nd
.ni_vp
);
2065 * drop the iocount we picked up in change_dir
2067 vnode_put(nd
.ni_vp
);
2070 thread_t th
= vfs_context_thread(ctx
);
2072 uthread_t uth
= get_bsdthread_info(th
);
2074 uth
->uu_cdir
= nd
.ni_vp
;
2075 OSBitOrAtomic(P_THCWD
, &p
->p_flag
);
2077 vnode_rele(nd
.ni_vp
);
2083 fdp
->fd_cdir
= nd
.ni_vp
;
2097 * Change current working directory (".") for the entire process
2099 * Parameters: p Process requesting the call
2100 * uap User argument descriptor (see below)
2103 * Indirect parameters: uap->path Directory path
2105 * Returns: 0 Success
2106 * common_chdir: ENOTDIR
2107 * common_chdir: ENOENT No such file or directory
2112 chdir(proc_t p
, struct chdir_args
*uap
, __unused
int32_t *retval
)
2114 return common_chdir(p
, (void *)uap
, 0);
2120 * Change current working directory (".") for a single thread
2122 * Parameters: p Process requesting the call
2123 * uap User argument descriptor (see below)
2126 * Indirect parameters: uap->path Directory path
2128 * Returns: 0 Success
2129 * common_chdir: ENOTDIR
2130 * common_chdir: ENOENT No such file or directory
2135 __pthread_chdir(proc_t p
, struct __pthread_chdir_args
*uap
, __unused
int32_t *retval
)
2137 return common_chdir(p
, (void *)uap
, 1);
2142 * Change notion of root (``/'') directory.
2146 chroot(proc_t p
, struct chroot_args
*uap
, __unused
int32_t *retval
)
2148 struct filedesc
*fdp
= p
->p_fd
;
2150 struct nameidata nd
;
2152 vfs_context_t ctx
= vfs_context_current();
2154 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
2157 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2158 UIO_USERSPACE
, uap
->path
, ctx
);
2159 error
= change_dir(&nd
, ctx
);
2164 error
= mac_vnode_check_chroot(ctx
, nd
.ni_vp
,
2167 vnode_put(nd
.ni_vp
);
2172 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
2173 vnode_put(nd
.ni_vp
);
2176 vnode_put(nd
.ni_vp
);
2180 fdp
->fd_rdir
= nd
.ni_vp
;
2181 fdp
->fd_flags
|= FD_CHROOT
;
2191 * Common routine for chroot and chdir.
2193 * Returns: 0 Success
2194 * ENOTDIR Not a directory
2195 * namei:??? [anything namei can return]
2196 * vnode_authorize:??? [anything vnode_authorize can return]
2199 change_dir(struct nameidata
*ndp
, vfs_context_t ctx
)
2204 if ((error
= namei(ndp
)))
2209 if (vp
->v_type
!= VDIR
) {
2215 error
= mac_vnode_check_chdir(ctx
, vp
);
2222 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, ctx
);
2232 * Check permissions, allocate an open file structure,
2233 * and call the device open routine if any.
2235 * Returns: 0 Success
2246 * XXX Need to implement uid, gid
2249 open1(vfs_context_t ctx
, struct nameidata
*ndp
, int uflags
, struct vnode_attr
*vap
, int32_t *retval
)
2251 proc_t p
= vfs_context_proc(ctx
);
2252 uthread_t uu
= get_bsdthread_info(vfs_context_thread(ctx
));
2253 struct filedesc
*fdp
= p
->p_fd
;
2254 struct fileproc
*fp
;
2257 struct fileproc
*nfp
;
2258 int type
, indx
, error
;
2260 int no_controlling_tty
= 0;
2261 int deny_controlling_tty
= 0;
2262 struct session
*sessp
= SESSION_NULL
;
2263 struct vfs_context context
= *vfs_context_current(); /* local copy */
2267 if ((oflags
& O_ACCMODE
) == O_ACCMODE
)
2269 flags
= FFLAGS(uflags
);
2271 AUDIT_ARG(fflags
, oflags
);
2272 AUDIT_ARG(mode
, vap
->va_mode
);
2274 if ( (error
= falloc(p
, &nfp
, &indx
, ctx
)) ) {
2278 uu
->uu_dupfd
= -indx
- 1;
2280 if (!(p
->p_flag
& P_CONTROLT
)) {
2281 sessp
= proc_session(p
);
2282 no_controlling_tty
= 1;
2284 * If conditions would warrant getting a controlling tty if
2285 * the device being opened is a tty (see ttyopen in tty.c),
2286 * but the open flags deny it, set a flag in the session to
2289 if (SESS_LEADER(p
, sessp
) &&
2290 sessp
->s_ttyvp
== NULL
&&
2291 (flags
& O_NOCTTY
)) {
2292 session_lock(sessp
);
2293 sessp
->s_flags
|= S_NOCTTY
;
2294 session_unlock(sessp
);
2295 deny_controlling_tty
= 1;
2299 if ((error
= vn_open_auth(ndp
, &flags
, vap
))) {
2300 if ((error
== ENODEV
|| error
== ENXIO
) && (uu
->uu_dupfd
>= 0)){ /* XXX from fdopen */
2301 if ((error
= dupfdopen(fdp
, indx
, uu
->uu_dupfd
, flags
, error
)) == 0) {
2302 fp_drop(p
, indx
, NULL
, 0);
2304 if (deny_controlling_tty
) {
2305 session_lock(sessp
);
2306 sessp
->s_flags
&= ~S_NOCTTY
;
2307 session_unlock(sessp
);
2309 if (sessp
!= SESSION_NULL
)
2310 session_rele(sessp
);
2314 if (error
== ERESTART
)
2316 fp_free(p
, indx
, fp
);
2318 if (deny_controlling_tty
) {
2319 session_lock(sessp
);
2320 sessp
->s_flags
&= ~S_NOCTTY
;
2321 session_unlock(sessp
);
2323 if (sessp
!= SESSION_NULL
)
2324 session_rele(sessp
);
2330 fp
->f_fglob
->fg_flag
= flags
& (FMASK
| O_EVTONLY
);
2331 fp
->f_fglob
->fg_type
= DTYPE_VNODE
;
2332 fp
->f_fglob
->fg_ops
= &vnops
;
2333 fp
->f_fglob
->fg_data
= (caddr_t
)vp
;
2335 if (flags
& (O_EXLOCK
| O_SHLOCK
)) {
2336 lf
.l_whence
= SEEK_SET
;
2339 if (flags
& O_EXLOCK
)
2340 lf
.l_type
= F_WRLCK
;
2342 lf
.l_type
= F_RDLCK
;
2344 if ((flags
& FNONBLOCK
) == 0)
2347 error
= mac_file_check_lock(vfs_context_ucred(ctx
), fp
->f_fglob
,
2352 if ((error
= VNOP_ADVLOCK(vp
, (caddr_t
)fp
->f_fglob
, F_SETLK
, &lf
, type
, ctx
)))
2354 fp
->f_fglob
->fg_flag
|= FHASLOCK
;
2357 /* try to truncate by setting the size attribute */
2358 if ((flags
& O_TRUNC
) && ((error
= vnode_setsize(vp
, (off_t
)0, 0, ctx
)) != 0))
2362 * If the open flags denied the acquisition of a controlling tty,
2363 * clear the flag in the session structure that prevented the lower
2364 * level code from assigning one.
2366 if (deny_controlling_tty
) {
2367 session_lock(sessp
);
2368 sessp
->s_flags
&= ~S_NOCTTY
;
2369 session_unlock(sessp
);
2373 * If a controlling tty was set by the tty line discipline, then we
2374 * want to set the vp of the tty into the session structure. We have
2375 * a race here because we can't get to the vp for the tp in ttyopen,
2376 * because it's not passed as a parameter in the open path.
2378 if (no_controlling_tty
&& (p
->p_flag
& P_CONTROLT
)) {
2381 session_lock(sessp
);
2382 ttyvp
= sessp
->s_ttyvp
;
2383 sessp
->s_ttyvp
= vp
;
2384 sessp
->s_ttyvid
= vnode_vid(vp
);
2385 session_unlock(sessp
);
2386 if (ttyvp
!= NULLVP
)
2393 procfdtbl_releasefd(p
, indx
, NULL
);
2394 fp_drop(p
, indx
, fp
, 1);
2399 if (sessp
!= SESSION_NULL
)
2400 session_rele(sessp
);
2403 if (deny_controlling_tty
) {
2404 session_lock(sessp
);
2405 sessp
->s_flags
&= ~S_NOCTTY
;
2406 session_unlock(sessp
);
2408 if (sessp
!= SESSION_NULL
)
2409 session_rele(sessp
);
2411 /* Modify local copy (to not damage thread copy) */
2412 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
2414 vn_close(vp
, fp
->f_fglob
->fg_flag
, &context
);
2416 fp_free(p
, indx
, fp
);
2423 * open_extended: open a file given a path name; with extended argument list (including extended security (ACL)).
2425 * Parameters: p Process requesting the open
2426 * uap User argument descriptor (see below)
2427 * retval Pointer to an area to receive the
2428 * return calue from the system call
2430 * Indirect: uap->path Path to open (same as 'open')
2431 * uap->flags Flags to open (same as 'open'
2432 * uap->uid UID to set, if creating
2433 * uap->gid GID to set, if creating
2434 * uap->mode File mode, if creating (same as 'open')
2435 * uap->xsecurity ACL to set, if creating
2437 * Returns: 0 Success
2440 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
2442 * XXX: We should enummerate the possible errno values here, and where
2443 * in the code they originated.
2446 open_extended(proc_t p
, struct open_extended_args
*uap
, int32_t *retval
)
2448 struct filedesc
*fdp
= p
->p_fd
;
2450 kauth_filesec_t xsecdst
;
2451 struct vnode_attr va
;
2452 struct nameidata nd
;
2455 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
2458 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
2459 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
2463 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
2464 VATTR_SET(&va
, va_mode
, cmode
);
2465 if (uap
->uid
!= KAUTH_UID_NONE
)
2466 VATTR_SET(&va
, va_uid
, uap
->uid
);
2467 if (uap
->gid
!= KAUTH_GID_NONE
)
2468 VATTR_SET(&va
, va_gid
, uap
->gid
);
2469 if (xsecdst
!= NULL
)
2470 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2472 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, vfs_context_current());
2474 ciferror
= open1(vfs_context_current(), &nd
, uap
->flags
, &va
, retval
);
2475 if (xsecdst
!= NULL
)
2476 kauth_filesec_free(xsecdst
);
2482 open(proc_t p
, struct open_args
*uap
, int32_t *retval
)
2484 __pthread_testcancel(1);
2485 return(open_nocancel(p
, (struct open_nocancel_args
*)uap
, retval
));
2489 open_nocancel(proc_t p
, struct open_nocancel_args
*uap
, int32_t *retval
)
2491 struct filedesc
*fdp
= p
->p_fd
;
2492 struct vnode_attr va
;
2493 struct nameidata nd
;
2497 /* Mask off all but regular access permissions */
2498 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
2499 VATTR_SET(&va
, va_mode
, cmode
& ACCESSPERMS
);
2501 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, vfs_context_current());
2503 return(open1(vfs_context_current(), &nd
, uap
->flags
, &va
, retval
));
2508 * Create a special file.
2510 static int mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
);
2513 mknod(proc_t p
, struct mknod_args
*uap
, __unused
int32_t *retval
)
2515 struct vnode_attr va
;
2516 vfs_context_t ctx
= vfs_context_current();
2519 struct nameidata nd
;
2523 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
2524 VATTR_SET(&va
, va_rdev
, uap
->dev
);
2526 /* If it's a mknod() of a FIFO, call mkfifo1() instead */
2527 if ((uap
->mode
& S_IFMT
) == S_IFIFO
)
2528 return(mkfifo1(ctx
, uap
->path
, &va
));
2530 AUDIT_ARG(mode
, uap
->mode
);
2531 AUDIT_ARG(value32
, uap
->dev
);
2533 if ((error
= suser(vfs_context_ucred(ctx
), &p
->p_acflag
)))
2535 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
2536 UIO_USERSPACE
, uap
->path
, ctx
);
2548 switch (uap
->mode
& S_IFMT
) {
2549 case S_IFMT
: /* used by badsect to flag bad sectors */
2550 VATTR_SET(&va
, va_type
, VBAD
);
2553 VATTR_SET(&va
, va_type
, VCHR
);
2556 VATTR_SET(&va
, va_type
, VBLK
);
2568 error
= mac_vnode_check_create(ctx
,
2569 nd
.ni_dvp
, &nd
.ni_cnd
, &va
);
2575 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
2579 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, CREATE
, ctx
);
2581 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, &va
, 0, ctx
);
2587 int update_flags
= 0;
2589 // Make sure the name & parent pointers are hooked up
2590 if (vp
->v_name
== NULL
)
2591 update_flags
|= VNODE_UPDATE_NAME
;
2592 if (vp
->v_parent
== NULLVP
)
2593 update_flags
|= VNODE_UPDATE_PARENT
;
2596 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
2599 add_fsevent(FSE_CREATE_FILE
, ctx
,
2607 * nameidone has to happen before we vnode_put(dvp)
2608 * since it may need to release the fs_nodelock on the dvp
2620 * Create a named pipe.
2622 * Returns: 0 Success
2625 * vnode_authorize:???
2629 mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
)
2633 struct nameidata nd
;
2635 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
2636 UIO_USERSPACE
, upath
, ctx
);
2643 /* check that this is a new file and authorize addition */
2648 VATTR_SET(vap
, va_type
, VFIFO
);
2651 error
= mac_vnode_check_create(ctx
, nd
.ni_dvp
,
2658 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
2662 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
);
2665 * nameidone has to happen before we vnode_put(dvp)
2666 * since it may need to release the fs_nodelock on the dvp
2679 * mkfifo_extended: Create a named pipe; with extended argument list (including extended security (ACL)).
2681 * Parameters: p Process requesting the open
2682 * uap User argument descriptor (see below)
2685 * Indirect: uap->path Path to fifo (same as 'mkfifo')
2686 * uap->uid UID to set
2687 * uap->gid GID to set
2688 * uap->mode File mode to set (same as 'mkfifo')
2689 * uap->xsecurity ACL to set, if creating
2691 * Returns: 0 Success
2694 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
2696 * XXX: We should enummerate the possible errno values here, and where
2697 * in the code they originated.
2700 mkfifo_extended(proc_t p
, struct mkfifo_extended_args
*uap
, __unused
int32_t *retval
)
2703 kauth_filesec_t xsecdst
;
2704 struct vnode_attr va
;
2706 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
2708 xsecdst
= KAUTH_FILESEC_NONE
;
2709 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
2710 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
2715 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
2716 if (uap
->uid
!= KAUTH_UID_NONE
)
2717 VATTR_SET(&va
, va_uid
, uap
->uid
);
2718 if (uap
->gid
!= KAUTH_GID_NONE
)
2719 VATTR_SET(&va
, va_gid
, uap
->gid
);
2720 if (xsecdst
!= KAUTH_FILESEC_NONE
)
2721 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2723 ciferror
= mkfifo1(vfs_context_current(), uap
->path
, &va
);
2725 if (xsecdst
!= KAUTH_FILESEC_NONE
)
2726 kauth_filesec_free(xsecdst
);
2732 mkfifo(proc_t p
, struct mkfifo_args
*uap
, __unused
int32_t *retval
)
2734 struct vnode_attr va
;
2737 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
2739 return(mkfifo1(vfs_context_current(), uap
->path
, &va
));
2744 my_strrchr(char *p
, int ch
)
2748 for (save
= NULL
;; ++p
) {
2757 extern int safe_getpath(struct vnode
*dvp
, char *leafname
, char *path
, int _len
, int *truncated_path
);
2760 safe_getpath(struct vnode
*dvp
, char *leafname
, char *path
, int _len
, int *truncated_path
)
2762 int ret
, len
= _len
;
2764 *truncated_path
= 0;
2765 ret
= vn_getpath(dvp
, path
, &len
);
2766 if (ret
== 0 && len
< (MAXPATHLEN
- 1)) {
2769 len
+= strlcpy(&path
[len
], leafname
, MAXPATHLEN
-len
) + 1;
2770 if (len
> MAXPATHLEN
) {
2773 // the string got truncated!
2774 *truncated_path
= 1;
2775 ptr
= my_strrchr(path
, '/');
2777 *ptr
= '\0'; // chop off the string at the last directory component
2779 len
= strlen(path
) + 1;
2782 } else if (ret
== 0) {
2783 *truncated_path
= 1;
2784 } else if (ret
!= 0) {
2785 struct vnode
*mydvp
=dvp
;
2787 if (ret
!= ENOSPC
) {
2788 printf("safe_getpath: failed to get the path for vp %p (%s) : err %d\n",
2789 dvp
, dvp
->v_name
? dvp
->v_name
: "no-name", ret
);
2791 *truncated_path
= 1;
2794 if (mydvp
->v_parent
!= NULL
) {
2795 mydvp
= mydvp
->v_parent
;
2796 } else if (mydvp
->v_mount
) {
2797 strlcpy(path
, mydvp
->v_mount
->mnt_vfsstat
.f_mntonname
, _len
);
2800 // no parent and no mount point? only thing is to punt and say "/" changed
2801 strlcpy(path
, "/", _len
);
2806 if (mydvp
== NULL
) {
2811 ret
= vn_getpath(mydvp
, path
, &len
);
2812 } while (ret
== ENOSPC
);
2820 * Make a hard file link.
2822 * Returns: 0 Success
2827 * vnode_authorize:???
2832 link(__unused proc_t p
, struct link_args
*uap
, __unused
int32_t *retval
)
2834 vnode_t vp
, dvp
, lvp
;
2835 struct nameidata nd
;
2836 vfs_context_t ctx
= vfs_context_current();
2841 int need_event
, has_listeners
;
2842 char *target_path
= NULL
;
2845 vp
= dvp
= lvp
= NULLVP
;
2847 /* look up the object we are linking to */
2848 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2849 UIO_USERSPACE
, uap
->path
, ctx
);
2858 * Normally, linking to directories is not supported.
2859 * However, some file systems may have limited support.
2861 if (vp
->v_type
== VDIR
) {
2862 if (!(vp
->v_mount
->mnt_vtable
->vfc_vfsflags
& VFC_VFSDIRLINKS
)) {
2863 error
= EPERM
; /* POSIX */
2866 /* Linking to a directory requires ownership. */
2867 if (!kauth_cred_issuser(vfs_context_ucred(ctx
))) {
2868 struct vnode_attr dva
;
2871 VATTR_WANTED(&dva
, va_uid
);
2872 if (vnode_getattr(vp
, &dva
, ctx
) != 0 ||
2873 !VATTR_IS_SUPPORTED(&dva
, va_uid
) ||
2874 (dva
.va_uid
!= kauth_cred_getuid(vfs_context_ucred(ctx
)))) {
2881 /* lookup the target node */
2882 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2883 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| AUDITVNPATH2
| CN_NBMOUNTLOOK
;
2884 nd
.ni_dirp
= uap
->link
;
2892 if ((error
= mac_vnode_check_link(ctx
, dvp
, vp
, &nd
.ni_cnd
)) != 0)
2896 /* or to anything that kauth doesn't want us to (eg. immutable items) */
2897 if ((error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_LINKTARGET
, ctx
)) != 0)
2900 /* target node must not exist */
2901 if (lvp
!= NULLVP
) {
2905 /* cannot link across mountpoints */
2906 if (vnode_mount(vp
) != vnode_mount(dvp
)) {
2911 /* authorize creation of the target note */
2912 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
2915 /* and finally make the link */
2916 error
= VNOP_LINK(vp
, dvp
, &nd
.ni_cnd
, ctx
);
2921 need_event
= need_fsevent(FSE_CREATE_FILE
, dvp
);
2925 has_listeners
= kauth_authorize_fileop_has_listeners();
2927 if (need_event
|| has_listeners
) {
2928 char *link_to_path
= NULL
;
2929 int len
, link_name_len
;
2931 /* build the path to the new link file */
2932 GET_PATH(target_path
);
2933 if (target_path
== NULL
) {
2938 len
= safe_getpath(dvp
, nd
.ni_cnd
.cn_nameptr
, target_path
, MAXPATHLEN
, &truncated
);
2940 if (has_listeners
) {
2941 /* build the path to file we are linking to */
2942 GET_PATH(link_to_path
);
2943 if (link_to_path
== NULL
) {
2948 link_name_len
= MAXPATHLEN
;
2949 vn_getpath(vp
, link_to_path
, &link_name_len
);
2952 * Call out to allow 3rd party notification of rename.
2953 * Ignore result of kauth_authorize_fileop call.
2955 kauth_authorize_fileop(vfs_context_ucred(ctx
), KAUTH_FILEOP_LINK
,
2956 (uintptr_t)link_to_path
, (uintptr_t)target_path
);
2957 if (link_to_path
!= NULL
) {
2958 RELEASE_PATH(link_to_path
);
2963 /* construct fsevent */
2964 if (get_fse_info(vp
, &finfo
, ctx
) == 0) {
2966 finfo
.mode
|= FSE_TRUNCATED_PATH
;
2969 // build the path to the destination of the link
2970 add_fsevent(FSE_CREATE_FILE
, ctx
,
2971 FSE_ARG_STRING
, len
, target_path
,
2972 FSE_ARG_FINFO
, &finfo
,
2976 add_fsevent(FSE_STAT_CHANGED
, ctx
,
2977 FSE_ARG_VNODE
, vp
->v_parent
,
2985 * nameidone has to happen before we vnode_put(dvp)
2986 * since it may need to release the fs_nodelock on the dvp
2989 if (target_path
!= NULL
) {
2990 RELEASE_PATH(target_path
);
3002 * Make a symbolic link.
3004 * We could add support for ACLs here too...
3008 symlink(proc_t p
, struct symlink_args
*uap
, __unused
int32_t *retval
)
3010 struct vnode_attr va
;
3013 struct nameidata nd
;
3014 vfs_context_t ctx
= vfs_context_current();
3018 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
3019 error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
);
3022 AUDIT_ARG(text
, path
); /* This is the link string */
3024 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
3025 UIO_USERSPACE
, uap
->link
, ctx
);
3033 VATTR_SET(&va
, va_type
, VLNK
);
3034 VATTR_SET(&va
, va_mode
, ACCESSPERMS
& ~p
->p_fd
->fd_cmask
);
3036 error
= mac_vnode_check_create(ctx
,
3037 dvp
, &nd
.ni_cnd
, &va
);
3050 error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
);
3051 /* get default ownership, etc. */
3053 error
= vnode_authattr_new(dvp
, &va
, 0, ctx
);
3055 error
= VNOP_SYMLINK(dvp
, &vp
, &nd
.ni_cnd
, &va
, path
, ctx
);
3057 /* do fallback attribute handling */
3059 error
= vnode_setattr_fallback(vp
, &va
, ctx
);
3062 int update_flags
= 0;
3065 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
3066 nd
.ni_cnd
.cn_flags
= 0;
3074 #if 0 /* XXX - kauth_todo - is KAUTH_FILEOP_SYMLINK needed? */
3075 /* call out to allow 3rd party notification of rename.
3076 * Ignore result of kauth_authorize_fileop call.
3078 if (kauth_authorize_fileop_has_listeners() &&
3080 char *new_link_path
= NULL
;
3083 /* build the path to the new link file */
3084 new_link_path
= get_pathbuff();
3086 vn_getpath(dvp
, new_link_path
, &len
);
3087 if ((len
+ 1 + nd
.ni_cnd
.cn_namelen
+ 1) < MAXPATHLEN
) {
3088 new_link_path
[len
- 1] = '/';
3089 strlcpy(&new_link_path
[len
], nd
.ni_cnd
.cn_nameptr
, MAXPATHLEN
-len
);
3092 kauth_authorize_fileop(vfs_context_ucred(ctx
), KAUTH_FILEOP_SYMLINK
,
3093 (uintptr_t)path
, (uintptr_t)new_link_path
);
3094 if (new_link_path
!= NULL
)
3095 release_pathbuff(new_link_path
);
3098 // Make sure the name & parent pointers are hooked up
3099 if (vp
->v_name
== NULL
)
3100 update_flags
|= VNODE_UPDATE_NAME
;
3101 if (vp
->v_parent
== NULLVP
)
3102 update_flags
|= VNODE_UPDATE_PARENT
;
3105 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
3108 add_fsevent(FSE_CREATE_FILE
, ctx
,
3116 * nameidone has to happen before we vnode_put(dvp)
3117 * since it may need to release the fs_nodelock on the dvp
3125 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
3131 * Delete a whiteout from the filesystem.
3132 * XXX authorization not implmented for whiteouts
3135 undelete(__unused proc_t p
, struct undelete_args
*uap
, __unused
int32_t *retval
)
3138 struct nameidata nd
;
3139 vfs_context_t ctx
= vfs_context_current();
3142 NDINIT(&nd
, DELETE
, LOCKPARENT
|DOWHITEOUT
|AUDITVNPATH1
,
3143 UIO_USERSPACE
, uap
->path
, ctx
);
3150 if (vp
== NULLVP
&& (nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
3151 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, DELETE
, ctx
);
3156 * nameidone has to happen before we vnode_put(dvp)
3157 * since it may need to release the fs_nodelock on the dvp
3170 * Delete a name from the filesystem.
3174 unlink1(vfs_context_t ctx
, struct nameidata
*ndp
, int nodelbusy
)
3178 struct componentname
*cnp
;
3186 int has_listeners
= 0;
3187 int truncated_path
=0;
3189 /* unlink or delete is allowed on rsrc forks and named streams */
3190 ndp
->ni_cnd
.cn_flags
|= CN_ALLOWRSRCFORK
;
3193 ndp
->ni_cnd
.cn_flags
|= LOCKPARENT
;
3203 /* With Carbon delete semantics, busy files cannot be deleted */
3205 flags
|= VNODE_REMOVE_NODELETEBUSY
;
3209 * Normally, unlinking of directories is not supported.
3210 * However, some file systems may have limited support.
3212 if ((vp
->v_type
== VDIR
) &&
3213 !(vp
->v_mount
->mnt_vtable
->vfc_vfsflags
& VFC_VFSDIRLINKS
)) {
3214 error
= EPERM
; /* POSIX */
3218 * The root of a mounted filesystem cannot be deleted.
3220 if (vp
->v_flag
& VROOT
) {
3227 /* authorize the delete operation */
3230 error
= mac_vnode_check_unlink(ctx
,
3234 error
= vnode_authorize(vp
, ndp
->ni_dvp
, KAUTH_VNODE_DELETE
, ctx
);
3239 need_event
= need_fsevent(FSE_DELETE
, dvp
);
3241 if ((vp
->v_flag
& VISHARDLINK
) == 0) {
3242 get_fse_info(vp
, &finfo
, ctx
);
3246 has_listeners
= kauth_authorize_fileop_has_listeners();
3247 if (need_event
|| has_listeners
) {
3254 len
= safe_getpath(dvp
, ndp
->ni_cnd
.cn_nameptr
, path
, MAXPATHLEN
, &truncated_path
);
3258 if (ndp
->ni_cnd
.cn_flags
& CN_WANTSRSRCFORK
)
3259 error
= vnode_removenamedstream(dvp
, vp
, XATTR_RESOURCEFORK_NAME
, 0, ctx
);
3262 error
= VNOP_REMOVE(dvp
, vp
, &ndp
->ni_cnd
, flags
, ctx
);
3265 * Call out to allow 3rd party notification of delete.
3266 * Ignore result of kauth_authorize_fileop call.
3269 if (has_listeners
) {
3270 kauth_authorize_fileop(vfs_context_ucred(ctx
),
3271 KAUTH_FILEOP_DELETE
,
3276 if (vp
->v_flag
& VISHARDLINK
) {
3278 // if a hardlink gets deleted we want to blow away the
3279 // v_parent link because the path that got us to this
3280 // instance of the link is no longer valid. this will
3281 // force the next call to get the path to ask the file
3282 // system instead of just following the v_parent link.
3284 vnode_update_identity(vp
, NULL
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
3289 if (vp
->v_flag
& VISHARDLINK
) {
3290 get_fse_info(vp
, &finfo
, ctx
);
3292 if (truncated_path
) {
3293 finfo
.mode
|= FSE_TRUNCATED_PATH
;
3295 add_fsevent(FSE_DELETE
, ctx
,
3296 FSE_ARG_STRING
, len
, path
,
3297 FSE_ARG_FINFO
, &finfo
,
3306 * nameidone has to happen before we vnode_put(dvp)
3307 * since it may need to release the fs_nodelock on the dvp
3311 /* recycle the deleted rsrc fork vnode to force a reclaim, which
3312 * will cause its shadow file to go away if necessary.
3314 if ((vnode_isnamedstream(ndp
->ni_vp
)) &&
3315 (ndp
->ni_vp
->v_parent
!= NULLVP
) &&
3316 vnode_isshadow(ndp
->ni_vp
)) {
3317 vnode_recycle(ndp
->ni_vp
);
3327 * Delete a name from the filesystem using POSIX semantics.
3330 unlink(__unused proc_t p
, struct unlink_args
*uap
, __unused
int32_t *retval
)
3332 struct nameidata nd
;
3333 vfs_context_t ctx
= vfs_context_current();
3335 NDINIT(&nd
, DELETE
, AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, ctx
);
3336 return unlink1(ctx
, &nd
, 0);
3340 * Delete a name from the filesystem using Carbon semantics.
3343 delete(__unused proc_t p
, struct delete_args
*uap
, __unused
int32_t *retval
)
3345 struct nameidata nd
;
3346 vfs_context_t ctx
= vfs_context_current();
3348 NDINIT(&nd
, DELETE
, AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, ctx
);
3349 return unlink1(ctx
, &nd
, 1);
3353 * Reposition read/write file offset.
3356 lseek(proc_t p
, struct lseek_args
*uap
, off_t
*retval
)
3358 struct fileproc
*fp
;
3360 struct vfs_context
*ctx
;
3361 off_t offset
= uap
->offset
, file_size
;
3364 if ( (error
= fp_getfvp(p
,uap
->fd
, &fp
, &vp
)) ) {
3365 if (error
== ENOTSUP
)
3369 if (vnode_isfifo(vp
)) {
3375 ctx
= vfs_context_current();
3377 if (uap
->whence
== L_INCR
&& uap
->offset
== 0)
3378 error
= mac_file_check_get_offset(vfs_context_ucred(ctx
),
3381 error
= mac_file_check_change_offset(vfs_context_ucred(ctx
),
3388 if ( (error
= vnode_getwithref(vp
)) ) {
3393 switch (uap
->whence
) {
3395 offset
+= fp
->f_fglob
->fg_offset
;
3398 if ((error
= vnode_size(vp
, &file_size
, ctx
)) != 0)
3400 offset
+= file_size
;
3408 if (uap
->offset
> 0 && offset
< 0) {
3409 /* Incremented/relative move past max size */
3413 * Allow negative offsets on character devices, per
3414 * POSIX 1003.1-2001. Most likely for writing disk
3417 if (offset
< 0 && vp
->v_type
!= VCHR
) {
3418 /* Decremented/relative move before start */
3422 fp
->f_fglob
->fg_offset
= offset
;
3423 *retval
= fp
->f_fglob
->fg_offset
;
3429 * An lseek can affect whether data is "available to read." Use
3430 * hint of NOTE_NONE so no EVFILT_VNODE events fire
3432 post_event_if_success(vp
, error
, NOTE_NONE
);
3433 (void)vnode_put(vp
);
3440 * Check access permissions.
3442 * Returns: 0 Success
3443 * vnode_authorize:???
3446 access1(vnode_t vp
, vnode_t dvp
, int uflags
, vfs_context_t ctx
)
3448 kauth_action_t action
;
3452 * If just the regular access bits, convert them to something
3453 * that vnode_authorize will understand.
3455 if (!(uflags
& _ACCESS_EXTENDED_MASK
)) {
3458 action
|= KAUTH_VNODE_READ_DATA
; /* aka KAUTH_VNODE_LIST_DIRECTORY */
3459 if (uflags
& W_OK
) {
3460 if (vnode_isdir(vp
)) {
3461 action
|= KAUTH_VNODE_ADD_FILE
|
3462 KAUTH_VNODE_ADD_SUBDIRECTORY
;
3463 /* might want delete rights here too */
3465 action
|= KAUTH_VNODE_WRITE_DATA
;
3468 if (uflags
& X_OK
) {
3469 if (vnode_isdir(vp
)) {
3470 action
|= KAUTH_VNODE_SEARCH
;
3472 action
|= KAUTH_VNODE_EXECUTE
;
3476 /* take advantage of definition of uflags */
3477 action
= uflags
>> 8;
3481 error
= mac_vnode_check_access(ctx
, vp
, uflags
);
3486 /* action == 0 means only check for existence */
3488 error
= vnode_authorize(vp
, dvp
, action
| KAUTH_VNODE_ACCESS
, ctx
);
3499 * access_extended: Check access permissions in bulk.
3501 * Description: uap->entries Pointer to an array of accessx
3502 * descriptor structs, plus one or
3503 * more NULL terminated strings (see
3504 * "Notes" section below).
3505 * uap->size Size of the area pointed to by
3507 * uap->results Pointer to the results array.
3509 * Returns: 0 Success
3510 * ENOMEM Insufficient memory
3511 * EINVAL Invalid arguments
3512 * namei:EFAULT Bad address
3513 * namei:ENAMETOOLONG Filename too long
3514 * namei:ENOENT No such file or directory
3515 * namei:ELOOP Too many levels of symbolic links
3516 * namei:EBADF Bad file descriptor
3517 * namei:ENOTDIR Not a directory
3522 * uap->results Array contents modified
3524 * Notes: The uap->entries are structured as an arbitrary length array
3525 * of accessx descriptors, followed by one or more NULL terminated
3528 * struct accessx_descriptor[0]
3530 * struct accessx_descriptor[n]
3531 * char name_data[0];
3533 * We determine the entry count by walking the buffer containing
3534 * the uap->entries argument descriptor. For each descriptor we
3535 * see, the valid values for the offset ad_name_offset will be
3536 * in the byte range:
3538 * [ uap->entries + sizeof(struct accessx_descriptor) ]
3540 * [ uap->entries + uap->size - 2 ]
3542 * since we must have at least one string, and the string must
3543 * be at least one character plus the NULL terminator in length.
3545 * XXX: Need to support the check-as uid argument
3548 access_extended(__unused proc_t p
, struct access_extended_args
*uap
, __unused
int32_t *retval
)
3550 struct accessx_descriptor
*input
= NULL
;
3551 errno_t
*result
= NULL
;
3554 unsigned int desc_max
, desc_actual
, i
, j
;
3555 struct vfs_context context
;
3556 struct nameidata nd
;
3560 #define ACCESSX_MAX_DESCR_ON_STACK 10
3561 struct accessx_descriptor stack_input
[ACCESSX_MAX_DESCR_ON_STACK
];
3563 context
.vc_ucred
= NULL
;
3566 * Validate parameters; if valid, copy the descriptor array and string
3567 * arguments into local memory. Before proceeding, the following
3568 * conditions must have been met:
3570 * o The total size is not permitted to exceed ACCESSX_MAX_TABLESIZE
3571 * o There must be sufficient room in the request for at least one
3572 * descriptor and a one yte NUL terminated string.
3573 * o The allocation of local storage must not fail.
3575 if (uap
->size
> ACCESSX_MAX_TABLESIZE
)
3577 if (uap
->size
< (sizeof(struct accessx_descriptor
) + 2))
3579 if (uap
->size
<= sizeof (stack_input
)) {
3580 input
= stack_input
;
3582 MALLOC(input
, struct accessx_descriptor
*, uap
->size
, M_TEMP
, M_WAITOK
);
3583 if (input
== NULL
) {
3588 error
= copyin(uap
->entries
, input
, uap
->size
);
3592 AUDIT_ARG(opaque
, input
, uap
->size
);
3595 * Force NUL termination of the copyin buffer to avoid nami() running
3596 * off the end. If the caller passes us bogus data, they may get a
3599 ((char *)input
)[uap
->size
- 1] = 0;
3602 * Access is defined as checking against the process' real identity,
3603 * even if operations are checking the effective identity. This
3604 * requires that we use a local vfs context.
3606 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
3607 context
.vc_thread
= current_thread();
3610 * Find out how many entries we have, so we can allocate the result
3611 * array by walking the list and adjusting the count downward by the
3612 * earliest string offset we see.
3614 desc_max
= (uap
->size
- 2) / sizeof(struct accessx_descriptor
);
3615 desc_actual
= desc_max
;
3616 for (i
= 0; i
< desc_actual
; i
++) {
3618 * Take the offset to the name string for this entry and
3619 * convert to an input array index, which would be one off
3620 * the end of the array if this entry was the lowest-addressed
3623 j
= input
[i
].ad_name_offset
/ sizeof(struct accessx_descriptor
);
3626 * An offset greater than the max allowable offset is an error.
3627 * It is also an error for any valid entry to point
3628 * to a location prior to the end of the current entry, if
3629 * it's not a reference to the string of the previous entry.
3631 if (j
> desc_max
|| (j
!= 0 && j
<= i
)) {
3637 * An offset of 0 means use the previous descriptor's offset;
3638 * this is used to chain multiple requests for the same file
3639 * to avoid multiple lookups.
3642 /* This is not valid for the first entry */
3651 * If the offset of the string for this descriptor is before
3652 * what we believe is the current actual last descriptor,
3653 * then we need to adjust our estimate downward; this permits
3654 * the string table following the last descriptor to be out
3655 * of order relative to the descriptor list.
3657 if (j
< desc_actual
)
3662 * We limit the actual number of descriptors we are willing to process
3663 * to a hard maximum of ACCESSX_MAX_DESCRIPTORS. If the number being
3664 * requested does not exceed this limit,
3666 if (desc_actual
> ACCESSX_MAX_DESCRIPTORS
) {
3670 MALLOC(result
, errno_t
*, desc_actual
* sizeof(errno_t
), M_TEMP
, M_WAITOK
);
3671 if (result
== NULL
) {
3677 * Do the work by iterating over the descriptor entries we know to
3678 * at least appear to contain valid data.
3681 for (i
= 0; i
< desc_actual
; i
++) {
3683 * If the ad_name_offset is 0, then we use the previous
3684 * results to make the check; otherwise, we are looking up
3687 if (input
[i
].ad_name_offset
!= 0) {
3688 /* discard old vnodes */
3699 * Scan forward in the descriptor list to see if we
3700 * need the parent vnode. We will need it if we are
3701 * deleting, since we must have rights to remove
3702 * entries in the parent directory, as well as the
3703 * rights to delete the object itself.
3705 wantdelete
= input
[i
].ad_flags
& _DELETE_OK
;
3706 for (j
= i
+ 1; (j
< desc_actual
) && (input
[j
].ad_name_offset
== 0); j
++)
3707 if (input
[j
].ad_flags
& _DELETE_OK
)
3710 niopts
= FOLLOW
| AUDITVNPATH1
;
3712 /* need parent for vnode_authorize for deletion test */
3714 niopts
|= WANTPARENT
;
3717 NDINIT(&nd
, LOOKUP
, niopts
, UIO_SYSSPACE
, CAST_USER_ADDR_T(((const char *)input
) + input
[i
].ad_name_offset
), &context
);
3728 * Handle lookup errors.
3738 /* run this access check */
3739 result
[i
] = access1(vp
, dvp
, input
[i
].ad_flags
, &context
);
3742 /* fatal lookup error */
3748 AUDIT_ARG(data
, result
, sizeof(errno_t
), desc_actual
);
3750 /* copy out results */
3751 error
= copyout(result
, uap
->results
, desc_actual
* sizeof(errno_t
));
3754 if (input
&& input
!= stack_input
)
3755 FREE(input
, M_TEMP
);
3757 FREE(result
, M_TEMP
);
3762 if (IS_VALID_CRED(context
.vc_ucred
))
3763 kauth_cred_unref(&context
.vc_ucred
);
3769 * Returns: 0 Success
3770 * namei:EFAULT Bad address
3771 * namei:ENAMETOOLONG Filename too long
3772 * namei:ENOENT No such file or directory
3773 * namei:ELOOP Too many levels of symbolic links
3774 * namei:EBADF Bad file descriptor
3775 * namei:ENOTDIR Not a directory
3780 access(__unused proc_t p
, struct access_args
*uap
, __unused
int32_t *retval
)
3783 struct nameidata nd
;
3785 struct vfs_context context
;
3787 int is_namedstream
= 0;
3791 * Access is defined as checking against the process'
3792 * real identity, even if operations are checking the
3793 * effective identity. So we need to tweak the credential
3796 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
3797 context
.vc_thread
= current_thread();
3799 niopts
= FOLLOW
| AUDITVNPATH1
;
3800 /* need parent for vnode_authorize for deletion test */
3801 if (uap
->flags
& _DELETE_OK
)
3802 niopts
|= WANTPARENT
;
3803 NDINIT(&nd
, LOOKUP
, niopts
, UIO_USERSPACE
, uap
->path
, &context
);
3806 /* access(F_OK) calls are allowed for resource forks. */
3807 if (uap
->flags
== F_OK
)
3808 nd
.ni_cnd
.cn_flags
|= CN_ALLOWRSRCFORK
;
3815 /* Grab reference on the shadow stream file vnode to
3816 * force an inactive on release which will mark it
3819 if (vnode_isnamedstream(nd
.ni_vp
) &&
3820 (nd
.ni_vp
->v_parent
!= NULLVP
) &&
3821 vnode_isshadow(nd
.ni_vp
)) {
3823 vnode_ref(nd
.ni_vp
);
3827 error
= access1(nd
.ni_vp
, nd
.ni_dvp
, uap
->flags
, &context
);
3830 if (is_namedstream
) {
3831 vnode_rele(nd
.ni_vp
);
3835 vnode_put(nd
.ni_vp
);
3836 if (uap
->flags
& _DELETE_OK
)
3837 vnode_put(nd
.ni_dvp
);
3841 kauth_cred_unref(&context
.vc_ucred
);
3847 * Returns: 0 Success
3854 stat2(vfs_context_t ctx
, struct nameidata
*ndp
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
, int isstat64
)
3861 struct user64_stat user64_sb
;
3862 struct user32_stat user32_sb
;
3863 struct user64_stat64 user64_sb64
;
3864 struct user32_stat64 user32_sb64
;
3868 kauth_filesec_t fsec
;
3869 size_t xsecurity_bufsize
;
3873 int is_namedstream
= 0;
3874 /* stat calls are allowed for resource forks. */
3875 ndp
->ni_cnd
.cn_flags
|= CN_ALLOWRSRCFORK
;
3880 fsec
= KAUTH_FILESEC_NONE
;
3882 statptr
= (void *)&source
;
3885 /* Grab reference on the shadow stream file vnode to
3886 * force an inactive on release which will mark it
3889 if (vnode_isnamedstream(ndp
->ni_vp
) &&
3890 (ndp
->ni_vp
->v_parent
!= NULLVP
) &&
3891 vnode_isshadow(ndp
->ni_vp
)) {
3893 vnode_ref(ndp
->ni_vp
);
3897 error
= vn_stat(ndp
->ni_vp
, statptr
, (xsecurity
!= USER_ADDR_NULL
? &fsec
: NULL
), isstat64
, ctx
);
3900 if (is_namedstream
) {
3901 vnode_rele(ndp
->ni_vp
);
3904 vnode_put(ndp
->ni_vp
);
3909 /* Zap spare fields */
3910 if (isstat64
!= 0) {
3911 source
.sb64
.st_lspare
= 0;
3912 source
.sb64
.st_qspare
[0] = 0LL;
3913 source
.sb64
.st_qspare
[1] = 0LL;
3914 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
3915 munge_user64_stat64(&source
.sb64
, &dest
.user64_sb64
);
3916 my_size
= sizeof(dest
.user64_sb64
);
3917 sbp
= (caddr_t
)&dest
.user64_sb64
;
3919 munge_user32_stat64(&source
.sb64
, &dest
.user32_sb64
);
3920 my_size
= sizeof(dest
.user32_sb64
);
3921 sbp
= (caddr_t
)&dest
.user32_sb64
;
3924 * Check if we raced (post lookup) against the last unlink of a file.
3926 if ((source
.sb64
.st_nlink
== 0) && S_ISREG(source
.sb64
.st_mode
)) {
3927 source
.sb64
.st_nlink
= 1;
3930 source
.sb
.st_lspare
= 0;
3931 source
.sb
.st_qspare
[0] = 0LL;
3932 source
.sb
.st_qspare
[1] = 0LL;
3933 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
3934 munge_user64_stat(&source
.sb
, &dest
.user64_sb
);
3935 my_size
= sizeof(dest
.user64_sb
);
3936 sbp
= (caddr_t
)&dest
.user64_sb
;
3938 munge_user32_stat(&source
.sb
, &dest
.user32_sb
);
3939 my_size
= sizeof(dest
.user32_sb
);
3940 sbp
= (caddr_t
)&dest
.user32_sb
;
3944 * Check if we raced (post lookup) against the last unlink of a file.
3946 if ((source
.sb
.st_nlink
== 0) && S_ISREG(source
.sb
.st_mode
)) {
3947 source
.sb
.st_nlink
= 1;
3950 if ((error
= copyout(sbp
, ub
, my_size
)) != 0)
3953 /* caller wants extended security information? */
3954 if (xsecurity
!= USER_ADDR_NULL
) {
3956 /* did we get any? */
3957 if (fsec
== KAUTH_FILESEC_NONE
) {
3958 if (susize(xsecurity_size
, 0) != 0) {
3963 /* find the user buffer size */
3964 xsecurity_bufsize
= fusize(xsecurity_size
);
3966 /* copy out the actual data size */
3967 if (susize(xsecurity_size
, KAUTH_FILESEC_COPYSIZE(fsec
)) != 0) {
3972 /* if the caller supplied enough room, copy out to it */
3973 if (xsecurity_bufsize
>= KAUTH_FILESEC_COPYSIZE(fsec
))
3974 error
= copyout(fsec
, xsecurity
, KAUTH_FILESEC_COPYSIZE(fsec
));
3978 if (fsec
!= KAUTH_FILESEC_NONE
)
3979 kauth_filesec_free(fsec
);
3984 * Get file status; this version follows links.
3986 * Returns: 0 Success
3987 * stat2:??? [see stat2() in this file]
3990 stat1(user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
, int isstat64
)
3992 struct nameidata nd
;
3993 vfs_context_t ctx
= vfs_context_current();
3995 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
3996 UIO_USERSPACE
, path
, ctx
);
3997 return(stat2(ctx
, &nd
, ub
, xsecurity
, xsecurity_size
, isstat64
));
4001 * stat_extended: Get file status; with extended security (ACL).
4003 * Parameters: p (ignored)
4004 * uap User argument descriptor (see below)
4007 * Indirect: uap->path Path of file to get status from
4008 * uap->ub User buffer (holds file status info)
4009 * uap->xsecurity ACL to get (extended security)
4010 * uap->xsecurity_size Size of ACL
4012 * Returns: 0 Success
4017 stat_extended(__unused proc_t p
, struct stat_extended_args
*uap
, __unused
int32_t *retval
)
4019 return (stat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 0));
4023 * Returns: 0 Success
4024 * stat1:??? [see stat1() in this file]
4027 stat(__unused proc_t p
, struct stat_args
*uap
, __unused
int32_t *retval
)
4029 return(stat1(uap
->path
, uap
->ub
, 0, 0, 0));
4033 stat64(__unused proc_t p
, struct stat64_args
*uap
, __unused
int32_t *retval
)
4035 return(stat1(uap
->path
, uap
->ub
, 0, 0, 1));
4039 * stat64_extended: Get file status; can handle large inode numbers; with extended security (ACL).
4041 * Parameters: p (ignored)
4042 * uap User argument descriptor (see below)
4045 * Indirect: uap->path Path of file to get status from
4046 * uap->ub User buffer (holds file status info)
4047 * uap->xsecurity ACL to get (extended security)
4048 * uap->xsecurity_size Size of ACL
4050 * Returns: 0 Success
4055 stat64_extended(__unused proc_t p
, struct stat64_extended_args
*uap
, __unused
int32_t *retval
)
4057 return (stat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 1));
4060 * Get file status; this version does not follow links.
4063 lstat1(user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
, int isstat64
)
4065 struct nameidata nd
;
4066 vfs_context_t ctx
= vfs_context_current();
4068 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| NOFOLLOW
| AUDITVNPATH1
,
4069 UIO_USERSPACE
, path
, ctx
);
4071 return(stat2(ctx
, &nd
, ub
, xsecurity
, xsecurity_size
, isstat64
));
4075 * lstat_extended: Get file status; does not follow links; with extended security (ACL).
4077 * Parameters: p (ignored)
4078 * uap User argument descriptor (see below)
4081 * Indirect: uap->path Path of file to get status from
4082 * uap->ub User buffer (holds file status info)
4083 * uap->xsecurity ACL to get (extended security)
4084 * uap->xsecurity_size Size of ACL
4086 * Returns: 0 Success
4091 lstat_extended(__unused proc_t p
, struct lstat_extended_args
*uap
, __unused
int32_t *retval
)
4093 return (lstat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 0));
4097 lstat(__unused proc_t p
, struct lstat_args
*uap
, __unused
int32_t *retval
)
4099 return(lstat1(uap
->path
, uap
->ub
, 0, 0, 0));
4103 lstat64(__unused proc_t p
, struct lstat64_args
*uap
, __unused
int32_t *retval
)
4105 return(lstat1(uap
->path
, uap
->ub
, 0, 0, 1));
4109 * lstat64_extended: Get file status; can handle large inode numbers; does not
4110 * follow links; with extended security (ACL).
4112 * Parameters: p (ignored)
4113 * uap User argument descriptor (see below)
4116 * Indirect: uap->path Path of file to get status from
4117 * uap->ub User buffer (holds file status info)
4118 * uap->xsecurity ACL to get (extended security)
4119 * uap->xsecurity_size Size of ACL
4121 * Returns: 0 Success
4126 lstat64_extended(__unused proc_t p
, struct lstat64_extended_args
*uap
, __unused
int32_t *retval
)
4128 return (lstat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 1));
4132 * Get configurable pathname variables.
4134 * Returns: 0 Success
4138 * Notes: Global implementation constants are intended to be
4139 * implemented in this function directly; all other constants
4140 * are per-FS implementation, and therefore must be handled in
4141 * each respective FS, instead.
4143 * XXX We implement some things globally right now that should actually be
4144 * XXX per-FS; we will need to deal with this at some point.
4148 pathconf(__unused proc_t p
, struct pathconf_args
*uap
, int32_t *retval
)
4151 struct nameidata nd
;
4152 vfs_context_t ctx
= vfs_context_current();
4154 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4155 UIO_USERSPACE
, uap
->path
, ctx
);
4160 error
= vn_pathconf(nd
.ni_vp
, uap
->name
, retval
, ctx
);
4162 vnode_put(nd
.ni_vp
);
4168 * Return target name of a symbolic link.
4172 readlink(proc_t p
, struct readlink_args
*uap
, int32_t *retval
)
4176 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4178 struct nameidata nd
;
4179 vfs_context_t ctx
= vfs_context_current();
4180 char uio_buf
[ UIO_SIZEOF(1) ];
4182 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
4183 UIO_USERSPACE
, uap
->path
, ctx
);
4191 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
4192 &uio_buf
[0], sizeof(uio_buf
));
4193 uio_addiov(auio
, uap
->buf
, uap
->count
);
4194 if (vp
->v_type
!= VLNK
)
4198 error
= mac_vnode_check_readlink(ctx
,
4202 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, ctx
);
4204 error
= VNOP_READLINK(vp
, auio
, ctx
);
4208 /* Safe: uio_resid() is bounded above by "count", and "count" is an int */
4209 *retval
= uap
->count
- (int)uio_resid(auio
);
4214 * Change file flags.
4217 chflags1(vnode_t vp
, int flags
, vfs_context_t ctx
)
4219 struct vnode_attr va
;
4220 kauth_action_t action
;
4224 VATTR_SET(&va
, va_flags
, flags
);
4227 error
= mac_vnode_check_setflags(ctx
, vp
, flags
);
4232 /* request authorisation, disregard immutability */
4233 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
4236 * Request that the auth layer disregard those file flags it's allowed to when
4237 * authorizing this operation; we need to do this in order to be able to
4238 * clear immutable flags.
4240 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
| KAUTH_VNODE_NOIMMUTABLE
, ctx
)) != 0))
4242 error
= vnode_setattr(vp
, &va
, ctx
);
4244 if ((error
== 0) && !VATTR_IS_SUPPORTED(&va
, va_flags
)) {
4253 * Change flags of a file given a path name.
4257 chflags(__unused proc_t p
, struct chflags_args
*uap
, __unused
int32_t *retval
)
4260 vfs_context_t ctx
= vfs_context_current();
4262 struct nameidata nd
;
4264 AUDIT_ARG(fflags
, uap
->flags
);
4265 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4266 UIO_USERSPACE
, uap
->path
, ctx
);
4273 error
= chflags1(vp
, uap
->flags
, ctx
);
4279 * Change flags of a file given a file descriptor.
4283 fchflags(__unused proc_t p
, struct fchflags_args
*uap
, __unused
int32_t *retval
)
4288 AUDIT_ARG(fd
, uap
->fd
);
4289 AUDIT_ARG(fflags
, uap
->flags
);
4290 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
4293 if ((error
= vnode_getwithref(vp
))) {
4298 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4300 error
= chflags1(vp
, uap
->flags
, vfs_context_current());
4307 * Change security information on a filesystem object.
4309 * Returns: 0 Success
4310 * EPERM Operation not permitted
4311 * vnode_authattr:??? [anything vnode_authattr can return]
4312 * vnode_authorize:??? [anything vnode_authorize can return]
4313 * vnode_setattr:??? [anything vnode_setattr can return]
4315 * Notes: If vnode_authattr or vnode_authorize return EACCES, it will be
4316 * translated to EPERM before being returned.
4319 chmod2(vfs_context_t ctx
, vnode_t vp
, struct vnode_attr
*vap
)
4321 kauth_action_t action
;
4324 AUDIT_ARG(mode
, vap
->va_mode
);
4325 /* XXX audit new args */
4328 /* chmod calls are not allowed for resource forks. */
4329 if (vp
->v_flag
& VISNAMEDSTREAM
) {
4335 error
= mac_vnode_check_setmode(ctx
, vp
, (mode_t
)vap
->va_mode
);
4340 /* make sure that the caller is allowed to set this security information */
4341 if (((error
= vnode_authattr(vp
, vap
, &action
, ctx
)) != 0) ||
4342 ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
4343 if (error
== EACCES
)
4348 error
= vnode_setattr(vp
, vap
, ctx
);
4355 * Change mode of a file given a path name.
4357 * Returns: 0 Success
4358 * namei:??? [anything namei can return]
4359 * chmod2:??? [anything chmod2 can return]
4362 chmod1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
4364 struct nameidata nd
;
4367 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4368 UIO_USERSPACE
, path
, ctx
);
4369 if ((error
= namei(&nd
)))
4371 error
= chmod2(ctx
, nd
.ni_vp
, vap
);
4372 vnode_put(nd
.ni_vp
);
4378 * chmod_extended: Change the mode of a file given a path name; with extended
4379 * argument list (including extended security (ACL)).
4381 * Parameters: p Process requesting the open
4382 * uap User argument descriptor (see below)
4385 * Indirect: uap->path Path to object (same as 'chmod')
4386 * uap->uid UID to set
4387 * uap->gid GID to set
4388 * uap->mode File mode to set (same as 'chmod')
4389 * uap->xsecurity ACL to set (or delete)
4391 * Returns: 0 Success
4394 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
4396 * XXX: We should enummerate the possible errno values here, and where
4397 * in the code they originated.
4400 chmod_extended(__unused proc_t p
, struct chmod_extended_args
*uap
, __unused
int32_t *retval
)
4403 struct vnode_attr va
;
4404 kauth_filesec_t xsecdst
;
4406 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
4409 if (uap
->mode
!= -1)
4410 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
4411 if (uap
->uid
!= KAUTH_UID_NONE
)
4412 VATTR_SET(&va
, va_uid
, uap
->uid
);
4413 if (uap
->gid
!= KAUTH_GID_NONE
)
4414 VATTR_SET(&va
, va_gid
, uap
->gid
);
4417 switch(uap
->xsecurity
) {
4418 /* explicit remove request */
4419 case CAST_USER_ADDR_T((void *)1): /* _FILESEC_REMOVE_ACL */
4420 VATTR_SET(&va
, va_acl
, NULL
);
4423 case USER_ADDR_NULL
:
4426 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
4428 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
4429 KAUTH_DEBUG("CHMOD - setting ACL with %d entries", va
.va_acl
->acl_entrycount
);
4432 error
= chmod1(vfs_context_current(), uap
->path
, &va
);
4434 if (xsecdst
!= NULL
)
4435 kauth_filesec_free(xsecdst
);
4440 * Returns: 0 Success
4441 * chmod1:??? [anything chmod1 can return]
4444 chmod(__unused proc_t p
, struct chmod_args
*uap
, __unused
int32_t *retval
)
4446 struct vnode_attr va
;
4449 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
4451 return(chmod1(vfs_context_current(), uap
->path
, &va
));
4455 * Change mode of a file given a file descriptor.
4458 fchmod1(__unused proc_t p
, int fd
, struct vnode_attr
*vap
)
4465 if ((error
= file_vnode(fd
, &vp
)) != 0)
4467 if ((error
= vnode_getwithref(vp
)) != 0) {
4471 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4473 error
= chmod2(vfs_context_current(), vp
, vap
);
4474 (void)vnode_put(vp
);
4481 * fchmod_extended: Change mode of a file given a file descriptor; with
4482 * extended argument list (including extended security (ACL)).
4484 * Parameters: p Process requesting to change file mode
4485 * uap User argument descriptor (see below)
4488 * Indirect: uap->mode File mode to set (same as 'chmod')
4489 * uap->uid UID to set
4490 * uap->gid GID to set
4491 * uap->xsecurity ACL to set (or delete)
4492 * uap->fd File descriptor of file to change mode
4494 * Returns: 0 Success
4499 fchmod_extended(proc_t p
, struct fchmod_extended_args
*uap
, __unused
int32_t *retval
)
4502 struct vnode_attr va
;
4503 kauth_filesec_t xsecdst
;
4505 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
4508 if (uap
->mode
!= -1)
4509 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
4510 if (uap
->uid
!= KAUTH_UID_NONE
)
4511 VATTR_SET(&va
, va_uid
, uap
->uid
);
4512 if (uap
->gid
!= KAUTH_GID_NONE
)
4513 VATTR_SET(&va
, va_gid
, uap
->gid
);
4516 switch(uap
->xsecurity
) {
4517 case USER_ADDR_NULL
:
4518 VATTR_SET(&va
, va_acl
, NULL
);
4520 case CAST_USER_ADDR_T(-1):
4523 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
4525 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
4528 error
= fchmod1(p
, uap
->fd
, &va
);
4531 switch(uap
->xsecurity
) {
4532 case USER_ADDR_NULL
:
4533 case CAST_USER_ADDR_T(-1):
4536 if (xsecdst
!= NULL
)
4537 kauth_filesec_free(xsecdst
);
4543 fchmod(proc_t p
, struct fchmod_args
*uap
, __unused
int32_t *retval
)
4545 struct vnode_attr va
;
4548 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
4550 return(fchmod1(p
, uap
->fd
, &va
));
4555 * Set ownership given a path name.
4559 chown1(vfs_context_t ctx
, struct chown_args
*uap
, __unused
int32_t *retval
, int follow
)
4562 struct vnode_attr va
;
4564 struct nameidata nd
;
4565 kauth_action_t action
;
4567 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
4569 NDINIT(&nd
, LOOKUP
, (follow
? FOLLOW
: 0) | NOTRIGGER
| AUDITVNPATH1
,
4570 UIO_USERSPACE
, uap
->path
, ctx
);
4579 if (uap
->uid
!= VNOVAL
)
4580 VATTR_SET(&va
, va_uid
, uap
->uid
);
4581 if (uap
->gid
!= VNOVAL
)
4582 VATTR_SET(&va
, va_gid
, uap
->gid
);
4585 error
= mac_vnode_check_setowner(ctx
, vp
, uap
->uid
, uap
->gid
);
4590 /* preflight and authorize attribute changes */
4591 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
4593 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
4595 error
= vnode_setattr(vp
, &va
, ctx
);
4599 * EACCES is only allowed from namei(); permissions failure should
4600 * return EPERM, so we need to translate the error code.
4602 if (error
== EACCES
)
4610 chown(__unused proc_t p
, struct chown_args
*uap
, int32_t *retval
)
4612 return chown1(vfs_context_current(), uap
, retval
, 1);
4616 lchown(__unused proc_t p
, struct lchown_args
*uap
, int32_t *retval
)
4618 /* Argument list identical, but machine generated; cast for chown1() */
4619 return chown1(vfs_context_current(), (struct chown_args
*)uap
, retval
, 0);
4623 * Set ownership given a file descriptor.
4627 fchown(__unused proc_t p
, struct fchown_args
*uap
, __unused
int32_t *retval
)
4629 struct vnode_attr va
;
4630 vfs_context_t ctx
= vfs_context_current();
4633 kauth_action_t action
;
4635 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
4636 AUDIT_ARG(fd
, uap
->fd
);
4638 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
4641 if ( (error
= vnode_getwithref(vp
)) ) {
4645 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4648 if (uap
->uid
!= VNOVAL
)
4649 VATTR_SET(&va
, va_uid
, uap
->uid
);
4650 if (uap
->gid
!= VNOVAL
)
4651 VATTR_SET(&va
, va_gid
, uap
->gid
);
4654 /* chown calls are not allowed for resource forks. */
4655 if (vp
->v_flag
& VISNAMEDSTREAM
) {
4662 error
= mac_vnode_check_setowner(ctx
, vp
, uap
->uid
, uap
->gid
);
4667 /* preflight and authorize attribute changes */
4668 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
4670 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
4671 if (error
== EACCES
)
4675 error
= vnode_setattr(vp
, &va
, ctx
);
4678 (void)vnode_put(vp
);
4684 getutimes(user_addr_t usrtvp
, struct timespec
*tsp
)
4688 if (usrtvp
== USER_ADDR_NULL
) {
4689 struct timeval old_tv
;
4690 /* XXX Y2038 bug because of microtime argument */
4692 TIMEVAL_TO_TIMESPEC(&old_tv
, &tsp
[0]);
4695 if (IS_64BIT_PROCESS(current_proc())) {
4696 struct user64_timeval tv
[2];
4697 error
= copyin(usrtvp
, (void *)tv
, sizeof(tv
));
4700 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
4701 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
4703 struct user32_timeval tv
[2];
4704 error
= copyin(usrtvp
, (void *)tv
, sizeof(tv
));
4707 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
4708 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
4715 setutimes(vfs_context_t ctx
, vnode_t vp
, const struct timespec
*ts
,
4719 struct vnode_attr va
;
4720 kauth_action_t action
;
4722 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4725 VATTR_SET(&va
, va_access_time
, ts
[0]);
4726 VATTR_SET(&va
, va_modify_time
, ts
[1]);
4728 va
.va_vaflags
|= VA_UTIMES_NULL
;
4731 /* utimes calls are not allowed for resource forks. */
4732 if (vp
->v_flag
& VISNAMEDSTREAM
) {
4739 error
= mac_vnode_check_setutimes(ctx
, vp
, ts
[0], ts
[1]);
4743 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0) {
4744 if (!nullflag
&& error
== EACCES
)
4749 /* since we may not need to auth anything, check here */
4750 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
4751 if (!nullflag
&& error
== EACCES
)
4755 error
= vnode_setattr(vp
, &va
, ctx
);
4762 * Set the access and modification times of a file.
4766 utimes(__unused proc_t p
, struct utimes_args
*uap
, __unused
int32_t *retval
)
4768 struct timespec ts
[2];
4771 struct nameidata nd
;
4772 vfs_context_t ctx
= vfs_context_current();
4775 * AUDIT: Needed to change the order of operations to do the
4776 * name lookup first because auditing wants the path.
4778 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4779 UIO_USERSPACE
, uap
->path
, ctx
);
4786 * Fetch the user-supplied time. If usrtvp is USER_ADDR_NULL, we fetch
4787 * the current time instead.
4790 if ((error
= getutimes(usrtvp
, ts
)) != 0)
4793 error
= setutimes(ctx
, nd
.ni_vp
, ts
, usrtvp
== USER_ADDR_NULL
);
4796 vnode_put(nd
.ni_vp
);
4801 * Set the access and modification times of a file.
4805 futimes(__unused proc_t p
, struct futimes_args
*uap
, __unused
int32_t *retval
)
4807 struct timespec ts
[2];
4812 AUDIT_ARG(fd
, uap
->fd
);
4814 if ((error
= getutimes(usrtvp
, ts
)) != 0)
4816 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
4818 if((error
= vnode_getwithref(vp
))) {
4823 error
= setutimes(vfs_context_current(), vp
, ts
, usrtvp
== 0);
4830 * Truncate a file given its path name.
4834 truncate(__unused proc_t p
, struct truncate_args
*uap
, __unused
int32_t *retval
)
4837 struct vnode_attr va
;
4838 vfs_context_t ctx
= vfs_context_current();
4840 struct nameidata nd
;
4841 kauth_action_t action
;
4843 if (uap
->length
< 0)
4845 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4846 UIO_USERSPACE
, uap
->path
, ctx
);
4847 if ((error
= namei(&nd
)))
4854 VATTR_SET(&va
, va_data_size
, uap
->length
);
4857 error
= mac_vnode_check_truncate(ctx
, NOCRED
, vp
);
4862 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
4864 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
4866 error
= vnode_setattr(vp
, &va
, ctx
);
4873 * Truncate a file given a file descriptor.
4877 ftruncate(proc_t p
, struct ftruncate_args
*uap
, int32_t *retval
)
4879 vfs_context_t ctx
= vfs_context_current();
4880 struct vnode_attr va
;
4882 struct fileproc
*fp
;
4886 AUDIT_ARG(fd
, uap
->fd
);
4887 if (uap
->length
< 0)
4890 if ( (error
= fp_lookup(p
,fd
,&fp
,0)) ) {
4894 if (fp
->f_fglob
->fg_type
== DTYPE_PSXSHM
) {
4895 error
= pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
);
4898 if (fp
->f_fglob
->fg_type
!= DTYPE_VNODE
) {
4903 vp
= (vnode_t
)fp
->f_fglob
->fg_data
;
4905 if ((fp
->f_fglob
->fg_flag
& FWRITE
) == 0) {
4906 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4911 if ((error
= vnode_getwithref(vp
)) != 0) {
4915 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4918 error
= mac_vnode_check_truncate(ctx
,
4919 fp
->f_fglob
->fg_cred
, vp
);
4921 (void)vnode_put(vp
);
4926 VATTR_SET(&va
, va_data_size
, uap
->length
);
4927 error
= vnode_setattr(vp
, &va
, ctx
);
4928 (void)vnode_put(vp
);
4936 * Sync an open file with synchronized I/O _file_ integrity completion
4940 fsync(proc_t p
, struct fsync_args
*uap
, __unused
int32_t *retval
)
4942 __pthread_testcancel(1);
4943 return(fsync_common(p
, uap
, MNT_WAIT
));
4948 * Sync an open file with synchronized I/O _file_ integrity completion
4950 * Notes: This is a legacy support function that does not test for
4951 * thread cancellation points.
4955 fsync_nocancel(proc_t p
, struct fsync_nocancel_args
*uap
, __unused
int32_t *retval
)
4957 return(fsync_common(p
, (struct fsync_args
*)uap
, MNT_WAIT
));
4962 * Sync an open file with synchronized I/O _data_ integrity completion
4966 fdatasync(proc_t p
, struct fdatasync_args
*uap
, __unused
int32_t *retval
)
4968 __pthread_testcancel(1);
4969 return(fsync_common(p
, (struct fsync_args
*)uap
, MNT_DWAIT
));
4976 * Common fsync code to support both synchronized I/O file integrity completion
4977 * (normal fsync) and synchronized I/O data integrity completion (fdatasync).
4979 * If 'flags' is MNT_DWAIT, the caller is requesting data integrity, which
4980 * will only guarantee that the file data contents are retrievable. If
4981 * 'flags' is MNT_WAIT, the caller is rewuesting file integrity, which also
4982 * includes additional metadata unnecessary for retrieving the file data
4983 * contents, such as atime, mtime, ctime, etc., also be committed to stable
4986 * Parameters: p The process
4987 * uap->fd The descriptor to synchronize
4988 * flags The data integrity flags
4990 * Returns: int Success
4991 * fp_getfvp:EBADF Bad file descriptor
4992 * fp_getfvp:ENOTSUP fd does not refer to a vnode
4993 * VNOP_FSYNC:??? unspecified
4995 * Notes: We use struct fsync_args because it is a short name, and all
4996 * caller argument structures are otherwise identical.
4999 fsync_common(proc_t p
, struct fsync_args
*uap
, int flags
)
5002 struct fileproc
*fp
;
5003 vfs_context_t ctx
= vfs_context_current();
5006 AUDIT_ARG(fd
, uap
->fd
);
5008 if ( (error
= fp_getfvp(p
, uap
->fd
, &fp
, &vp
)) )
5010 if ( (error
= vnode_getwithref(vp
)) ) {
5015 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
5017 error
= VNOP_FSYNC(vp
, flags
, ctx
);
5020 /* Sync resource fork shadow file if necessary. */
5022 (vp
->v_flag
& VISNAMEDSTREAM
) &&
5023 (vp
->v_parent
!= NULLVP
) &&
5024 vnode_isshadow(vp
) &&
5025 (fp
->f_flags
& FP_WRITTEN
)) {
5026 (void) vnode_flushnamedstream(vp
->v_parent
, vp
, ctx
);
5030 (void)vnode_put(vp
);
5036 * Duplicate files. Source must be a file, target must be a file or
5039 * XXX Copyfile authorisation checking is woefully inadequate, and will not
5040 * perform inheritance correctly.
5044 copyfile(__unused proc_t p
, struct copyfile_args
*uap
, __unused
int32_t *retval
)
5046 vnode_t tvp
, fvp
, tdvp
, sdvp
;
5047 struct nameidata fromnd
, tond
;
5049 vfs_context_t ctx
= vfs_context_current();
5051 /* Check that the flags are valid. */
5053 if (uap
->flags
& ~CPF_MASK
) {
5057 NDINIT(&fromnd
, LOOKUP
, SAVESTART
| AUDITVNPATH1
,
5058 UIO_USERSPACE
, uap
->from
, ctx
);
5059 if ((error
= namei(&fromnd
)))
5063 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
| AUDITVNPATH2
| CN_NBMOUNTLOOK
,
5064 UIO_USERSPACE
, uap
->to
, ctx
);
5065 if ((error
= namei(&tond
))) {
5072 if (!(uap
->flags
& CPF_OVERWRITE
)) {
5077 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
5082 if ((error
= vnode_authorize(tdvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
5088 * If source is the same as the destination (that is the
5089 * same inode number) then there is nothing to do.
5090 * (fixed to have POSIX semantics - CSM 3/2/98)
5095 error
= VNOP_COPYFILE(fvp
, tdvp
, tvp
, &tond
.ni_cnd
, uap
->mode
, uap
->flags
, ctx
);
5097 sdvp
= tond
.ni_startdir
;
5099 * nameidone has to happen before we vnode_put(tdvp)
5100 * since it may need to release the fs_nodelock on the tdvp
5111 if (fromnd
.ni_startdir
)
5112 vnode_put(fromnd
.ni_startdir
);
5122 * Rename files. Source and destination must either both be directories,
5123 * or both not be directories. If target is a directory, it must be empty.
5127 rename(__unused proc_t p
, struct rename_args
*uap
, __unused
int32_t *retval
)
5131 struct nameidata fromnd
, tond
;
5132 vfs_context_t ctx
= vfs_context_current();
5138 char *from_name
= NULL
, *to_name
= NULL
;
5139 int from_len
=0, to_len
=0;
5140 int holding_mntlock
;
5141 mount_t locked_mp
= NULL
;
5144 fse_info from_finfo
, to_finfo
;
5146 int from_truncated
=0, to_truncated
;
5148 holding_mntlock
= 0;
5155 NDINIT(&fromnd
, DELETE
, WANTPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->from
, ctx
);
5157 if ( (error
= namei(&fromnd
)) )
5159 fdvp
= fromnd
.ni_dvp
;
5163 error
= mac_vnode_check_rename_from(ctx
, fdvp
, fvp
, &fromnd
.ni_cnd
);
5168 NDINIT(&tond
, RENAME
, WANTPARENT
| AUDITVNPATH2
| CN_NBMOUNTLOOK
, UIO_USERSPACE
, uap
->to
, ctx
);
5169 if (fvp
->v_type
== VDIR
)
5170 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
5172 if ( (error
= namei(&tond
)) ) {
5174 * Translate error code for rename("dir1", "dir2/.").
5176 if (error
== EISDIR
&& fvp
->v_type
== VDIR
)
5184 error
= mac_vnode_check_rename_to(ctx
,
5185 tdvp
, tvp
, fdvp
== tdvp
, &tond
.ni_cnd
);
5191 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
5194 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
5204 * If the source and destination are the same (i.e. they're
5205 * links to the same vnode) and the target file system is
5206 * case sensitive, then there is nothing to do.
5212 * Note: if _PC_CASE_SENSITIVE selector isn't supported,
5213 * then assume that this file system is case sensitive.
5215 if (VNOP_PATHCONF(fvp
, _PC_CASE_SENSITIVE
, &pathconf_val
, ctx
) != 0 ||
5216 pathconf_val
!= 0) {
5224 * If tvp is a directory and not the same as fdvp, or tdvp is not
5225 * the same as fdvp, the node is moving between directories and we
5226 * need rights to remove from the old and add to the new.
5228 * If tvp already exists and is not a directory, we need to be
5229 * allowed to delete it.
5231 * Note that we do not inherit when renaming.
5233 * XXX This needs to be revisited to implement the deferred-inherit bit
5239 if ((tvp
!= NULL
) && vnode_isdir(tvp
)) {
5242 } else if (tdvp
!= fdvp
) {
5246 * must have delete rights to remove the old name even in
5247 * the simple case of fdvp == tdvp.
5249 * If fvp is a directory, and we are changing it's parent,
5250 * then we also need rights to rewrite its ".." entry as well.
5252 if (vnode_isdir(fvp
)) {
5253 if ((error
= vnode_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
| KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
)) != 0)
5256 if ((error
= vnode_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
, ctx
)) != 0)
5260 /* moving into tdvp or tvp, must have rights to add */
5261 if ((error
= vnode_authorize(((tvp
!= NULL
) && vnode_isdir(tvp
)) ? tvp
: tdvp
,
5263 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
5266 * We could encounter a race where after doing the namei, tvp stops
5267 * being valid. If so, simply re-drive the rename call from the
5270 if (error
== ENOENT
) {
5276 /* node staying in same directory, must be allowed to add new name */
5277 if ((error
= vnode_authorize(fdvp
, NULL
,
5278 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
5281 /* overwriting tvp */
5282 if ((tvp
!= NULL
) && !vnode_isdir(tvp
) &&
5283 ((error
= vnode_authorize(tvp
, tdvp
, KAUTH_VNODE_DELETE
, ctx
)) != 0)) {
5285 * We could encounter a race where after doing the namei, tvp stops
5286 * being valid. If so, simply re-drive the rename call from the
5289 if (error
== ENOENT
) {
5295 /* XXX more checks? */
5298 /* authorization denied */
5303 * Allow the renaming of mount points.
5304 * - target must not exist
5305 * - target must reside in the same directory as source
5306 * - union mounts cannot be renamed
5307 * - "/" cannot be renamed
5309 if ((fvp
->v_flag
& VROOT
) &&
5310 (fvp
->v_type
== VDIR
) &&
5312 (fvp
->v_mountedhere
== NULL
) &&
5314 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
5315 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
5318 /* switch fvp to the covered vnode */
5319 coveredvp
= fvp
->v_mount
->mnt_vnodecovered
;
5320 if ( (vnode_getwithref(coveredvp
)) ) {
5330 * Check for cross-device rename.
5332 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
5333 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
5338 * Avoid renaming "." and "..".
5340 if (fvp
->v_type
== VDIR
&&
5342 (fromnd
.ni_cnd
.cn_namelen
== 1 && fromnd
.ni_cnd
.cn_nameptr
[0] == '.') ||
5343 ((fromnd
.ni_cnd
.cn_flags
| tond
.ni_cnd
.cn_flags
) & ISDOTDOT
)) ) {
5348 * The following edge case is caught here:
5349 * (to cannot be a descendent of from)
5362 if (tdvp
->v_parent
== fvp
) {
5368 * If source is the same as the destination (that is the
5369 * same inode number) then there is nothing to do...
5370 * EXCEPT if the underlying file system supports case
5371 * insensitivity and is case preserving. In this case
5372 * the file system needs to handle the special case of
5373 * getting the same vnode as target (fvp) and source (tvp).
5375 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
5376 * and _PC_CASE_PRESERVING can have this exception, and they need to
5377 * handle the special case of getting the same vnode as target and
5378 * source. NOTE: Then the target is unlocked going into vnop_rename,
5379 * so not to cause locking problems. There is a single reference on tvp.
5381 * NOTE - that fvp == tvp also occurs if they are hard linked and
5382 * that correct behaviour then is just to return success without doing
5385 if (fvp
== tvp
&& fdvp
== tdvp
) {
5386 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
5387 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
5388 fromnd
.ni_cnd
.cn_namelen
)) {
5393 if (holding_mntlock
&& fvp
->v_mount
!= locked_mp
) {
5395 * we're holding a reference and lock
5396 * on locked_mp, but it no longer matches
5397 * what we want to do... so drop our hold
5399 mount_unlock_renames(locked_mp
);
5400 mount_drop(locked_mp
, 0);
5401 holding_mntlock
= 0;
5403 if (tdvp
!= fdvp
&& fvp
->v_type
== VDIR
) {
5405 * serialize renames that re-shape
5406 * the tree... if holding_mntlock is
5407 * set, then we're ready to go...
5409 * first need to drop the iocounts
5410 * we picked up, second take the
5411 * lock to serialize the access,
5412 * then finally start the lookup
5413 * process over with the lock held
5415 if (!holding_mntlock
) {
5417 * need to grab a reference on
5418 * the mount point before we
5419 * drop all the iocounts... once
5420 * the iocounts are gone, the mount
5423 locked_mp
= fvp
->v_mount
;
5424 mount_ref(locked_mp
, 0);
5427 * nameidone has to happen before we vnode_put(tvp)
5428 * since it may need to release the fs_nodelock on the tvp
5437 * nameidone has to happen before we vnode_put(fdvp)
5438 * since it may need to release the fs_nodelock on the fvp
5445 mount_lock_renames(locked_mp
);
5446 holding_mntlock
= 1;
5452 * when we dropped the iocounts to take
5453 * the lock, we allowed the identity of
5454 * the various vnodes to change... if they did,
5455 * we may no longer be dealing with a rename
5456 * that reshapes the tree... once we're holding
5457 * the iocounts, the vnodes can't change type
5458 * so we're free to drop the lock at this point
5461 if (holding_mntlock
) {
5462 mount_unlock_renames(locked_mp
);
5463 mount_drop(locked_mp
, 0);
5464 holding_mntlock
= 0;
5467 // save these off so we can later verify that fvp is the same
5468 oname
= fvp
->v_name
;
5469 oparent
= fvp
->v_parent
;
5472 need_event
= need_fsevent(FSE_RENAME
, fvp
);
5474 get_fse_info(fvp
, &from_finfo
, ctx
);
5477 get_fse_info(tvp
, &to_finfo
, ctx
);
5482 #endif /* CONFIG_FSE */
5484 if (need_event
|| kauth_authorize_fileop_has_listeners()) {
5485 GET_PATH(from_name
);
5486 if (from_name
== NULL
) {
5491 from_len
= safe_getpath(fdvp
, fromnd
.ni_cnd
.cn_nameptr
, from_name
, MAXPATHLEN
, &from_truncated
);
5494 if (to_name
== NULL
) {
5499 to_len
= safe_getpath(tdvp
, tond
.ni_cnd
.cn_nameptr
, to_name
, MAXPATHLEN
, &to_truncated
);
5502 error
= VNOP_RENAME(fdvp
, fvp
, &fromnd
.ni_cnd
,
5503 tdvp
, tvp
, &tond
.ni_cnd
,
5506 if (holding_mntlock
) {
5508 * we can drop our serialization
5511 mount_unlock_renames(locked_mp
);
5512 mount_drop(locked_mp
, 0);
5513 holding_mntlock
= 0;
5517 * We may encounter a race in the VNOP where the destination didn't
5518 * exist when we did the namei, but it does by the time we go and
5519 * try to create the entry. In this case, we should re-drive this rename
5520 * call from the top again. Currently, only HFS bubbles out ERECYCLE,
5521 * but other filesystems susceptible to this race could return it, too.
5523 if (error
== ERECYCLE
) {
5530 /* call out to allow 3rd party notification of rename.
5531 * Ignore result of kauth_authorize_fileop call.
5533 kauth_authorize_fileop(vfs_context_ucred(ctx
),
5534 KAUTH_FILEOP_RENAME
,
5535 (uintptr_t)from_name
, (uintptr_t)to_name
);
5538 if (from_name
!= NULL
&& to_name
!= NULL
) {
5539 if (from_truncated
|| to_truncated
) {
5540 // set it here since only the from_finfo gets reported up to user space
5541 from_finfo
.mode
|= FSE_TRUNCATED_PATH
;
5544 add_fsevent(FSE_RENAME
, ctx
,
5545 FSE_ARG_STRING
, from_len
, from_name
,
5546 FSE_ARG_FINFO
, &from_finfo
,
5547 FSE_ARG_STRING
, to_len
, to_name
,
5548 FSE_ARG_FINFO
, &to_finfo
,
5551 add_fsevent(FSE_RENAME
, ctx
,
5552 FSE_ARG_STRING
, from_len
, from_name
,
5553 FSE_ARG_FINFO
, &from_finfo
,
5554 FSE_ARG_STRING
, to_len
, to_name
,
5558 #endif /* CONFIG_FSE */
5561 * update filesystem's mount point data
5564 char *cp
, *pathend
, *mpname
;
5570 mp
= fvp
->v_mountedhere
;
5572 if (vfs_busy(mp
, LK_NOWAIT
)) {
5576 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
5578 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
5580 /* find current mount point prefix */
5581 pathend
= &mp
->mnt_vfsstat
.f_mntonname
[0];
5582 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
5586 /* find last component of target name */
5587 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
5591 /* append name to prefix */
5592 maxlen
= MAXPATHLEN
- (pathend
- mp
->mnt_vfsstat
.f_mntonname
);
5593 bzero(pathend
, maxlen
);
5594 strlcpy(pathend
, mpname
, maxlen
);
5596 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
5601 * fix up name & parent pointers. note that we first
5602 * check that fvp has the same name/parent pointers it
5603 * had before the rename call... this is a 'weak' check
5606 if (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
) {
5609 update_flags
= VNODE_UPDATE_NAME
;
5612 update_flags
|= VNODE_UPDATE_PARENT
;
5614 vnode_update_identity(fvp
, tdvp
, tond
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_namelen
, tond
.ni_cnd
.cn_hash
, update_flags
);
5617 if (to_name
!= NULL
) {
5618 RELEASE_PATH(to_name
);
5621 if (from_name
!= NULL
) {
5622 RELEASE_PATH(from_name
);
5625 if (holding_mntlock
) {
5626 mount_unlock_renames(locked_mp
);
5627 mount_drop(locked_mp
, 0);
5628 holding_mntlock
= 0;
5632 * nameidone has to happen before we vnode_put(tdvp)
5633 * since it may need to release the fs_nodelock on the tdvp
5643 * nameidone has to happen before we vnode_put(fdvp)
5644 * since it may need to release the fs_nodelock on the fdvp
5654 * If things changed after we did the namei, then we will re-drive
5655 * this rename call from the top.
5666 * Make a directory file.
5668 * Returns: 0 Success
5671 * vnode_authorize:???
5676 mkdir1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
5680 int update_flags
= 0;
5681 struct nameidata nd
;
5683 AUDIT_ARG(mode
, vap
->va_mode
);
5684 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
5685 UIO_USERSPACE
, path
, ctx
);
5686 nd
.ni_cnd
.cn_flags
|= WILLBEDIR
;
5698 VATTR_SET(vap
, va_type
, VDIR
);
5701 error
= mac_vnode_check_create(ctx
,
5702 nd
.ni_dvp
, &nd
.ni_cnd
, vap
);
5707 /* authorize addition of a directory to the parent */
5708 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
)) != 0)
5712 /* make the directory */
5713 if ((error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
)) != 0)
5716 // Make sure the name & parent pointers are hooked up
5717 if (vp
->v_name
== NULL
)
5718 update_flags
|= VNODE_UPDATE_NAME
;
5719 if (vp
->v_parent
== NULLVP
)
5720 update_flags
|= VNODE_UPDATE_PARENT
;
5723 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
5726 add_fsevent(FSE_CREATE_DIR
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
5731 * nameidone has to happen before we vnode_put(dvp)
5732 * since it may need to release the fs_nodelock on the dvp
5744 * mkdir_extended: Create a directory; with extended security (ACL).
5746 * Parameters: p Process requesting to create the directory
5747 * uap User argument descriptor (see below)
5750 * Indirect: uap->path Path of directory to create
5751 * uap->mode Access permissions to set
5752 * uap->xsecurity ACL to set
5754 * Returns: 0 Success
5759 mkdir_extended(proc_t p
, struct mkdir_extended_args
*uap
, __unused
int32_t *retval
)
5762 kauth_filesec_t xsecdst
;
5763 struct vnode_attr va
;
5765 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
5768 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
5769 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
5773 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
5774 if (xsecdst
!= NULL
)
5775 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
5777 ciferror
= mkdir1(vfs_context_current(), uap
->path
, &va
);
5778 if (xsecdst
!= NULL
)
5779 kauth_filesec_free(xsecdst
);
5784 mkdir(proc_t p
, struct mkdir_args
*uap
, __unused
int32_t *retval
)
5786 struct vnode_attr va
;
5789 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
5791 return(mkdir1(vfs_context_current(), uap
->path
, &va
));
5795 * Remove a directory file.
5799 rmdir(__unused proc_t p
, struct rmdir_args
*uap
, __unused
int32_t *retval
)
5803 struct nameidata nd
;
5804 vfs_context_t ctx
= vfs_context_current();
5807 uint32_t oldvp_id
= UINT32_MAX
;
5810 * This loop exists to restart rmdir in the unlikely case that two
5811 * processes are simultaneously trying to remove the same directory
5812 * containing orphaned appleDouble files.
5817 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
5818 UIO_USERSPACE
, uap
->path
, ctx
);
5828 * If being restarted check if the new vp
5829 * still has the same v_id.
5831 if (oldvp_id
!= UINT32_MAX
&& oldvp_id
!= vp
->v_id
) {
5836 if (vp
->v_type
!= VDIR
) {
5838 * rmdir only deals with directories
5841 } else if (dvp
== vp
) {
5843 * No rmdir "." please.
5846 } else if (vp
->v_flag
& VROOT
) {
5848 * The root of a mounted filesystem cannot be deleted.
5853 error
= mac_vnode_check_unlink(ctx
, dvp
,
5857 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, ctx
);
5862 int has_listeners
= 0;
5868 need_event
= need_fsevent(FSE_DELETE
, dvp
);
5870 get_fse_info(vp
, &finfo
, ctx
);
5873 has_listeners
= kauth_authorize_fileop_has_listeners();
5874 if (need_event
|| has_listeners
) {
5881 len
= safe_getpath(vp
, NULL
, path
, MAXPATHLEN
, &truncated
);
5884 finfo
.mode
|= FSE_TRUNCATED_PATH
;
5889 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, ctx
);
5892 * Special case to remove orphaned AppleDouble
5893 * files. I don't like putting this in the kernel,
5894 * but carbon does not like putting this in carbon either,
5897 if (error
== ENOTEMPTY
) {
5898 error
= rmdir_remove_orphaned_appleDouble(vp
, ctx
, &restart_flag
);
5899 if (error
== EBUSY
) {
5900 oldvp_id
= vp
->v_id
;
5906 * Assuming everything went well, we will try the RMDIR again
5909 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, ctx
);
5913 * Call out to allow 3rd party notification of delete.
5914 * Ignore result of kauth_authorize_fileop call.
5917 if (has_listeners
) {
5918 kauth_authorize_fileop(vfs_context_ucred(ctx
),
5919 KAUTH_FILEOP_DELETE
,
5924 if (vp
->v_flag
& VISHARDLINK
) {
5925 // see the comment in unlink1() about why we update
5926 // the parent of a hard link when it is removed
5927 vnode_update_identity(vp
, NULL
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
5932 add_fsevent(FSE_DELETE
, ctx
,
5933 FSE_ARG_STRING
, len
, path
,
5934 FSE_ARG_FINFO
, &finfo
,
5945 * nameidone has to happen before we vnode_put(dvp)
5946 * since it may need to release the fs_nodelock on the dvp
5953 if (restart_flag
== 0) {
5954 wakeup_one((caddr_t
)vp
);
5957 tsleep(vp
, PVFS
, "rm AD", 1);
5959 } while (restart_flag
!= 0);
5965 /* Get direntry length padded to 8 byte alignment */
5966 #define DIRENT64_LEN(namlen) \
5967 ((sizeof(struct direntry) + (namlen) - (MAXPATHLEN-1) + 7) & ~7)
5970 vnode_readdir64(struct vnode
*vp
, struct uio
*uio
, int flags
, int *eofflag
,
5971 int *numdirent
, vfs_context_t ctxp
)
5973 /* Check if fs natively supports VNODE_READDIR_EXTENDED */
5974 if (vp
->v_mount
->mnt_vtable
->vfc_vfsflags
& VFC_VFSREADDIR_EXTENDED
) {
5975 return VNOP_READDIR(vp
, uio
, flags
, eofflag
, numdirent
, ctxp
);
5980 struct direntry entry64
;
5986 * Our kernel buffer needs to be smaller since re-packing
5987 * will expand each dirent. The worse case (when the name
5988 * length is 3) corresponds to a struct direntry size of 32
5989 * bytes (8-byte aligned) and a struct dirent size of 12 bytes
5990 * (4-byte aligned). So having a buffer that is 3/8 the size
5991 * will prevent us from reading more than we can pack.
5993 * Since this buffer is wired memory, we will limit the
5994 * buffer size to a maximum of 32K. We would really like to
5995 * use 32K in the MIN(), but we use magic number 87371 to
5996 * prevent uio_resid() * 3 / 8 from overflowing.
5998 bufsize
= 3 * MIN(uio_resid(uio
), 87371) / 8;
5999 MALLOC(bufptr
, void *, bufsize
, M_TEMP
, M_WAITOK
);
6000 if (bufptr
== NULL
) {
6004 auio
= uio_create(1, 0, UIO_SYSSPACE
, UIO_READ
);
6005 uio_addiov(auio
, (uintptr_t)bufptr
, bufsize
);
6006 auio
->uio_offset
= uio
->uio_offset
;
6008 error
= VNOP_READDIR(vp
, auio
, 0, eofflag
, numdirent
, ctxp
);
6010 dep
= (struct dirent
*)bufptr
;
6011 bytesread
= bufsize
- uio_resid(auio
);
6014 * Convert all the entries and copy them out to user's buffer.
6016 while (error
== 0 && (char *)dep
< ((char *)bufptr
+ bytesread
)) {
6017 /* Convert a dirent to a dirent64. */
6018 entry64
.d_ino
= dep
->d_ino
;
6019 entry64
.d_seekoff
= 0;
6020 entry64
.d_reclen
= DIRENT64_LEN(dep
->d_namlen
);
6021 entry64
.d_namlen
= dep
->d_namlen
;
6022 entry64
.d_type
= dep
->d_type
;
6023 bcopy(dep
->d_name
, entry64
.d_name
, dep
->d_namlen
+ 1);
6025 /* Move to next entry. */
6026 dep
= (struct dirent
*)((char *)dep
+ dep
->d_reclen
);
6028 /* Copy entry64 to user's buffer. */
6029 error
= uiomove((caddr_t
)&entry64
, entry64
.d_reclen
, uio
);
6032 /* Update the real offset using the offset we got from VNOP_READDIR. */
6034 uio
->uio_offset
= auio
->uio_offset
;
6037 FREE(bufptr
, M_TEMP
);
6043 * Read a block of directory entries in a file system independent format.
6046 getdirentries_common(int fd
, user_addr_t bufp
, user_size_t bufsize
, ssize_t
*bytesread
,
6047 off_t
*offset
, int flags
)
6050 struct vfs_context context
= *vfs_context_current(); /* local copy */
6051 struct fileproc
*fp
;
6053 int spacetype
= proc_is64bit(vfs_context_proc(&context
)) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6055 int error
, eofflag
, numdirent
;
6056 char uio_buf
[ UIO_SIZEOF(1) ];
6058 error
= fp_getfvp(vfs_context_proc(&context
), fd
, &fp
, &vp
);
6062 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
6063 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
6069 error
= mac_file_check_change_offset(vfs_context_ucred(&context
), fp
->f_fglob
);
6073 if ( (error
= vnode_getwithref(vp
)) ) {
6076 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
6079 if (vp
->v_type
!= VDIR
) {
6080 (void)vnode_put(vp
);
6086 error
= mac_vnode_check_readdir(&context
, vp
);
6088 (void)vnode_put(vp
);
6093 loff
= fp
->f_fglob
->fg_offset
;
6094 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
6095 uio_addiov(auio
, bufp
, bufsize
);
6097 if (flags
& VNODE_READDIR_EXTENDED
) {
6098 error
= vnode_readdir64(vp
, auio
, flags
, &eofflag
, &numdirent
, &context
);
6099 fp
->f_fglob
->fg_offset
= uio_offset(auio
);
6101 error
= VNOP_READDIR(vp
, auio
, 0, &eofflag
, &numdirent
, &context
);
6102 fp
->f_fglob
->fg_offset
= uio_offset(auio
);
6105 (void)vnode_put(vp
);
6109 if ((user_ssize_t
)bufsize
== uio_resid(auio
)){
6110 if (union_dircheckp
) {
6111 error
= union_dircheckp(&vp
, fp
, &context
);
6118 if ((vp
->v_flag
& VROOT
) && (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
6119 struct vnode
*tvp
= vp
;
6120 vp
= vp
->v_mount
->mnt_vnodecovered
;
6121 vnode_getwithref(vp
);
6123 fp
->f_fglob
->fg_data
= (caddr_t
) vp
;
6124 fp
->f_fglob
->fg_offset
= 0;
6136 *bytesread
= bufsize
- uio_resid(auio
);
6144 getdirentries(__unused
struct proc
*p
, struct getdirentries_args
*uap
, int32_t *retval
)
6150 AUDIT_ARG(fd
, uap
->fd
);
6151 error
= getdirentries_common(uap
->fd
, uap
->buf
, uap
->count
, &bytesread
, &offset
, 0);
6154 if (proc_is64bit(p
)) {
6155 user64_long_t base
= (user64_long_t
)offset
;
6156 error
= copyout((caddr_t
)&base
, uap
->basep
, sizeof(user64_long_t
));
6158 user32_long_t base
= (user32_long_t
)offset
;
6159 error
= copyout((caddr_t
)&base
, uap
->basep
, sizeof(user32_long_t
));
6161 *retval
= bytesread
;
6167 getdirentries64(__unused
struct proc
*p
, struct getdirentries64_args
*uap
, user_ssize_t
*retval
)
6173 AUDIT_ARG(fd
, uap
->fd
);
6174 error
= getdirentries_common(uap
->fd
, uap
->buf
, uap
->bufsize
, &bytesread
, &offset
, VNODE_READDIR_EXTENDED
);
6177 *retval
= bytesread
;
6178 error
= copyout((caddr_t
)&offset
, uap
->position
, sizeof(off_t
));
6185 * Set the mode mask for creation of filesystem nodes.
6186 * XXX implement xsecurity
6188 #define UMASK_NOXSECURITY (void *)1 /* leave existing xsecurity alone */
6190 umask1(proc_t p
, int newmask
, __unused kauth_filesec_t fsec
, int32_t *retval
)
6192 struct filedesc
*fdp
;
6194 AUDIT_ARG(mask
, newmask
);
6197 *retval
= fdp
->fd_cmask
;
6198 fdp
->fd_cmask
= newmask
& ALLPERMS
;
6204 * umask_extended: Set the mode mask for creation of filesystem nodes; with extended security (ACL).
6206 * Parameters: p Process requesting to set the umask
6207 * uap User argument descriptor (see below)
6208 * retval umask of the process (parameter p)
6210 * Indirect: uap->newmask umask to set
6211 * uap->xsecurity ACL to set
6213 * Returns: 0 Success
6218 umask_extended(proc_t p
, struct umask_extended_args
*uap
, int32_t *retval
)
6221 kauth_filesec_t xsecdst
;
6223 xsecdst
= KAUTH_FILESEC_NONE
;
6224 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
6225 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
6228 xsecdst
= KAUTH_FILESEC_NONE
;
6231 ciferror
= umask1(p
, uap
->newmask
, xsecdst
, retval
);
6233 if (xsecdst
!= KAUTH_FILESEC_NONE
)
6234 kauth_filesec_free(xsecdst
);
6239 umask(proc_t p
, struct umask_args
*uap
, int32_t *retval
)
6241 return(umask1(p
, uap
->newmask
, UMASK_NOXSECURITY
, retval
));
6245 * Void all references to file by ripping underlying filesystem
6250 revoke(proc_t p
, struct revoke_args
*uap
, __unused
int32_t *retval
)
6253 struct vnode_attr va
;
6254 vfs_context_t ctx
= vfs_context_current();
6256 struct nameidata nd
;
6258 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
6259 UIO_USERSPACE
, uap
->path
, ctx
);
6267 if (!(vnode_ischr(vp
) || vnode_isblk(vp
))) {
6272 if (vnode_isblk(vp
) && vnode_ismountedon(vp
)) {
6278 error
= mac_vnode_check_revoke(ctx
, vp
);
6284 VATTR_WANTED(&va
, va_uid
);
6285 if ((error
= vnode_getattr(vp
, &va
, ctx
)))
6287 if (kauth_cred_getuid(vfs_context_ucred(ctx
)) != va
.va_uid
&&
6288 (error
= suser(vfs_context_ucred(ctx
), &p
->p_acflag
)))
6290 if (vp
->v_usecount
> 0 || (vnode_isaliased(vp
)))
6291 VNOP_REVOKE(vp
, REVOKEALL
, ctx
);
6299 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
6300 * The following system calls are designed to support features
6301 * which are specific to the HFS & HFS Plus volume formats
6304 #ifdef __APPLE_API_OBSOLETE
6306 /************************************************/
6307 /* *** Following calls will be deleted soon *** */
6308 /************************************************/
6311 * Make a complex file. A complex file is one with multiple forks (data streams)
6315 mkcomplex(__unused proc_t p
, __unused
struct mkcomplex_args
*uap
, __unused
int32_t *retval
)
6321 * Extended stat call which returns volumeid and vnodeid as well as other info
6325 statv(__unused proc_t p
,
6326 __unused
struct statv_args
*uap
,
6327 __unused
int32_t *retval
)
6329 return (ENOTSUP
); /* We'll just return an error for now */
6331 } /* end of statv system call */
6334 * Extended lstat call which returns volumeid and vnodeid as well as other info
6338 lstatv(__unused proc_t p
,
6339 __unused
struct lstatv_args
*uap
,
6340 __unused
int32_t *retval
)
6342 return (ENOTSUP
); /* We'll just return an error for now */
6343 } /* end of lstatv system call */
6346 * Extended fstat call which returns volumeid and vnodeid as well as other info
6350 fstatv(__unused proc_t p
,
6351 __unused
struct fstatv_args
*uap
,
6352 __unused
int32_t *retval
)
6354 return (ENOTSUP
); /* We'll just return an error for now */
6355 } /* end of fstatv system call */
6358 /************************************************/
6359 /* *** Preceding calls will be deleted soon *** */
6360 /************************************************/
6362 #endif /* __APPLE_API_OBSOLETE */
6365 * Obtain attribute information on objects in a directory while enumerating
6366 * the directory. This call does not yet support union mounted directories.
6368 * 1.union mounted directories.
6373 getdirentriesattr (proc_t p
, struct getdirentriesattr_args
*uap
, int32_t *retval
)
6376 struct fileproc
*fp
;
6378 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6383 struct attrlist attributelist
;
6384 vfs_context_t ctx
= vfs_context_current();
6386 char uio_buf
[ UIO_SIZEOF(1) ];
6387 kauth_action_t action
;
6391 /* Get the attributes into kernel space */
6392 if ((error
= copyin(uap
->alist
, (caddr_t
)&attributelist
, sizeof(attributelist
)))) {
6395 if ((error
= copyin(uap
->count
, (caddr_t
)&count
, sizeof(count
)))) {
6398 if ( (error
= fp_getfvp(p
, fd
, &fp
, &vp
)) ) {
6401 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
6402 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
6409 error
= mac_file_check_change_offset(vfs_context_ucred(ctx
),
6416 if ( (error
= vnode_getwithref(vp
)) )
6419 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
6421 if (vp
->v_type
!= VDIR
) {
6422 (void)vnode_put(vp
);
6428 error
= mac_vnode_check_readdir(ctx
, vp
);
6430 (void)vnode_put(vp
);
6435 /* set up the uio structure which will contain the users return buffer */
6436 loff
= fp
->f_fglob
->fg_offset
;
6437 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
6438 &uio_buf
[0], sizeof(uio_buf
));
6439 uio_addiov(auio
, uap
->buffer
, uap
->buffersize
);
6442 * If the only item requested is file names, we can let that past with
6443 * just LIST_DIRECTORY. If they want any other attributes, that means
6444 * they need SEARCH as well.
6446 action
= KAUTH_VNODE_LIST_DIRECTORY
;
6447 if ((attributelist
.commonattr
& ~ATTR_CMN_NAME
) ||
6448 attributelist
.fileattr
|| attributelist
.dirattr
)
6449 action
|= KAUTH_VNODE_SEARCH
;
6451 if ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) == 0) {
6453 /* Believe it or not, uap->options only has 32-bits of valid
6454 * info, so truncate before extending again */
6455 error
= VNOP_READDIRATTR(vp
, &attributelist
, auio
,
6457 (u_long
)(uint32_t)uap
->options
, &newstate
, &eofflag
,
6460 (void)vnode_put(vp
);
6464 fp
->f_fglob
->fg_offset
= uio_offset(auio
); /* should be multiple of dirent, not variable */
6466 if ((error
= copyout((caddr_t
) &count
, uap
->count
, sizeof(count
))))
6468 if ((error
= copyout((caddr_t
) &newstate
, uap
->newstate
, sizeof(newstate
))))
6470 if ((error
= copyout((caddr_t
) &loff
, uap
->basep
, sizeof(loff
))))
6473 *retval
= eofflag
; /* similar to getdirentries */
6477 return (error
); /* return error earlier, an retval of 0 or 1 now */
6479 } /* end of getdirentryattr system call */
6482 * Exchange data between two files
6487 exchangedata (__unused proc_t p
, struct exchangedata_args
*uap
, __unused
int32_t *retval
)
6490 struct nameidata fnd
, snd
;
6491 vfs_context_t ctx
= vfs_context_current();
6495 u_int32_t nameiflags
;
6499 int from_truncated
=0, to_truncated
=0;
6501 fse_info f_finfo
, s_finfo
;
6505 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
6507 NDINIT(&fnd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
6508 UIO_USERSPACE
, uap
->path1
, ctx
);
6510 error
= namei(&fnd
);
6517 NDINIT(&snd
, LOOKUP
| CN_NBMOUNTLOOK
, nameiflags
| AUDITVNPATH2
,
6518 UIO_USERSPACE
, uap
->path2
, ctx
);
6520 error
= namei(&snd
);
6529 * if the files are the same, return an inval error
6537 * if the files are on different volumes, return an error
6539 if (svp
->v_mount
!= fvp
->v_mount
) {
6545 error
= mac_vnode_check_exchangedata(ctx
,
6550 if (((error
= vnode_authorize(fvp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, ctx
)) != 0) ||
6551 ((error
= vnode_authorize(svp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, ctx
)) != 0))
6556 need_fsevent(FSE_EXCHANGE
, fvp
) ||
6558 kauth_authorize_fileop_has_listeners()) {
6561 if (fpath
== NULL
|| spath
== NULL
) {
6566 flen
= safe_getpath(fvp
, NULL
, fpath
, MAXPATHLEN
, &from_truncated
);
6567 slen
= safe_getpath(svp
, NULL
, spath
, MAXPATHLEN
, &to_truncated
);
6570 get_fse_info(fvp
, &f_finfo
, ctx
);
6571 get_fse_info(svp
, &s_finfo
, ctx
);
6572 if (from_truncated
|| to_truncated
) {
6573 // set it here since only the f_finfo gets reported up to user space
6574 f_finfo
.mode
|= FSE_TRUNCATED_PATH
;
6578 /* Ok, make the call */
6579 error
= VNOP_EXCHANGE(fvp
, svp
, 0, ctx
);
6582 const char *tmpname
;
6584 if (fpath
!= NULL
&& spath
!= NULL
) {
6585 /* call out to allow 3rd party notification of exchangedata.
6586 * Ignore result of kauth_authorize_fileop call.
6588 kauth_authorize_fileop(vfs_context_ucred(ctx
), KAUTH_FILEOP_EXCHANGE
,
6589 (uintptr_t)fpath
, (uintptr_t)spath
);
6593 tmpname
= fvp
->v_name
;
6594 fvp
->v_name
= svp
->v_name
;
6595 svp
->v_name
= tmpname
;
6597 if (fvp
->v_parent
!= svp
->v_parent
) {
6600 tmp
= fvp
->v_parent
;
6601 fvp
->v_parent
= svp
->v_parent
;
6602 svp
->v_parent
= tmp
;
6604 name_cache_unlock();
6607 if (fpath
!= NULL
&& spath
!= NULL
) {
6608 add_fsevent(FSE_EXCHANGE
, ctx
,
6609 FSE_ARG_STRING
, flen
, fpath
,
6610 FSE_ARG_FINFO
, &f_finfo
,
6611 FSE_ARG_STRING
, slen
, spath
,
6612 FSE_ARG_FINFO
, &s_finfo
,
6620 RELEASE_PATH(fpath
);
6622 RELEASE_PATH(spath
);
6633 searchfs(proc_t p
, struct searchfs_args
*uap
, __unused
int32_t *retval
)
6638 struct nameidata nd
;
6639 struct user64_fssearchblock searchblock
;
6640 struct searchstate
*state
;
6641 struct attrlist
*returnattrs
;
6642 struct timeval timelimit
;
6643 void *searchparams1
,*searchparams2
;
6645 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6646 uint32_t nummatches
;
6648 uint32_t nameiflags
;
6649 vfs_context_t ctx
= vfs_context_current();
6650 char uio_buf
[ UIO_SIZEOF(1) ];
6652 /* Start by copying in fsearchblock paramater list */
6653 if (IS_64BIT_PROCESS(p
)) {
6654 error
= copyin(uap
->searchblock
, (caddr_t
) &searchblock
, sizeof(searchblock
));
6655 timelimit
.tv_sec
= searchblock
.timelimit
.tv_sec
;
6656 timelimit
.tv_usec
= searchblock
.timelimit
.tv_usec
;
6659 struct user32_fssearchblock tmp_searchblock
;
6661 error
= copyin(uap
->searchblock
, (caddr_t
) &tmp_searchblock
, sizeof(tmp_searchblock
));
6662 // munge into 64-bit version
6663 searchblock
.returnattrs
= CAST_USER_ADDR_T(tmp_searchblock
.returnattrs
);
6664 searchblock
.returnbuffer
= CAST_USER_ADDR_T(tmp_searchblock
.returnbuffer
);
6665 searchblock
.returnbuffersize
= tmp_searchblock
.returnbuffersize
;
6666 searchblock
.maxmatches
= tmp_searchblock
.maxmatches
;
6668 * These casts are safe. We will promote the tv_sec into a 64 bit long if necessary
6669 * from a 32 bit long, and tv_usec is already a signed 32 bit int.
6671 timelimit
.tv_sec
= (__darwin_time_t
) tmp_searchblock
.timelimit
.tv_sec
;
6672 timelimit
.tv_usec
= (__darwin_useconds_t
) tmp_searchblock
.timelimit
.tv_usec
;
6673 searchblock
.searchparams1
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams1
);
6674 searchblock
.sizeofsearchparams1
= tmp_searchblock
.sizeofsearchparams1
;
6675 searchblock
.searchparams2
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams2
);
6676 searchblock
.sizeofsearchparams2
= tmp_searchblock
.sizeofsearchparams2
;
6677 searchblock
.searchattrs
= tmp_searchblock
.searchattrs
;
6682 /* Do a sanity check on sizeofsearchparams1 and sizeofsearchparams2.
6684 if (searchblock
.sizeofsearchparams1
> SEARCHFS_MAX_SEARCHPARMS
||
6685 searchblock
.sizeofsearchparams2
> SEARCHFS_MAX_SEARCHPARMS
)
6688 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
6689 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
6690 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
6693 mallocsize
= searchblock
.sizeofsearchparams1
+ searchblock
.sizeofsearchparams2
+
6694 sizeof(struct attrlist
) + sizeof(struct searchstate
);
6696 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
6698 /* Now set up the various pointers to the correct place in our newly allocated memory */
6700 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
6701 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
6702 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
6704 /* Now copy in the stuff given our local variables. */
6706 if ((error
= copyin(searchblock
.searchparams1
, searchparams1
, searchblock
.sizeofsearchparams1
)))
6709 if ((error
= copyin(searchblock
.searchparams2
, searchparams2
, searchblock
.sizeofsearchparams2
)))
6712 if ((error
= copyin(searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
))))
6715 if ((error
= copyin(uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
))))
6720 * Because searchparams1 and searchparams2 may contain an ATTR_CMN_NAME search parameter,
6721 * which is passed in with an attrreference_t, we need to inspect the buffer manually here.
6722 * The KPI does not provide us the ability to pass in the length of the buffers searchparams1
6723 * and searchparams2. To obviate the need for all searchfs-supporting filesystems to
6724 * validate the user-supplied data offset of the attrreference_t, we'll do it here.
6727 if (searchblock
.searchattrs
.commonattr
& ATTR_CMN_NAME
) {
6728 attrreference_t
* string_ref
;
6729 u_int32_t
* start_length
;
6730 user64_size_t param_length
;
6732 /* validate searchparams1 */
6733 param_length
= searchblock
.sizeofsearchparams1
;
6734 /* skip the word that specifies length of the buffer */
6735 start_length
= (u_int32_t
*) searchparams1
;
6736 start_length
= start_length
+1;
6737 string_ref
= (attrreference_t
*) start_length
;
6739 /* ensure no negative offsets or too big offsets */
6740 if (string_ref
->attr_dataoffset
< 0 ) {
6744 if (string_ref
->attr_length
> MAXPATHLEN
) {
6749 /* Check for pointer overflow in the string ref */
6750 if (((char*) string_ref
+ string_ref
->attr_dataoffset
) < (char*) string_ref
) {
6755 if (((char*) string_ref
+ string_ref
->attr_dataoffset
) > ((char*)searchparams1
+ param_length
)) {
6759 if (((char*)string_ref
+ string_ref
->attr_dataoffset
+ string_ref
->attr_length
) > ((char*)searchparams1
+ param_length
)) {
6765 /* set up the uio structure which will contain the users return buffer */
6766 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
6767 &uio_buf
[0], sizeof(uio_buf
));
6768 uio_addiov(auio
, searchblock
.returnbuffer
, searchblock
.returnbuffersize
);
6771 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
6772 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
6773 UIO_USERSPACE
, uap
->path
, ctx
);
6784 * If searchblock.maxmatches == 0, then skip the search. This has happened
6785 * before and sometimes the underlyning code doesnt deal with it well.
6787 if (searchblock
.maxmatches
== 0) {
6793 Allright, we have everything we need, so lets make that call.
6795 We keep special track of the return value from the file system:
6796 EAGAIN is an acceptable error condition that shouldn't keep us
6797 from copying out any results...
6800 fserror
= VNOP_SEARCHFS(vp
,
6803 &searchblock
.searchattrs
,
6804 (u_long
)searchblock
.maxmatches
,
6808 (u_long
)uap
->scriptcode
,
6809 (u_long
)uap
->options
,
6818 /* Now copy out the stuff that needs copying out. That means the number of matches, the
6819 search state. Everything was already put into he return buffer by the vop call. */
6821 if ((error
= copyout((caddr_t
) state
, uap
->state
, sizeof(struct searchstate
))) != 0)
6824 if ((error
= suulong(uap
->nummatches
, (uint64_t)nummatches
)) != 0)
6831 FREE(searchparams1
,M_TEMP
);
6836 } /* end of searchfs system call */
6840 * Make a filesystem-specific control call:
6844 fsctl_internal(proc_t p
, vnode_t
*arg_vp
, u_long cmd
, user_addr_t udata
, u_long options
, vfs_context_t ctx
)
6849 #define STK_PARAMS 128
6850 char stkbuf
[STK_PARAMS
];
6852 vnode_t vp
= *arg_vp
;
6854 size
= IOCPARM_LEN(cmd
);
6855 if (size
> IOCPARM_MAX
) return (EINVAL
);
6857 is64bit
= proc_is64bit(p
);
6860 if (size
> sizeof (stkbuf
)) {
6861 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
6869 error
= copyin(udata
, data
, size
);
6870 if (error
) goto FSCtl_Exit
;
6873 *(user_addr_t
*)data
= udata
;
6876 *(uint32_t *)data
= (uint32_t)udata
;
6879 } else if ((cmd
& IOC_OUT
) && size
) {
6881 * Zero the buffer so the user always
6882 * gets back something deterministic.
6885 } else if (cmd
& IOC_VOID
) {
6887 *(user_addr_t
*)data
= udata
;
6890 *(uint32_t *)data
= (uint32_t)udata
;
6894 /* Check to see if it's a generic command */
6895 if (IOCBASECMD(cmd
) == FSCTL_SYNC_VOLUME
) {
6896 mount_t mp
= vp
->v_mount
;
6897 int arg
= *(uint32_t*)data
;
6899 /* record vid of vp so we can drop it below. */
6900 uint32_t vvid
= vp
->v_id
;
6903 * Then grab mount_iterref so that we can release the vnode.
6904 * Without this, a thread may call vnode_iterate_prepare then
6905 * get into a deadlock because we've never released the root vp
6907 error
= mount_iterref (mp
, 0);
6913 /* issue the sync for this volume */
6914 (void)sync_callback(mp
, (arg
& FSCTL_SYNC_WAIT
) ? &arg
: NULL
);
6917 * Then release the mount_iterref once we're done syncing; it's not
6918 * needed for the VNOP_IOCTL below
6922 if (arg
& FSCTL_SYNC_FULLSYNC
) {
6923 /* re-obtain vnode iocount on the root vp, if possible */
6924 error
= vnode_getwithvid (vp
, vvid
);
6926 error
= VNOP_IOCTL(vp
, F_FULLFSYNC
, (caddr_t
)NULL
, 0, ctx
);
6930 /* mark the argument VP as having been released */
6933 } else if (IOCBASECMD(cmd
) == FSCTL_SET_PACKAGE_EXTS
) {
6934 user_addr_t ext_strings
;
6935 uint32_t num_entries
;
6938 if ( (is64bit
&& size
!= sizeof(user64_package_ext_info
))
6939 || (is64bit
== 0 && size
!= sizeof(user32_package_ext_info
))) {
6941 // either you're 64-bit and passed a 64-bit struct or
6942 // you're 32-bit and passed a 32-bit struct. otherwise
6949 ext_strings
= ((user64_package_ext_info
*)data
)->strings
;
6950 num_entries
= ((user64_package_ext_info
*)data
)->num_entries
;
6951 max_width
= ((user64_package_ext_info
*)data
)->max_width
;
6953 ext_strings
= CAST_USER_ADDR_T(((user32_package_ext_info
*)data
)->strings
);
6954 num_entries
= ((user32_package_ext_info
*)data
)->num_entries
;
6955 max_width
= ((user32_package_ext_info
*)data
)->max_width
;
6958 error
= set_package_extensions_table(ext_strings
, num_entries
, max_width
);
6960 } else if (IOCBASECMD(cmd
) == FSCTL_WAIT_FOR_SYNC
) {
6961 error
= tsleep((caddr_t
)&sync_wait_time
, PVFS
|PCATCH
, "sync-wait", 0);
6963 *(uint32_t *)data
= (uint32_t)sync_wait_time
;
6970 /* Invoke the filesystem-specific code */
6971 error
= VNOP_IOCTL(vp
, IOCBASECMD(cmd
), data
, options
, ctx
);
6976 * Copy any data to user, size was
6977 * already set and checked above.
6979 if (error
== 0 && (cmd
& IOC_OUT
) && size
)
6980 error
= copyout(data
, udata
, size
);
6983 if (memp
) kfree(memp
, size
);
6990 fsctl (proc_t p
, struct fsctl_args
*uap
, __unused
int32_t *retval
)
6993 struct nameidata nd
;
6996 vfs_context_t ctx
= vfs_context_current();
6998 AUDIT_ARG(cmd
, uap
->cmd
);
6999 AUDIT_ARG(value32
, uap
->options
);
7000 /* Get the vnode for the file we are getting info on: */
7002 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
7003 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
, UIO_USERSPACE
,
7005 if ((error
= namei(&nd
))) goto done
;
7010 error
= mac_mount_check_fsctl(ctx
, vnode_mount(vp
), uap
->cmd
);
7016 error
= fsctl_internal(p
, &vp
, uap
->cmd
, (user_addr_t
)uap
->data
, uap
->options
, ctx
);
7025 ffsctl (proc_t p
, struct ffsctl_args
*uap
, __unused
int32_t *retval
)
7029 vfs_context_t ctx
= vfs_context_current();
7032 AUDIT_ARG(fd
, uap
->fd
);
7033 AUDIT_ARG(cmd
, uap
->cmd
);
7034 AUDIT_ARG(value32
, uap
->options
);
7036 /* Get the vnode for the file we are getting info on: */
7037 if ((error
= file_vnode(uap
->fd
, &vp
)))
7040 if ((error
= vnode_getwithref(vp
))) {
7045 error
= mac_mount_check_fsctl(ctx
, vnode_mount(vp
), uap
->cmd
);
7051 error
= fsctl_internal(p
, &vp
, uap
->cmd
, (user_addr_t
)uap
->data
, uap
->options
, ctx
);
7061 /* end of fsctl system call */
7064 * An in-kernel sync for power management to call.
7066 __private_extern__
int
7071 struct sync_args data
;
7076 error
= sync(current_proc(), &data
, &retval
[0]);
7080 } /* end of sync_internal call */
7084 * Retrieve the data of an extended attribute.
7087 getxattr(proc_t p
, struct getxattr_args
*uap
, user_ssize_t
*retval
)
7090 struct nameidata nd
;
7091 char attrname
[XATTR_MAXNAMELEN
+1];
7092 vfs_context_t ctx
= vfs_context_current();
7094 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
7095 size_t attrsize
= 0;
7097 u_int32_t nameiflags
;
7099 char uio_buf
[ UIO_SIZEOF(1) ];
7101 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
7104 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
7105 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, ctx
);
7106 if ((error
= namei(&nd
))) {
7112 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
7115 if (xattr_protected(attrname
)) {
7120 * the specific check for 0xffffffff is a hack to preserve
7121 * binaray compatibilty in K64 with applications that discovered
7122 * that passing in a buf pointer and a size of -1 resulted in
7123 * just the size of the indicated extended attribute being returned.
7124 * this isn't part of the documented behavior, but because of the
7125 * original implemtation's check for "uap->size > 0", this behavior
7126 * was allowed. In K32 that check turned into a signed comparison
7127 * even though uap->size is unsigned... in K64, we blow by that
7128 * check because uap->size is unsigned and doesn't get sign smeared
7129 * in the munger for a 32 bit user app. we also need to add a
7130 * check to limit the maximum size of the buffer being passed in...
7131 * unfortunately, the underlying fileystems seem to just malloc
7132 * the requested size even if the actual extended attribute is tiny.
7133 * because that malloc is for kernel wired memory, we have to put a
7136 * U32 running on K64 will yield 0x00000000ffffffff for uap->size
7137 * U64 running on K64 will yield -1 (64 bits wide)
7138 * U32/U64 running on K32 will yield -1 (32 bits wide)
7140 if (uap
->size
== 0xffffffff || uap
->size
== (size_t)-1)
7143 if (uap
->size
> (size_t)XATTR_MAXSIZE
)
7144 uap
->size
= XATTR_MAXSIZE
;
7147 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
7148 &uio_buf
[0], sizeof(uio_buf
));
7149 uio_addiov(auio
, uap
->value
, uap
->size
);
7152 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, ctx
);
7157 *retval
= uap
->size
- uio_resid(auio
);
7159 *retval
= (user_ssize_t
)attrsize
;
7166 * Retrieve the data of an extended attribute.
7169 fgetxattr(proc_t p
, struct fgetxattr_args
*uap
, user_ssize_t
*retval
)
7172 char attrname
[XATTR_MAXNAMELEN
+1];
7174 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
7175 size_t attrsize
= 0;
7178 char uio_buf
[ UIO_SIZEOF(1) ];
7180 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
7183 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
7186 if ( (error
= vnode_getwithref(vp
)) ) {
7190 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
7193 if (xattr_protected(attrname
)) {
7197 if (uap
->value
&& uap
->size
> 0) {
7198 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
7199 &uio_buf
[0], sizeof(uio_buf
));
7200 uio_addiov(auio
, uap
->value
, uap
->size
);
7203 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, vfs_context_current());
7205 (void)vnode_put(vp
);
7209 *retval
= uap
->size
- uio_resid(auio
);
7211 *retval
= (user_ssize_t
)attrsize
;
7217 * Set the data of an extended attribute.
7220 setxattr(proc_t p
, struct setxattr_args
*uap
, int *retval
)
7223 struct nameidata nd
;
7224 char attrname
[XATTR_MAXNAMELEN
+1];
7225 vfs_context_t ctx
= vfs_context_current();
7227 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
7229 u_int32_t nameiflags
;
7231 char uio_buf
[ UIO_SIZEOF(1) ];
7233 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
7236 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
7239 if (xattr_protected(attrname
))
7241 if (uap
->size
!= 0 && uap
->value
== 0) {
7245 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
7246 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, ctx
);
7247 if ((error
= namei(&nd
))) {
7253 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
7254 &uio_buf
[0], sizeof(uio_buf
));
7255 uio_addiov(auio
, uap
->value
, uap
->size
);
7257 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, ctx
);
7260 add_fsevent(FSE_XATTR_MODIFIED
, ctx
,
7271 * Set the data of an extended attribute.
7274 fsetxattr(proc_t p
, struct fsetxattr_args
*uap
, int *retval
)
7277 char attrname
[XATTR_MAXNAMELEN
+1];
7279 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
7282 char uio_buf
[ UIO_SIZEOF(1) ];
7283 vfs_context_t ctx
= vfs_context_current();
7285 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
7288 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
7291 if (xattr_protected(attrname
))
7293 if (uap
->size
!= 0 && uap
->value
== 0) {
7296 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
7299 if ( (error
= vnode_getwithref(vp
)) ) {
7303 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
7304 &uio_buf
[0], sizeof(uio_buf
));
7305 uio_addiov(auio
, uap
->value
, uap
->size
);
7307 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, vfs_context_current());
7310 add_fsevent(FSE_XATTR_MODIFIED
, ctx
,
7322 * Remove an extended attribute.
7323 * XXX Code duplication here.
7326 removexattr(proc_t p
, struct removexattr_args
*uap
, int *retval
)
7329 struct nameidata nd
;
7330 char attrname
[XATTR_MAXNAMELEN
+1];
7331 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
7332 vfs_context_t ctx
= vfs_context_current();
7334 u_int32_t nameiflags
;
7337 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
7340 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
7344 if (xattr_protected(attrname
))
7346 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
7347 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, ctx
);
7348 if ((error
= namei(&nd
))) {
7354 error
= vn_removexattr(vp
, attrname
, uap
->options
, ctx
);
7357 add_fsevent(FSE_XATTR_REMOVED
, ctx
,
7368 * Remove an extended attribute.
7369 * XXX Code duplication here.
7372 fremovexattr(__unused proc_t p
, struct fremovexattr_args
*uap
, int *retval
)
7375 char attrname
[XATTR_MAXNAMELEN
+1];
7378 vfs_context_t ctx
= vfs_context_current();
7380 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
7383 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
7387 if (xattr_protected(attrname
))
7389 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
7392 if ( (error
= vnode_getwithref(vp
)) ) {
7397 error
= vn_removexattr(vp
, attrname
, uap
->options
, vfs_context_current());
7400 add_fsevent(FSE_XATTR_REMOVED
, ctx
,
7412 * Retrieve the list of extended attribute names.
7413 * XXX Code duplication here.
7416 listxattr(proc_t p
, struct listxattr_args
*uap
, user_ssize_t
*retval
)
7419 struct nameidata nd
;
7420 vfs_context_t ctx
= vfs_context_current();
7422 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
7423 size_t attrsize
= 0;
7424 u_int32_t nameiflags
;
7426 char uio_buf
[ UIO_SIZEOF(1) ];
7428 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
7431 nameiflags
= ((uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
) | NOTRIGGER
;
7432 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, ctx
);
7433 if ((error
= namei(&nd
))) {
7438 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
7439 auio
= uio_createwithbuffer(1, 0, spacetype
,
7440 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
7441 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
7444 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, ctx
);
7448 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
7450 *retval
= (user_ssize_t
)attrsize
;
7456 * Retrieve the list of extended attribute names.
7457 * XXX Code duplication here.
7460 flistxattr(proc_t p
, struct flistxattr_args
*uap
, user_ssize_t
*retval
)
7464 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
7465 size_t attrsize
= 0;
7467 char uio_buf
[ UIO_SIZEOF(1) ];
7469 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
7472 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
7475 if ( (error
= vnode_getwithref(vp
)) ) {
7479 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
7480 auio
= uio_createwithbuffer(1, 0, spacetype
,
7481 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
7482 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
7485 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, vfs_context_current());
7490 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
7492 *retval
= (user_ssize_t
)attrsize
;
7498 * Obtain the full pathname of a file system object by id.
7500 * This is a private SPI used by the File Manager.
7504 fsgetpath(__unused proc_t p
, struct fsgetpath_args
*uap
, user_ssize_t
*retval
)
7507 struct mount
*mp
= NULL
;
7508 vfs_context_t ctx
= vfs_context_current();
7515 if ((error
= copyin(uap
->fsid
, (caddr_t
)&fsid
, sizeof(fsid
)))) {
7518 AUDIT_ARG(value32
, fsid
.val
[0]);
7519 AUDIT_ARG(value64
, uap
->objid
);
7520 /* Restrict output buffer size for now. */
7521 if (uap
->bufsize
> PAGE_SIZE
) {
7524 MALLOC(realpath
, char *, uap
->bufsize
, M_TEMP
, M_WAITOK
);
7525 if (realpath
== NULL
) {
7528 /* Find the target mountpoint. */
7529 if ((mp
= mount_lookupby_volfsid(fsid
.val
[0], 1)) == NULL
) {
7530 error
= ENOTSUP
; /* unexpected failure */
7533 /* Find the target vnode. */
7534 if (uap
->objid
== 2) {
7535 error
= VFS_ROOT(mp
, &vp
, ctx
);
7537 error
= VFS_VGET(mp
, (ino64_t
)uap
->objid
, &vp
, ctx
);
7543 /* Obtain the absolute path to this vnode. */
7544 bpflags
= vfs_context_suser(ctx
) ? BUILDPATH_CHECKACCESS
: 0;
7545 error
= build_path(vp
, realpath
, uap
->bufsize
, &length
, bpflags
, ctx
);
7550 AUDIT_ARG(text
, realpath
);
7551 error
= copyout((caddr_t
)realpath
, uap
->buf
, length
);
7553 *retval
= (user_ssize_t
)length
; /* may be superseded by error */
7556 FREE(realpath
, M_TEMP
);
7562 * Common routine to handle various flavors of statfs data heading out
7565 * Returns: 0 Success
7569 munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
7570 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
7571 boolean_t partial_copy
)
7574 int my_size
, copy_size
;
7577 struct user64_statfs sfs
;
7578 my_size
= copy_size
= sizeof(sfs
);
7579 bzero(&sfs
, my_size
);
7580 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
7581 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
7582 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
7583 sfs
.f_bsize
= (user64_long_t
)sfsp
->f_bsize
;
7584 sfs
.f_iosize
= (user64_long_t
)sfsp
->f_iosize
;
7585 sfs
.f_blocks
= (user64_long_t
)sfsp
->f_blocks
;
7586 sfs
.f_bfree
= (user64_long_t
)sfsp
->f_bfree
;
7587 sfs
.f_bavail
= (user64_long_t
)sfsp
->f_bavail
;
7588 sfs
.f_files
= (user64_long_t
)sfsp
->f_files
;
7589 sfs
.f_ffree
= (user64_long_t
)sfsp
->f_ffree
;
7590 sfs
.f_fsid
= sfsp
->f_fsid
;
7591 sfs
.f_owner
= sfsp
->f_owner
;
7592 strlcpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
);
7593 strlcpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
);
7594 strlcpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
);
7597 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
7599 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
7602 struct user32_statfs sfs
;
7604 my_size
= copy_size
= sizeof(sfs
);
7605 bzero(&sfs
, my_size
);
7607 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
7608 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
7609 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
7612 * It's possible for there to be more than 2^^31 blocks in the filesystem, so we
7613 * have to fudge the numbers here in that case. We inflate the blocksize in order
7614 * to reflect the filesystem size as best we can.
7616 if ((sfsp
->f_blocks
> INT_MAX
)
7617 /* Hack for 4061702 . I think the real fix is for Carbon to
7618 * look for some volume capability and not depend on hidden
7619 * semantics agreed between a FS and carbon.
7620 * f_blocks, f_bfree, and f_bavail set to -1 is the trigger
7621 * for Carbon to set bNoVolumeSizes volume attribute.
7622 * Without this the webdavfs files cannot be copied onto
7623 * disk as they look huge. This change should not affect
7624 * XSAN as they should not setting these to -1..
7626 && (sfsp
->f_blocks
!= 0xffffffffffffffffULL
)
7627 && (sfsp
->f_bfree
!= 0xffffffffffffffffULL
)
7628 && (sfsp
->f_bavail
!= 0xffffffffffffffffULL
)) {
7632 * Work out how far we have to shift the block count down to make it fit.
7633 * Note that it's possible to have to shift so far that the resulting
7634 * blocksize would be unreportably large. At that point, we will clip
7635 * any values that don't fit.
7637 * For safety's sake, we also ensure that f_iosize is never reported as
7638 * being smaller than f_bsize.
7640 for (shift
= 0; shift
< 32; shift
++) {
7641 if ((sfsp
->f_blocks
>> shift
) <= INT_MAX
)
7643 if ((sfsp
->f_bsize
<< (shift
+ 1)) > INT_MAX
)
7646 #define __SHIFT_OR_CLIP(x, s) ((((x) >> (s)) > INT_MAX) ? INT_MAX : ((x) >> (s)))
7647 sfs
.f_blocks
= (user32_long_t
)__SHIFT_OR_CLIP(sfsp
->f_blocks
, shift
);
7648 sfs
.f_bfree
= (user32_long_t
)__SHIFT_OR_CLIP(sfsp
->f_bfree
, shift
);
7649 sfs
.f_bavail
= (user32_long_t
)__SHIFT_OR_CLIP(sfsp
->f_bavail
, shift
);
7650 #undef __SHIFT_OR_CLIP
7651 sfs
.f_bsize
= (user32_long_t
)(sfsp
->f_bsize
<< shift
);
7652 sfs
.f_iosize
= lmax(sfsp
->f_iosize
, sfsp
->f_bsize
);
7654 /* filesystem is small enough to be reported honestly */
7655 sfs
.f_bsize
= (user32_long_t
)sfsp
->f_bsize
;
7656 sfs
.f_iosize
= (user32_long_t
)sfsp
->f_iosize
;
7657 sfs
.f_blocks
= (user32_long_t
)sfsp
->f_blocks
;
7658 sfs
.f_bfree
= (user32_long_t
)sfsp
->f_bfree
;
7659 sfs
.f_bavail
= (user32_long_t
)sfsp
->f_bavail
;
7661 sfs
.f_files
= (user32_long_t
)sfsp
->f_files
;
7662 sfs
.f_ffree
= (user32_long_t
)sfsp
->f_ffree
;
7663 sfs
.f_fsid
= sfsp
->f_fsid
;
7664 sfs
.f_owner
= sfsp
->f_owner
;
7665 strlcpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
);
7666 strlcpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
);
7667 strlcpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
);
7670 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
7672 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
7675 if (sizep
!= NULL
) {
7682 * copy stat structure into user_stat structure.
7684 void munge_user64_stat(struct stat
*sbp
, struct user64_stat
*usbp
)
7686 bzero(usbp
, sizeof(*usbp
));
7688 usbp
->st_dev
= sbp
->st_dev
;
7689 usbp
->st_ino
= sbp
->st_ino
;
7690 usbp
->st_mode
= sbp
->st_mode
;
7691 usbp
->st_nlink
= sbp
->st_nlink
;
7692 usbp
->st_uid
= sbp
->st_uid
;
7693 usbp
->st_gid
= sbp
->st_gid
;
7694 usbp
->st_rdev
= sbp
->st_rdev
;
7695 #ifndef _POSIX_C_SOURCE
7696 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
7697 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
7698 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
7699 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
7700 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
7701 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
7703 usbp
->st_atime
= sbp
->st_atime
;
7704 usbp
->st_atimensec
= sbp
->st_atimensec
;
7705 usbp
->st_mtime
= sbp
->st_mtime
;
7706 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
7707 usbp
->st_ctime
= sbp
->st_ctime
;
7708 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
7710 usbp
->st_size
= sbp
->st_size
;
7711 usbp
->st_blocks
= sbp
->st_blocks
;
7712 usbp
->st_blksize
= sbp
->st_blksize
;
7713 usbp
->st_flags
= sbp
->st_flags
;
7714 usbp
->st_gen
= sbp
->st_gen
;
7715 usbp
->st_lspare
= sbp
->st_lspare
;
7716 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
7717 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];
7720 void munge_user32_stat(struct stat
*sbp
, struct user32_stat
*usbp
)
7722 bzero(usbp
, sizeof(*usbp
));
7724 usbp
->st_dev
= sbp
->st_dev
;
7725 usbp
->st_ino
= sbp
->st_ino
;
7726 usbp
->st_mode
= sbp
->st_mode
;
7727 usbp
->st_nlink
= sbp
->st_nlink
;
7728 usbp
->st_uid
= sbp
->st_uid
;
7729 usbp
->st_gid
= sbp
->st_gid
;
7730 usbp
->st_rdev
= sbp
->st_rdev
;
7731 #ifndef _POSIX_C_SOURCE
7732 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
7733 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
7734 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
7735 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
7736 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
7737 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
7739 usbp
->st_atime
= sbp
->st_atime
;
7740 usbp
->st_atimensec
= sbp
->st_atimensec
;
7741 usbp
->st_mtime
= sbp
->st_mtime
;
7742 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
7743 usbp
->st_ctime
= sbp
->st_ctime
;
7744 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
7746 usbp
->st_size
= sbp
->st_size
;
7747 usbp
->st_blocks
= sbp
->st_blocks
;
7748 usbp
->st_blksize
= sbp
->st_blksize
;
7749 usbp
->st_flags
= sbp
->st_flags
;
7750 usbp
->st_gen
= sbp
->st_gen
;
7751 usbp
->st_lspare
= sbp
->st_lspare
;
7752 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
7753 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];
7757 * copy stat64 structure into user_stat64 structure.
7759 void munge_user64_stat64(struct stat64
*sbp
, struct user64_stat64
*usbp
)
7761 bzero(usbp
, sizeof(*usbp
));
7763 usbp
->st_dev
= sbp
->st_dev
;
7764 usbp
->st_ino
= sbp
->st_ino
;
7765 usbp
->st_mode
= sbp
->st_mode
;
7766 usbp
->st_nlink
= sbp
->st_nlink
;
7767 usbp
->st_uid
= sbp
->st_uid
;
7768 usbp
->st_gid
= sbp
->st_gid
;
7769 usbp
->st_rdev
= sbp
->st_rdev
;
7770 #ifndef _POSIX_C_SOURCE
7771 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
7772 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
7773 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
7774 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
7775 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
7776 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
7777 usbp
->st_birthtimespec
.tv_sec
= sbp
->st_birthtimespec
.tv_sec
;
7778 usbp
->st_birthtimespec
.tv_nsec
= sbp
->st_birthtimespec
.tv_nsec
;
7780 usbp
->st_atime
= sbp
->st_atime
;
7781 usbp
->st_atimensec
= sbp
->st_atimensec
;
7782 usbp
->st_mtime
= sbp
->st_mtime
;
7783 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
7784 usbp
->st_ctime
= sbp
->st_ctime
;
7785 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
7786 usbp
->st_birthtime
= sbp
->st_birthtime
;
7787 usbp
->st_birthtimensec
= sbp
->st_birthtimensec
;
7789 usbp
->st_size
= sbp
->st_size
;
7790 usbp
->st_blocks
= sbp
->st_blocks
;
7791 usbp
->st_blksize
= sbp
->st_blksize
;
7792 usbp
->st_flags
= sbp
->st_flags
;
7793 usbp
->st_gen
= sbp
->st_gen
;
7794 usbp
->st_lspare
= sbp
->st_lspare
;
7795 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
7796 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];
7799 void munge_user32_stat64(struct stat64
*sbp
, struct user32_stat64
*usbp
)
7801 bzero(usbp
, sizeof(*usbp
));
7803 usbp
->st_dev
= sbp
->st_dev
;
7804 usbp
->st_ino
= sbp
->st_ino
;
7805 usbp
->st_mode
= sbp
->st_mode
;
7806 usbp
->st_nlink
= sbp
->st_nlink
;
7807 usbp
->st_uid
= sbp
->st_uid
;
7808 usbp
->st_gid
= sbp
->st_gid
;
7809 usbp
->st_rdev
= sbp
->st_rdev
;
7810 #ifndef _POSIX_C_SOURCE
7811 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
7812 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
7813 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
7814 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
7815 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
7816 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
7817 usbp
->st_birthtimespec
.tv_sec
= sbp
->st_birthtimespec
.tv_sec
;
7818 usbp
->st_birthtimespec
.tv_nsec
= sbp
->st_birthtimespec
.tv_nsec
;
7820 usbp
->st_atime
= sbp
->st_atime
;
7821 usbp
->st_atimensec
= sbp
->st_atimensec
;
7822 usbp
->st_mtime
= sbp
->st_mtime
;
7823 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
7824 usbp
->st_ctime
= sbp
->st_ctime
;
7825 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
7826 usbp
->st_birthtime
= sbp
->st_birthtime
;
7827 usbp
->st_birthtimensec
= sbp
->st_birthtimensec
;
7829 usbp
->st_size
= sbp
->st_size
;
7830 usbp
->st_blocks
= sbp
->st_blocks
;
7831 usbp
->st_blksize
= sbp
->st_blksize
;
7832 usbp
->st_flags
= sbp
->st_flags
;
7833 usbp
->st_gen
= sbp
->st_gen
;
7834 usbp
->st_lspare
= sbp
->st_lspare
;
7835 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
7836 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];