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/ubc_internal.h>
99 #include <machine/cons.h>
100 #include <machine/limits.h>
101 #include <miscfs/specfs/specdev.h>
102 #include <miscfs/union/union.h>
104 #include <bsm/audit_kernel.h>
105 #include <bsm/audit_kevents.h>
107 #include <mach/mach_types.h>
108 #include <kern/kern_types.h>
109 #include <kern/kalloc.h>
111 #include <vm/vm_pageout.h>
113 #include <libkern/OSAtomic.h>
116 #include <security/mac.h>
117 #include <security/mac_framework.h>
121 #define GET_PATH(x) \
122 (x) = get_pathbuff();
123 #define RELEASE_PATH(x) \
126 #define GET_PATH(x) \
127 MALLOC_ZONE((x), char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
128 #define RELEASE_PATH(x) \
129 FREE_ZONE((x), MAXPATHLEN, M_NAMEI);
130 #endif /* CONFIG_FSE */
132 /* struct for checkdirs iteration */
137 /* callback for checkdirs iteration */
138 static int checkdirs_callback(proc_t p
, void * arg
);
140 static int change_dir(struct nameidata
*ndp
, vfs_context_t ctx
);
141 static int checkdirs(vnode_t olddp
, vfs_context_t ctx
);
142 void enablequotas(struct mount
*mp
, vfs_context_t ctx
);
143 static int getfsstat_callback(mount_t mp
, void * arg
);
144 static int getutimes(user_addr_t usrtvp
, struct timespec
*tsp
);
145 static int setutimes(vfs_context_t ctx
, vnode_t vp
, const struct timespec
*ts
, int nullflag
);
146 static int sync_callback(mount_t
, void *);
147 static int munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
148 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
149 boolean_t partial_copy
);
150 static int statfs64_common(struct mount
*mp
, struct vfsstatfs
*sfsp
, user_addr_t bufp
);
151 int (*union_dircheckp
)(struct vnode
**, struct fileproc
*, vfs_context_t
);
154 int sync_internal(void);
157 int open1(vfs_context_t
, struct nameidata
*, int, struct vnode_attr
*, register_t
*);
160 int unlink1(vfs_context_t
, struct nameidata
*, int);
163 #ifdef __APPLE_API_OBSOLETE
165 int fd
; /* file descriptor of the target file */
166 struct vstat
*vsb
; /* vstat structure for returned info */
169 const char *path
; /* pathname of the target file */
170 struct vstat
*vsb
; /* vstat structure for returned info */
172 struct mkcomplex_args
{
173 const char *path
; /* pathname of the file to be created */
174 mode_t mode
; /* access mode for the newly created file */
175 u_long type
; /* format of the complex file */
178 const char *path
; /* pathname of the target file */
179 struct vstat
*vsb
; /* vstat structure for returned info */
182 int fstatv(proc_t p
, struct fstatv_args
*uap
, register_t
*retval
);
183 int lstatv(proc_t p
, struct lstatv_args
*uap
, register_t
*retval
);
184 int mkcomplex(proc_t p
, struct mkcomplex_args
*uap
, register_t
*retval
);
185 int statv(proc_t p
, struct statv_args
*uap
, register_t
*retval
);
187 #endif /* __APPLE_API_OBSOLETE */
190 * incremented each time a mount or unmount operation occurs
191 * used to invalidate the cached value of the rootvp in the
192 * mount structure utilized by cache_lookup_path
194 int mount_generation
= 0;
196 /* counts number of mount and unmount operations */
197 unsigned int vfs_nummntops
=0;
199 extern struct fileops vnops
;
200 extern errno_t
rmdir_remove_orphaned_appleDouble(vnode_t
, vfs_context_t
, int *);
204 * Virtual File System System Calls
208 * Mount a file system.
212 mount(proc_t p
, struct mount_args
*uap
, __unused register_t
*retval
)
214 struct __mac_mount_args muap
;
216 muap
.type
= uap
->type
;
217 muap
.path
= uap
->path
;
218 muap
.flags
= uap
->flags
;
219 muap
.data
= uap
->data
;
220 muap
.mac_p
= USER_ADDR_NULL
;
221 return (__mac_mount(p
, &muap
, retval
));
225 __mac_mount(struct proc
*p
, register struct __mac_mount_args
*uap
, __unused register_t
*retval
)
228 struct vnode
*devvp
= NULLVP
;
229 struct vnode
*device_vnode
= NULLVP
;
234 struct vfstable
*vfsp
= (struct vfstable
*)0;
236 struct vnode_attr va
;
237 vfs_context_t ctx
= vfs_context_current();
239 struct nameidata nd1
;
240 char fstypename
[MFSNAMELEN
];
242 user_addr_t devpath
= USER_ADDR_NULL
;
243 user_addr_t fsmountargs
= uap
->data
;
248 boolean_t is_rwlock_locked
= FALSE
;
250 AUDIT_ARG(fflags
, uap
->flags
);
252 is_64bit
= proc_is64bit(p
);
255 * Get vnode to be covered
257 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
258 UIO_USERSPACE
, uap
->path
, ctx
);
264 if ((vp
->v_flag
& VROOT
) &&
265 (vp
->v_mount
->mnt_flag
& MNT_ROOTFS
))
266 uap
->flags
|= MNT_UPDATE
;
268 error
= copyinstr(uap
->type
, fstypename
, MFSNAMELEN
, &dummy
);
272 if (uap
->flags
& MNT_UPDATE
) {
273 if ((vp
->v_flag
& VROOT
) == 0) {
279 /* unmount in progress return error */
281 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
287 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
288 is_rwlock_locked
= TRUE
;
290 * We only allow the filesystem to be reloaded if it
291 * is currently mounted read-only.
293 if ((uap
->flags
& MNT_RELOAD
) &&
294 ((mp
->mnt_flag
& MNT_RDONLY
) == 0)) {
299 * Only root, or the user that did the original mount is
300 * permitted to update it.
302 if (mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(vfs_context_ucred(ctx
)) &&
303 (error
= suser(vfs_context_ucred(ctx
), &p
->p_acflag
))) {
307 error
= mac_mount_check_remount(ctx
, mp
);
309 lck_rw_done(&mp
->mnt_rwlock
);
314 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV,
315 * and MNT_NOEXEC if mount point is already MNT_NOEXEC.
317 if (suser(vfs_context_ucred(ctx
), NULL
)) {
318 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
319 if (mp
->mnt_flag
& MNT_NOEXEC
)
320 uap
->flags
|= MNT_NOEXEC
;
325 uap
->flags
& (MNT_RELOAD
| MNT_FORCE
| MNT_UPDATE
);
327 vfsp
= mp
->mnt_vtable
;
331 * If the user is not root, ensure that they own the directory
332 * onto which we are attempting to mount.
335 VATTR_WANTED(&va
, va_uid
);
336 if ((error
= vnode_getattr(vp
, &va
, ctx
)) ||
337 (va
.va_uid
!= kauth_cred_getuid(vfs_context_ucred(ctx
)) &&
338 (error
= suser(vfs_context_ucred(ctx
), &p
->p_acflag
)))) {
342 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV, and
343 * 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 (vp
->v_mount
->mnt_flag
& MNT_NOEXEC
)
348 uap
->flags
|= MNT_NOEXEC
;
350 if ( (error
= VNOP_FSYNC(vp
, MNT_WAIT
, ctx
)) )
353 if ( (error
= buf_invalidateblks(vp
, BUF_WRITE_DATA
, 0, 0)) )
356 if (vp
->v_type
!= VDIR
) {
361 /* XXXAUDIT: Should we capture the type on the error path as well? */
362 AUDIT_ARG(text
, fstypename
);
364 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
365 if (!strncmp(vfsp
->vfc_name
, fstypename
, MFSNAMELEN
))
373 error
= mac_mount_check_mount(ctx
, vp
,
374 &nd
.ni_cnd
, vfsp
->vfc_name
);
378 if (ISSET(vp
->v_flag
, VMOUNT
) && (vp
->v_mountedhere
!= NULL
)) {
383 SET(vp
->v_flag
, VMOUNT
);
387 * Allocate and initialize the filesystem.
389 MALLOC_ZONE(mp
, struct mount
*, (u_long
)sizeof(struct mount
),
391 bzero((char *)mp
, (u_long
)sizeof(struct mount
));
394 /* Initialize the default IO constraints */
395 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
396 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
397 mp
->mnt_maxsegreadsize
= mp
->mnt_maxreadcnt
;
398 mp
->mnt_maxsegwritesize
= mp
->mnt_maxwritecnt
;
399 mp
->mnt_devblocksize
= DEV_BSIZE
;
400 mp
->mnt_alignmentmask
= PAGE_MASK
;
402 mp
->mnt_realrootvp
= NULLVP
;
403 mp
->mnt_authcache_ttl
= CACHED_LOOKUP_RIGHT_TTL
;
405 TAILQ_INIT(&mp
->mnt_vnodelist
);
406 TAILQ_INIT(&mp
->mnt_workerqueue
);
407 TAILQ_INIT(&mp
->mnt_newvnodes
);
409 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
410 is_rwlock_locked
= TRUE
;
411 mp
->mnt_op
= vfsp
->vfc_vfsops
;
412 mp
->mnt_vtable
= vfsp
;
414 vfsp
->vfc_refcount
++;
416 //mp->mnt_stat.f_type = vfsp->vfc_typenum;
417 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
418 strncpy(mp
->mnt_vfsstat
.f_fstypename
, vfsp
->vfc_name
, MFSTYPENAMELEN
);
419 strncpy(mp
->mnt_vfsstat
.f_mntonname
, nd
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
420 mp
->mnt_vnodecovered
= vp
;
421 mp
->mnt_vfsstat
.f_owner
= kauth_cred_getuid(vfs_context_ucred(ctx
));
422 mp
->mnt_devbsdunit
= LOWPRI_MAX_NUM_DEV
- 1;
424 /* XXX 3762912 hack to support HFS filesystem 'owner' - filesystem may update later */
425 vfs_setowner(mp
, KAUTH_UID_NONE
, KAUTH_GID_NONE
);
429 * Set the mount level flags.
431 if (uap
->flags
& MNT_RDONLY
)
432 mp
->mnt_flag
|= MNT_RDONLY
;
433 else if (mp
->mnt_flag
& MNT_RDONLY
)
434 mp
->mnt_kern_flag
|= MNTK_WANTRDWR
;
435 mp
->mnt_flag
&= ~(MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
436 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
437 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
|
438 MNT_DEFWRITE
| MNT_NOATIME
| MNT_QUARANTINE
);
439 mp
->mnt_flag
|= uap
->flags
& (MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
440 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
441 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
|
442 MNT_DEFWRITE
| MNT_NOATIME
| MNT_QUARANTINE
);
445 if (uap
->flags
& MNT_MULTILABEL
) {
446 if (vfsp
->vfc_vfsflags
& VFC_VFSNOMACLABEL
) {
450 mp
->mnt_flag
|= MNT_MULTILABEL
;
454 if (vfsp
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
456 if ( (error
= copyin(fsmountargs
, (caddr_t
)&devpath
, sizeof(devpath
))) )
458 fsmountargs
+= sizeof(devpath
);
461 if ( (error
= copyin(fsmountargs
, (caddr_t
)&tmp
, sizeof(tmp
))) )
463 /* munge into LP64 addr */
464 devpath
= CAST_USER_ADDR_T(tmp
);
465 fsmountargs
+= sizeof(tmp
);
468 /* if it is not update and device name needs to be parsed */
470 NDINIT(&nd1
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, devpath
, ctx
);
471 if ( (error
= namei(&nd1
)) )
474 strncpy(mp
->mnt_vfsstat
.f_mntfromname
, nd1
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
479 if (devvp
->v_type
!= VBLK
) {
483 if (major(devvp
->v_rdev
) >= nblkdev
) {
488 * If mount by non-root, then verify that user has necessary
489 * permissions on the device.
491 if (suser(vfs_context_ucred(ctx
), NULL
) != 0) {
492 accessmode
= KAUTH_VNODE_READ_DATA
;
493 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
494 accessmode
|= KAUTH_VNODE_WRITE_DATA
;
495 if ((error
= vnode_authorize(devvp
, NULL
, accessmode
, ctx
)) != 0)
499 if (devpath
&& ((uap
->flags
& MNT_UPDATE
) == 0)) {
500 if ( (error
= vnode_ref(devvp
)) )
503 * Disallow multiple mounts of the same device.
504 * Disallow mounting of a device that is currently in use
505 * (except for root, which might share swap device for miniroot).
506 * Flush out any old buffers remaining from a previous use.
508 if ( (error
= vfs_mountedon(devvp
)) )
511 if (vcount(devvp
) > 1 && !(vfs_flags(mp
) & MNT_ROOTFS
)) {
515 if ( (error
= VNOP_FSYNC(devvp
, MNT_WAIT
, ctx
)) ) {
519 if ( (error
= buf_invalidateblks(devvp
, BUF_WRITE_DATA
, 0, 0)) )
522 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
524 error
= mac_vnode_check_open(ctx
,
526 ronly
? FREAD
: FREAD
|FWRITE
);
530 if ( (error
= VNOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, ctx
)) )
533 mp
->mnt_devvp
= devvp
;
534 device_vnode
= devvp
;
536 if ((mp
->mnt_flag
& MNT_RDONLY
) && (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)) {
538 * If upgrade to read-write by non-root, then verify
539 * that user has necessary permissions on the device.
541 device_vnode
= mp
->mnt_devvp
;
542 if (device_vnode
&& suser(vfs_context_ucred(ctx
), NULL
)) {
543 if ((error
= vnode_authorize(device_vnode
, NULL
,
544 KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, ctx
)) != 0)
548 device_vnode
= NULLVP
;
552 if ((uap
->flags
& MNT_UPDATE
) == 0) {
553 mac_mount_label_init(mp
);
554 mac_mount_label_associate(ctx
, mp
);
556 if (uap
->mac_p
!= USER_ADDR_NULL
) {
558 char *labelstr
= NULL
;
561 if ((uap
->flags
& MNT_UPDATE
) != 0) {
562 error
= mac_mount_check_label_update(
568 error
= copyin(uap
->mac_p
, &mac
, sizeof(mac
));
571 error
= copyin(uap
->mac_p
, &mac32
, sizeof(mac32
));
572 mac
.m_buflen
= mac32
.m_buflen
;
573 mac
.m_string
= CAST_USER_ADDR_T(mac32
.m_string
);
577 if ((mac
.m_buflen
> MAC_MAX_LABEL_BUF_LEN
) ||
578 (mac
.m_buflen
< 2)) {
582 MALLOC(labelstr
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
583 error
= copyinstr(mac
.m_string
, labelstr
, mac
.m_buflen
, &ulen
);
585 FREE(labelstr
, M_MACTEMP
);
588 AUDIT_ARG(mac_string
, labelstr
);
589 error
= mac_mount_label_internalize(mp
->mnt_mntlabel
, labelstr
);
590 FREE(labelstr
, M_MACTEMP
);
595 if (device_vnode
!= NULL
) {
596 VNOP_IOCTL(device_vnode
, DKIOCGETBSDUNIT
, (caddr_t
)&mp
->mnt_devbsdunit
, 0, NULL
);
597 mp
->mnt_devbsdunit
%= LOWPRI_MAX_NUM_DEV
;
601 * Mount the filesystem.
603 error
= VFS_MOUNT(mp
, device_vnode
, fsmountargs
, ctx
);
605 if (uap
->flags
& MNT_UPDATE
) {
606 if (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)
607 mp
->mnt_flag
&= ~MNT_RDONLY
;
609 (MNT_UPDATE
| MNT_RELOAD
| MNT_FORCE
);
610 mp
->mnt_kern_flag
&=~ MNTK_WANTRDWR
;
613 vfs_event_signal(NULL
, VQ_UPDATE
, (intptr_t)NULL
);
614 lck_rw_done(&mp
->mnt_rwlock
);
615 is_rwlock_locked
= FALSE
;
617 enablequotas(mp
, ctx
);
621 * Put the new filesystem on the mount list after root.
624 struct vfs_attr vfsattr
;
626 if (vfs_flags(mp
) & MNT_MULTILABEL
) {
627 error
= VFS_ROOT(mp
, &rvp
, ctx
);
629 printf("%s() VFS_ROOT returned %d\n", __func__
, error
);
633 /* VFS_ROOT provides reference so needref = 0 */
634 error
= vnode_label(mp
, NULL
, rvp
, NULL
, 0, ctx
);
641 CLR(vp
->v_flag
, VMOUNT
);
642 vp
->v_mountedhere
= mp
;
646 * taking the name_cache_lock exclusively will
647 * insure that everyone is out of the fast path who
648 * might be trying to use a now stale copy of
649 * vp->v_mountedhere->mnt_realrootvp
650 * bumping mount_generation causes the cached values
659 error
= checkdirs(vp
, ctx
);
661 /* Unmount the filesystem as cdir/rdirs cannot be updated */
665 * there is no cleanup code here so I have made it void
666 * we need to revisit this
668 (void)VFS_START(mp
, 0, ctx
);
671 lck_rw_done(&mp
->mnt_rwlock
);
672 is_rwlock_locked
= FALSE
;
674 /* Check if this mounted file system supports EAs or named streams. */
675 /* Skip WebDAV file systems for now since they hang in VFS_GETATTR here. */
676 VFSATTR_INIT(&vfsattr
);
677 VFSATTR_WANTED(&vfsattr
, f_capabilities
);
678 if (strncmp(mp
->mnt_vfsstat
.f_fstypename
, "webdav", sizeof("webdav")) != 0 &&
679 vfs_getattr(mp
, &vfsattr
, ctx
) == 0 &&
680 VFSATTR_IS_SUPPORTED(&vfsattr
, f_capabilities
)) {
681 if ((vfsattr
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] & VOL_CAP_INT_EXTENDED_ATTR
) &&
682 (vfsattr
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] & VOL_CAP_INT_EXTENDED_ATTR
)) {
683 mp
->mnt_kern_flag
|= MNTK_EXTENDED_ATTRS
;
686 if ((vfsattr
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] & VOL_CAP_INT_NAMEDSTREAMS
) &&
687 (vfsattr
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] & VOL_CAP_INT_NAMEDSTREAMS
)) {
688 mp
->mnt_kern_flag
|= MNTK_NAMED_STREAMS
;
691 /* Check if this file system supports path from id lookups. */
692 if ((vfsattr
.f_capabilities
.capabilities
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_PATH_FROM_ID
) &&
693 (vfsattr
.f_capabilities
.valid
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_PATH_FROM_ID
)) {
694 mp
->mnt_kern_flag
|= MNTK_PATH_FROM_ID
;
695 } else if (mp
->mnt_flag
& MNT_DOVOLFS
) {
696 /* Legacy MNT_DOVOLFS flag also implies path from id lookups. */
697 mp
->mnt_kern_flag
|= MNTK_PATH_FROM_ID
;
700 if (mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSNATIVEXATTR
) {
701 mp
->mnt_kern_flag
|= MNTK_EXTENDED_ATTRS
;
703 if (mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSPREFLIGHT
) {
704 mp
->mnt_kern_flag
|= MNTK_UNMOUNT_PREFLIGHT
;
706 /* increment the operations count */
707 OSAddAtomic(1, (SInt32
*)&vfs_nummntops
);
708 enablequotas(mp
, ctx
);
711 device_vnode
->v_specflags
|= SI_MOUNTEDON
;
714 * cache the IO attributes for the underlying physical media...
715 * an error return indicates the underlying driver doesn't
716 * support all the queries necessary... however, reasonable
717 * defaults will have been set, so no reason to bail or care
719 vfs_init_io_attributes(device_vnode
, mp
);
722 /* Now that mount is setup, notify the listeners */
723 vfs_event_signal(NULL
, VQ_MOUNT
, (intptr_t)NULL
);
726 CLR(vp
->v_flag
, VMOUNT
);
729 mp
->mnt_vtable
->vfc_refcount
--;
733 VNOP_CLOSE(device_vnode
, ronly
? FREAD
: FREAD
|FWRITE
, ctx
);
734 vnode_rele(device_vnode
);
736 lck_rw_done(&mp
->mnt_rwlock
);
737 is_rwlock_locked
= FALSE
;
738 mount_lock_destroy(mp
);
740 mac_mount_label_destroy(mp
);
742 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
747 * drop I/O count on covered 'vp' and
748 * on the device vp if there was one
750 if (devpath
&& devvp
)
756 (void)VFS_UNMOUNT(mp
, MNT_FORCE
, ctx
);
757 if (device_vnode
!= NULLVP
) {
758 VNOP_CLOSE(device_vnode
, mp
->mnt_flag
& MNT_RDONLY
? FREAD
: FREAD
|FWRITE
,
763 vp
->v_mountedhere
= (mount_t
) 0;
767 if (devpath
&& ((uap
->flags
& MNT_UPDATE
) == 0))
770 if (devpath
&& devvp
)
773 /* Release mnt_rwlock only when it was taken */
774 if (is_rwlock_locked
== TRUE
) {
775 lck_rw_done(&mp
->mnt_rwlock
);
779 mac_mount_label_destroy(mp
);
782 vfsp
->vfc_refcount
--;
784 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
793 enablequotas(struct mount
*mp
, vfs_context_t ctx
)
795 struct nameidata qnd
;
797 char qfpath
[MAXPATHLEN
];
798 const char *qfname
= QUOTAFILENAME
;
799 const char *qfopsname
= QUOTAOPSNAME
;
800 const char *qfextension
[] = INITQFNAMES
;
802 /* XXX Shoulkd be an MNTK_ flag, instead of strncmp()'s */
803 if ((strncmp(mp
->mnt_vfsstat
.f_fstypename
, "hfs", sizeof("hfs")) != 0 )
804 && (strncmp( mp
->mnt_vfsstat
.f_fstypename
, "ufs", sizeof("ufs")) != 0))
808 * Enable filesystem disk quotas if necessary.
809 * We ignore errors as this should not interfere with final mount
811 for (type
=0; type
< MAXQUOTAS
; type
++) {
812 snprintf(qfpath
, sizeof(qfpath
), "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfopsname
, qfextension
[type
]);
813 NDINIT(&qnd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE32
, CAST_USER_ADDR_T(qfpath
), ctx
);
814 if (namei(&qnd
) != 0)
815 continue; /* option file to trigger quotas is not present */
816 vnode_put(qnd
.ni_vp
);
818 snprintf(qfpath
, sizeof(qfpath
), "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfname
, qfextension
[type
]);
820 (void) VFS_QUOTACTL(mp
, QCMD(Q_QUOTAON
, type
), 0, qfpath
, ctx
);
827 checkdirs_callback(proc_t p
, void * arg
)
829 struct cdirargs
* cdrp
= (struct cdirargs
* )arg
;
830 vnode_t olddp
= cdrp
->olddp
;
831 vnode_t newdp
= cdrp
->newdp
;
832 struct filedesc
*fdp
;
836 int cdir_changed
= 0;
837 int rdir_changed
= 0;
840 * XXX Also needs to iterate each thread in the process to see if it
841 * XXX is using a per-thread current working directory, and, if so,
842 * XXX update that as well.
847 if (fdp
== (struct filedesc
*)0) {
849 return(PROC_RETURNED
);
851 fdp_cvp
= fdp
->fd_cdir
;
852 fdp_rvp
= fdp
->fd_rdir
;
855 if (fdp_cvp
== olddp
) {
862 if (fdp_rvp
== olddp
) {
869 if (cdir_changed
|| rdir_changed
) {
871 fdp
->fd_cdir
= fdp_cvp
;
872 fdp
->fd_rdir
= fdp_rvp
;
875 return(PROC_RETURNED
);
881 * Scan all active processes to see if any of them have a current
882 * or root directory onto which the new filesystem has just been
883 * mounted. If so, replace them with the new mount point.
886 checkdirs(vnode_t olddp
, vfs_context_t ctx
)
892 struct uthread
* uth
= get_bsdthread_info(current_thread());
894 if (olddp
->v_usecount
== 1)
896 if (uth
!= (struct uthread
*)0)
897 uth
->uu_notrigger
= 1;
898 err
= VFS_ROOT(olddp
->v_mountedhere
, &newdp
, ctx
);
899 if (uth
!= (struct uthread
*)0)
900 uth
->uu_notrigger
= 0;
904 panic("mount: lost mount: error %d", err
);
911 /* do not block for exec/fork trans as the vp in cwd & rootdir are not changing */
912 proc_iterate(PROC_ALLPROCLIST
| PROC_NOWAITTRANS
, checkdirs_callback
, (void *)&cdr
, NULL
, NULL
);
914 if (rootvnode
== olddp
) {
926 * Unmount a file system.
928 * Note: unmount takes a path to the vnode mounted on as argument,
929 * not special file (as before).
933 unmount(__unused proc_t p
, struct unmount_args
*uap
, __unused register_t
*retval
)
939 vfs_context_t ctx
= vfs_context_current();
941 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
942 UIO_USERSPACE
, uap
->path
, ctx
);
951 error
= mac_mount_check_umount(ctx
, mp
);
958 * Must be the root of the filesystem
960 if ((vp
->v_flag
& VROOT
) == 0) {
966 /* safedounmount consumes the mount ref */
967 return (safedounmount(mp
, uap
->flags
, ctx
));
971 vfs_unmountbyfsid(fsid_t
* fsid
, int flags
, vfs_context_t ctx
)
975 mp
= mount_list_lookupby_fsid(fsid
, 0, 1);
976 if (mp
== (mount_t
)0) {
981 /* safedounmount consumes the mount ref */
982 return(safedounmount(mp
, flags
, ctx
));
987 * The mount struct comes with a mount ref which will be consumed.
988 * Do the actual file system unmount, prevent some common foot shooting.
991 safedounmount(struct mount
*mp
, int flags
, vfs_context_t ctx
)
994 proc_t p
= vfs_context_proc(ctx
);
997 * Only root, or the user that did the original mount is
998 * permitted to unmount this filesystem.
1000 if ((mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(kauth_cred_get())) &&
1001 (error
= suser(kauth_cred_get(), &p
->p_acflag
)))
1005 * Don't allow unmounting the root file system.
1007 if (mp
->mnt_flag
& MNT_ROOTFS
) {
1008 error
= EBUSY
; /* the root is always busy */
1012 return (dounmount(mp
, flags
, 1, ctx
));
1020 * Do the actual file system unmount.
1023 dounmount(struct mount
*mp
, int flags
, int withref
, vfs_context_t ctx
)
1025 vnode_t coveredvp
= (vnode_t
)0;
1028 int forcedunmount
= 0;
1030 struct vnode
*devvp
= NULLVP
;
1032 if (flags
& MNT_FORCE
)
1035 /* XXX post jaguar fix LK_DRAIN - then clean this up */
1036 if ((flags
& MNT_FORCE
)) {
1037 mp
->mnt_kern_flag
|= MNTK_FRCUNMOUNT
;
1038 mp
->mnt_lflag
|= MNT_LFORCE
;
1040 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
1041 mp
->mnt_lflag
|= MNT_LWAIT
;
1044 msleep((caddr_t
)mp
, &mp
->mnt_mlock
, (PVFS
| PDROP
), "dounmount", NULL
);
1046 * The prior unmount attempt has probably succeeded.
1047 * Do not dereference mp here - returning EBUSY is safest.
1051 mp
->mnt_kern_flag
|= MNTK_UNMOUNT
;
1052 mp
->mnt_lflag
|= MNT_LUNMOUNT
;
1053 mp
->mnt_flag
&=~ MNT_ASYNC
;
1055 * anyone currently in the fast path that
1056 * trips over the cached rootvp will be
1057 * dumped out and forced into the slow path
1058 * to regenerate a new cached value
1060 mp
->mnt_realrootvp
= NULLVP
;
1064 * taking the name_cache_lock exclusively will
1065 * insure that everyone is out of the fast path who
1066 * might be trying to use a now stale copy of
1067 * vp->v_mountedhere->mnt_realrootvp
1068 * bumping mount_generation causes the cached values
1073 name_cache_unlock();
1076 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
1080 fsevent_unmount(mp
); /* has to come first! */
1083 if (forcedunmount
== 0) {
1084 ubc_umount(mp
); /* release cached vnodes */
1085 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
1086 error
= VFS_SYNC(mp
, MNT_WAIT
, ctx
);
1089 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
1090 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
1091 mp
->mnt_lflag
&= ~MNT_LFORCE
;
1098 lflags
|= FORCECLOSE
;
1099 error
= vflush(mp
, NULLVP
, SKIPSWAP
| SKIPSYSTEM
| SKIPROOT
| lflags
);
1100 if ((forcedunmount
== 0) && error
) {
1102 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
1103 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
1104 mp
->mnt_lflag
&= ~MNT_LFORCE
;
1108 /* make sure there are no one in the mount iterations or lookup */
1109 mount_iterdrain(mp
);
1111 error
= VFS_UNMOUNT(mp
, flags
, ctx
);
1113 mount_iterreset(mp
);
1115 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
1116 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
1117 mp
->mnt_lflag
&= ~MNT_LFORCE
;
1121 /* increment the operations count */
1123 OSAddAtomic(1, (SInt32
*)&vfs_nummntops
);
1125 if ( mp
->mnt_devvp
&& mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
1126 /* hold an io reference and drop the usecount before close */
1127 devvp
= mp
->mnt_devvp
;
1128 vnode_clearmountedon(devvp
);
1129 vnode_getalways(devvp
);
1131 VNOP_CLOSE(devvp
, mp
->mnt_flag
& MNT_RDONLY
? FREAD
: FREAD
|FWRITE
,
1135 lck_rw_done(&mp
->mnt_rwlock
);
1136 mount_list_remove(mp
);
1137 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
1139 /* mark the mount point hook in the vp but not drop the ref yet */
1140 if ((coveredvp
= mp
->mnt_vnodecovered
) != NULLVP
) {
1141 vnode_getwithref(coveredvp
);
1142 vnode_lock_spin(coveredvp
);
1143 coveredvp
->v_mountedhere
= (struct mount
*)0;
1144 vnode_unlock(coveredvp
);
1145 vnode_put(coveredvp
);
1149 mp
->mnt_vtable
->vfc_refcount
--;
1150 mount_list_unlock();
1152 cache_purgevfs(mp
); /* remove cache entries for this file sys */
1153 vfs_event_signal(NULL
, VQ_UNMOUNT
, (intptr_t)NULL
);
1155 mp
->mnt_lflag
|= MNT_LDEAD
;
1157 if (mp
->mnt_lflag
& MNT_LWAIT
) {
1159 * do the wakeup here
1160 * in case we block in mount_refdrain
1161 * which will drop the mount lock
1162 * and allow anyone blocked in vfs_busy
1163 * to wakeup and see the LDEAD state
1165 mp
->mnt_lflag
&= ~MNT_LWAIT
;
1166 wakeup((caddr_t
)mp
);
1170 if (mp
->mnt_lflag
& MNT_LWAIT
) {
1171 mp
->mnt_lflag
&= ~MNT_LWAIT
;
1175 lck_rw_done(&mp
->mnt_rwlock
);
1178 wakeup((caddr_t
)mp
);
1180 if ((coveredvp
!= NULLVP
)) {
1181 vnode_getwithref(coveredvp
);
1182 vnode_rele(coveredvp
);
1183 vnode_lock_spin(coveredvp
);
1184 if(mp
->mnt_crossref
== 0) {
1185 vnode_unlock(coveredvp
);
1186 mount_lock_destroy(mp
);
1188 mac_mount_label_destroy(mp
);
1190 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
1192 coveredvp
->v_lflag
|= VL_MOUNTDEAD
;
1193 vnode_unlock(coveredvp
);
1195 vnode_put(coveredvp
);
1196 } else if (mp
->mnt_flag
& MNT_ROOTFS
) {
1197 mount_lock_destroy(mp
);
1199 mac_mount_label_destroy(mp
);
1201 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
1203 panic("dounmount: no coveredvp");
1209 mount_dropcrossref(mount_t mp
, vnode_t dp
, int need_put
)
1213 if (mp
->mnt_crossref
< 0)
1214 panic("mount cross refs -ve");
1215 if (((dp
->v_lflag
& VL_MOUNTDEAD
) == VL_MOUNTDEAD
) && (mp
->mnt_crossref
== 0)) {
1216 dp
->v_lflag
&= ~VL_MOUNTDEAD
;
1218 vnode_put_locked(dp
);
1220 mount_lock_destroy(mp
);
1222 mac_mount_label_destroy(mp
);
1224 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
1228 vnode_put_locked(dp
);
1234 * Sync each mounted filesystem.
1238 struct ctldebug debug0
= { "syncprt", &syncprt
};
1241 int print_vmpage_stat
=0;
1244 sync_callback(mount_t mp
, __unused
void * arg
)
1248 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
1249 asyncflag
= mp
->mnt_flag
& MNT_ASYNC
;
1250 mp
->mnt_flag
&= ~MNT_ASYNC
;
1251 VFS_SYNC(mp
, MNT_NOWAIT
, vfs_context_current());
1253 mp
->mnt_flag
|= MNT_ASYNC
;
1255 return(VFS_RETURNED
);
1259 extern unsigned int vp_pagein
, vp_pgodirty
, vp_pgoclean
;
1260 extern unsigned int dp_pgins
, dp_pgouts
;
1264 sync(__unused proc_t p
, __unused
struct sync_args
*uap
, __unused register_t
*retval
)
1267 vfs_iterate(LK_NOWAIT
, sync_callback
, (void *)0);
1269 if(print_vmpage_stat
) {
1270 vm_countdirtypages();
1271 printf("VP: %d: %d: %d: %d: %d\n", vp_pgodirty
, vp_pgoclean
, vp_pagein
,
1272 dp_pgins
, dp_pgouts
);
1278 #endif /* DIAGNOSTIC */
1283 * Change filesystem quotas.
1286 static int quotactl_funneled(proc_t p
, struct quotactl_args
*uap
, register_t
*retval
);
1289 quotactl(proc_t p
, struct quotactl_args
*uap
, register_t
*retval
)
1291 boolean_t funnel_state
;
1294 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
1295 error
= quotactl_funneled(p
, uap
, retval
);
1296 thread_funnel_set(kernel_flock
, funnel_state
);
1301 quotactl_funneled(proc_t p
, struct quotactl_args
*uap
, __unused register_t
*retval
)
1304 int error
, quota_cmd
, quota_status
;
1307 struct nameidata nd
;
1308 vfs_context_t ctx
= vfs_context_current();
1309 struct dqblk my_dqblk
;
1311 AUDIT_ARG(uid
, uap
->uid
, 0, 0, 0);
1312 AUDIT_ARG(cmd
, uap
->cmd
);
1313 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1314 UIO_USERSPACE
, uap
->path
, ctx
);
1318 mp
= nd
.ni_vp
->v_mount
;
1319 vnode_put(nd
.ni_vp
);
1322 /* copyin any data we will need for downstream code */
1323 quota_cmd
= uap
->cmd
>> SUBCMDSHIFT
;
1325 switch (quota_cmd
) {
1327 /* uap->arg specifies a file from which to take the quotas */
1328 fnamelen
= MAXPATHLEN
;
1329 datap
= kalloc(MAXPATHLEN
);
1330 error
= copyinstr(uap
->arg
, datap
, MAXPATHLEN
, &fnamelen
);
1333 /* uap->arg is a pointer to a dqblk structure. */
1334 datap
= (caddr_t
) &my_dqblk
;
1338 /* uap->arg is a pointer to a dqblk structure. */
1339 datap
= (caddr_t
) &my_dqblk
;
1340 if (proc_is64bit(p
)) {
1341 struct user_dqblk my_dqblk64
;
1342 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk64
, sizeof (my_dqblk64
));
1344 munge_dqblk(&my_dqblk
, &my_dqblk64
, FALSE
);
1348 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk
, sizeof (my_dqblk
));
1352 /* uap->arg is a pointer to an integer */
1353 datap
= (caddr_t
) "a_status
;
1361 error
= VFS_QUOTACTL(mp
, uap
->cmd
, uap
->uid
, datap
, ctx
);
1364 switch (quota_cmd
) {
1367 kfree(datap
, MAXPATHLEN
);
1370 /* uap->arg is a pointer to a dqblk structure we need to copy out to */
1372 if (proc_is64bit(p
)) {
1373 struct user_dqblk my_dqblk64
;
1374 munge_dqblk(&my_dqblk
, &my_dqblk64
, TRUE
);
1375 error
= copyout((caddr_t
)&my_dqblk64
, uap
->arg
, sizeof (my_dqblk64
));
1378 error
= copyout(datap
, uap
->arg
, sizeof (struct dqblk
));
1383 /* uap->arg is a pointer to an integer */
1385 error
= copyout(datap
, uap
->arg
, sizeof(quota_status
));
1396 quotactl(__unused proc_t p
, __unused
struct quotactl_args
*uap
, __unused register_t
*retval
)
1398 return (EOPNOTSUPP
);
1403 * Get filesystem statistics.
1405 * Returns: 0 Success
1407 * vfs_update_vfsstat:???
1408 * munge_statfs:EFAULT
1412 statfs(__unused proc_t p
, struct statfs_args
*uap
, __unused register_t
*retval
)
1415 struct vfsstatfs
*sp
;
1417 struct nameidata nd
;
1418 vfs_context_t ctx
= vfs_context_current();
1421 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
1422 UIO_USERSPACE
, uap
->path
, ctx
);
1428 sp
= &mp
->mnt_vfsstat
;
1431 error
= vfs_update_vfsstat(mp
, ctx
, VFS_USER_EVENT
);
1436 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1441 * Get filesystem statistics.
1445 fstatfs(__unused proc_t p
, struct fstatfs_args
*uap
, __unused register_t
*retval
)
1449 struct vfsstatfs
*sp
;
1452 AUDIT_ARG(fd
, uap
->fd
);
1454 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1457 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
1464 sp
= &mp
->mnt_vfsstat
;
1465 if ((error
= vfs_update_vfsstat(mp
,vfs_context_current(),VFS_USER_EVENT
)) != 0) {
1471 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1477 * Common routine to handle copying of statfs64 data to user space
1480 statfs64_common(struct mount
*mp
, struct vfsstatfs
*sfsp
, user_addr_t bufp
)
1483 struct statfs64 sfs
;
1485 bzero(&sfs
, sizeof(sfs
));
1487 sfs
.f_bsize
= sfsp
->f_bsize
;
1488 sfs
.f_iosize
= (int32_t)sfsp
->f_iosize
;
1489 sfs
.f_blocks
= sfsp
->f_blocks
;
1490 sfs
.f_bfree
= sfsp
->f_bfree
;
1491 sfs
.f_bavail
= sfsp
->f_bavail
;
1492 sfs
.f_files
= sfsp
->f_files
;
1493 sfs
.f_ffree
= sfsp
->f_ffree
;
1494 sfs
.f_fsid
= sfsp
->f_fsid
;
1495 sfs
.f_owner
= sfsp
->f_owner
;
1496 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
1497 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
1498 sfs
.f_fssubtype
= sfsp
->f_fssubtype
;
1499 strlcpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSTYPENAMELEN
);
1500 strlcpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MAXPATHLEN
);
1501 strlcpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MAXPATHLEN
);
1503 error
= copyout((caddr_t
)&sfs
, bufp
, sizeof(sfs
));
1509 * Get file system statistics in 64-bit mode
1512 statfs64(__unused
struct proc
*p
, struct statfs64_args
*uap
, __unused register_t
*retval
)
1515 struct vfsstatfs
*sp
;
1517 struct nameidata nd
;
1518 vfs_context_t ctxp
= vfs_context_current();
1521 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
1522 UIO_USERSPACE
, uap
->path
, ctxp
);
1528 sp
= &mp
->mnt_vfsstat
;
1531 error
= vfs_update_vfsstat(mp
, ctxp
, VFS_USER_EVENT
);
1536 error
= statfs64_common(mp
, sp
, uap
->buf
);
1542 * Get file system statistics in 64-bit mode
1545 fstatfs64(__unused
struct proc
*p
, struct fstatfs64_args
*uap
, __unused register_t
*retval
)
1549 struct vfsstatfs
*sp
;
1552 AUDIT_ARG(fd
, uap
->fd
);
1554 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1557 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
1564 sp
= &mp
->mnt_vfsstat
;
1565 if ((error
= vfs_update_vfsstat(mp
, vfs_context_current(), VFS_USER_EVENT
)) != 0) {
1571 error
= statfs64_common(mp
, sp
, uap
->buf
);
1576 struct getfsstat_struct
{
1587 getfsstat_callback(mount_t mp
, void * arg
)
1590 struct getfsstat_struct
*fstp
= (struct getfsstat_struct
*)arg
;
1591 struct vfsstatfs
*sp
;
1593 vfs_context_t ctx
= vfs_context_current();
1595 if (fstp
->sfsp
&& fstp
->count
< fstp
->maxcount
) {
1596 sp
= &mp
->mnt_vfsstat
;
1598 * If MNT_NOWAIT is specified, do not refresh the
1599 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
1601 if (((fstp
->flags
& MNT_NOWAIT
) == 0 || (fstp
->flags
& MNT_WAIT
)) &&
1602 (error
= vfs_update_vfsstat(mp
, ctx
,
1604 KAUTH_DEBUG("vfs_update_vfsstat returned %d", error
);
1605 return(VFS_RETURNED
);
1609 * Need to handle LP64 version of struct statfs
1611 error
= munge_statfs(mp
, sp
, fstp
->sfsp
, &my_size
, IS_64BIT_PROCESS(vfs_context_proc(ctx
)), FALSE
);
1613 fstp
->error
= error
;
1614 return(VFS_RETURNED_DONE
);
1616 fstp
->sfsp
+= my_size
;
1619 error
= mac_mount_label_get(mp
, *fstp
->mp
);
1621 fstp
->error
= error
;
1622 return(VFS_RETURNED_DONE
);
1628 return(VFS_RETURNED
);
1632 * Get statistics on all filesystems.
1635 getfsstat(__unused proc_t p
, struct getfsstat_args
*uap
, int *retval
)
1637 struct __mac_getfsstat_args muap
;
1639 muap
.buf
= uap
->buf
;
1640 muap
.bufsize
= uap
->bufsize
;
1641 muap
.mac
= USER_ADDR_NULL
;
1643 muap
.flags
= uap
->flags
;
1645 return (__mac_getfsstat(p
, &muap
, retval
));
1649 __mac_getfsstat(__unused proc_t p
, struct __mac_getfsstat_args
*uap
, int *retval
)
1653 int count
, maxcount
;
1654 struct getfsstat_struct fst
;
1656 if (IS_64BIT_PROCESS(p
)) {
1657 maxcount
= uap
->bufsize
/ sizeof(struct user_statfs
);
1660 maxcount
= uap
->bufsize
/ sizeof(struct statfs
);
1668 if (uap
->mac
!= USER_ADDR_NULL
) {
1673 count
= (int)(uap
->macsize
/ (IS_64BIT_PROCESS(p
) ? 8 : 4));
1674 if (count
!= maxcount
)
1677 /* Copy in the array */
1678 MALLOC(mp0
, u_int32_t
*, uap
->macsize
, M_MACTEMP
, M_WAITOK
);
1679 error
= copyin(uap
->mac
, mp0
, uap
->macsize
);
1683 /* Normalize to an array of user_addr_t */
1684 MALLOC(mp
, user_addr_t
*, count
* sizeof(user_addr_t
), M_MACTEMP
, M_WAITOK
);
1685 for (i
= 0; i
< count
; i
++) {
1686 if (IS_64BIT_PROCESS(p
))
1687 mp
[i
] = ((user_addr_t
*)mp0
)[i
];
1689 mp
[i
] = (user_addr_t
)mp0
[i
];
1691 FREE(mp0
, M_MACTEMP
);
1698 fst
.flags
= uap
->flags
;
1701 fst
.maxcount
= maxcount
;
1704 vfs_iterate(0, getfsstat_callback
, &fst
);
1707 FREE(mp
, M_MACTEMP
);
1710 KAUTH_DEBUG("ERROR - %s gets %d", p
->p_comm
, fst
.error
);
1714 if (fst
.sfsp
&& fst
.count
> fst
.maxcount
)
1715 *retval
= fst
.maxcount
;
1717 *retval
= fst
.count
;
1722 getfsstat64_callback(mount_t mp
, void * arg
)
1724 struct getfsstat_struct
*fstp
= (struct getfsstat_struct
*)arg
;
1725 struct vfsstatfs
*sp
;
1728 if (fstp
->sfsp
&& fstp
->count
< fstp
->maxcount
) {
1729 sp
= &mp
->mnt_vfsstat
;
1731 * If MNT_NOWAIT is specified, do not refresh the
1732 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
1734 if (((fstp
->flags
& MNT_NOWAIT
) == 0 || (fstp
->flags
& MNT_WAIT
)) &&
1735 (error
= vfs_update_vfsstat(mp
, vfs_context_current(), VFS_USER_EVENT
))) {
1736 KAUTH_DEBUG("vfs_update_vfsstat returned %d", error
);
1737 return(VFS_RETURNED
);
1740 error
= statfs64_common(mp
, sp
, fstp
->sfsp
);
1742 fstp
->error
= error
;
1743 return(VFS_RETURNED_DONE
);
1745 fstp
->sfsp
+= sizeof(struct statfs64
);
1748 return(VFS_RETURNED
);
1752 * Get statistics on all file systems in 64 bit mode.
1755 getfsstat64(__unused proc_t p
, struct getfsstat64_args
*uap
, int *retval
)
1758 int count
, maxcount
;
1759 struct getfsstat_struct fst
;
1761 maxcount
= uap
->bufsize
/ sizeof(struct statfs64
);
1767 fst
.flags
= uap
->flags
;
1770 fst
.maxcount
= maxcount
;
1772 vfs_iterate(0, getfsstat64_callback
, &fst
);
1775 KAUTH_DEBUG("ERROR - %s gets %d", p
->p_comm
, fst
.error
);
1779 if (fst
.sfsp
&& fst
.count
> fst
.maxcount
)
1780 *retval
= fst
.maxcount
;
1782 *retval
= fst
.count
;
1787 #if COMPAT_GETFSSTAT
1788 ogetfsstat(proc_t p
, struct getfsstat_args
*uap
, register_t
*retval
)
1795 * Change current working directory to a given file descriptor.
1799 common_fchdir(proc_t p
, struct fchdir_args
*uap
, int per_thread
)
1801 struct filedesc
*fdp
= p
->p_fd
;
1807 vfs_context_t ctx
= vfs_context_current();
1809 if (per_thread
&& uap
->fd
== -1) {
1811 * Switching back from per-thread to per process CWD; verify we
1812 * in fact have one before proceeding. The only success case
1813 * for this code path is to return 0 preemptively after zapping
1814 * the thread structure contents.
1816 thread_t th
= vfs_context_thread(ctx
);
1818 uthread_t uth
= get_bsdthread_info(th
);
1820 uth
->uu_cdir
= NULLVP
;
1821 if (tvp
!= NULLVP
) {
1829 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1831 if ( (error
= vnode_getwithref(vp
)) ) {
1836 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
1838 if (vp
->v_type
!= VDIR
) {
1844 error
= mac_vnode_check_chdir(ctx
, vp
);
1848 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, ctx
);
1852 while (!error
&& (mp
= vp
->v_mountedhere
) != NULL
) {
1853 if (vfs_busy(mp
, LK_NOWAIT
)) {
1857 error
= VFS_ROOT(mp
, &tdp
, ctx
);
1866 if ( (error
= vnode_ref(vp
)) )
1871 thread_t th
= vfs_context_thread(ctx
);
1873 uthread_t uth
= get_bsdthread_info(th
);
1876 OSBitOrAtomic(P_THCWD
, (UInt32
*)&p
->p_flag
);
1901 fchdir(proc_t p
, struct fchdir_args
*uap
, __unused register_t
*retval
)
1903 return common_fchdir(p
, uap
, 0);
1907 __pthread_fchdir(proc_t p
, struct __pthread_fchdir_args
*uap
, __unused register_t
*retval
)
1909 return common_fchdir(p
, (void *)uap
, 1);
1913 * Change current working directory (``.'').
1915 * Returns: 0 Success
1916 * change_dir:ENOTDIR
1918 * vnode_ref:ENOENT No such file or directory
1922 common_chdir(proc_t p
, struct chdir_args
*uap
, int per_thread
)
1924 struct filedesc
*fdp
= p
->p_fd
;
1926 struct nameidata nd
;
1928 vfs_context_t ctx
= vfs_context_current();
1930 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1931 UIO_USERSPACE
, uap
->path
, ctx
);
1932 error
= change_dir(&nd
, ctx
);
1935 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
1936 vnode_put(nd
.ni_vp
);
1940 * drop the iocount we picked up in change_dir
1942 vnode_put(nd
.ni_vp
);
1945 thread_t th
= vfs_context_thread(ctx
);
1947 uthread_t uth
= get_bsdthread_info(th
);
1949 uth
->uu_cdir
= nd
.ni_vp
;
1950 OSBitOrAtomic(P_THCWD
, (UInt32
*)&p
->p_flag
);
1952 vnode_rele(nd
.ni_vp
);
1958 fdp
->fd_cdir
= nd
.ni_vp
;
1969 chdir(proc_t p
, struct chdir_args
*uap
, __unused register_t
*retval
)
1971 return common_chdir(p
, (void *)uap
, 0);
1975 __pthread_chdir(proc_t p
, struct __pthread_chdir_args
*uap
, __unused register_t
*retval
)
1977 return common_chdir(p
, (void *)uap
, 1);
1982 * Change notion of root (``/'') directory.
1986 chroot(proc_t p
, struct chroot_args
*uap
, __unused register_t
*retval
)
1988 struct filedesc
*fdp
= p
->p_fd
;
1990 struct nameidata nd
;
1992 vfs_context_t ctx
= vfs_context_current();
1994 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
1997 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1998 UIO_USERSPACE
, uap
->path
, ctx
);
1999 error
= change_dir(&nd
, ctx
);
2004 error
= mac_vnode_check_chroot(ctx
, nd
.ni_vp
,
2007 vnode_put(nd
.ni_vp
);
2012 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
2013 vnode_put(nd
.ni_vp
);
2016 vnode_put(nd
.ni_vp
);
2020 fdp
->fd_rdir
= nd
.ni_vp
;
2021 fdp
->fd_flags
|= FD_CHROOT
;
2031 * Common routine for chroot and chdir.
2033 * Returns: 0 Success
2034 * ENOTDIR Not a directory
2035 * namei:??? [anything namei can return]
2036 * vnode_authorize:??? [anything vnode_authorize can return]
2039 change_dir(struct nameidata
*ndp
, vfs_context_t ctx
)
2044 if ((error
= namei(ndp
)))
2049 if (vp
->v_type
!= VDIR
) {
2055 error
= mac_vnode_check_chdir(ctx
, vp
);
2062 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, ctx
);
2072 * Check permissions, allocate an open file structure,
2073 * and call the device open routine if any.
2075 * Returns: 0 Success
2086 #warning XXX implement uid, gid
2088 open1(vfs_context_t ctx
, struct nameidata
*ndp
, int uflags
, struct vnode_attr
*vap
, register_t
*retval
)
2090 proc_t p
= vfs_context_proc(ctx
);
2091 uthread_t uu
= get_bsdthread_info(vfs_context_thread(ctx
));
2092 struct filedesc
*fdp
= p
->p_fd
;
2093 struct fileproc
*fp
;
2096 struct fileproc
*nfp
;
2097 int type
, indx
, error
;
2099 int no_controlling_tty
= 0;
2100 int deny_controlling_tty
= 0;
2101 struct session
*sessp
= SESSION_NULL
;
2102 struct vfs_context context
= *vfs_context_current(); /* local copy */
2106 if ((oflags
& O_ACCMODE
) == O_ACCMODE
)
2108 flags
= FFLAGS(uflags
);
2110 AUDIT_ARG(fflags
, oflags
);
2111 AUDIT_ARG(mode
, vap
->va_mode
);
2113 if ( (error
= falloc(p
, &nfp
, &indx
, ctx
)) ) {
2117 uu
->uu_dupfd
= -indx
- 1;
2119 if (!(p
->p_flag
& P_CONTROLT
)) {
2120 sessp
= proc_session(p
);
2121 no_controlling_tty
= 1;
2123 * If conditions would warrant getting a controlling tty if
2124 * the device being opened is a tty (see ttyopen in tty.c),
2125 * but the open flags deny it, set a flag in the session to
2128 if (SESS_LEADER(p
, sessp
) &&
2129 sessp
->s_ttyvp
== NULL
&&
2130 (flags
& O_NOCTTY
)) {
2131 session_lock(sessp
);
2132 sessp
->s_flags
|= S_NOCTTY
;
2133 session_unlock(sessp
);
2134 deny_controlling_tty
= 1;
2138 if ((error
= vn_open_auth(ndp
, &flags
, vap
))) {
2139 if ((error
== ENODEV
|| error
== ENXIO
) && (uu
->uu_dupfd
>= 0)){ /* XXX from fdopen */
2140 if ((error
= dupfdopen(fdp
, indx
, uu
->uu_dupfd
, flags
, error
)) == 0) {
2141 fp_drop(p
, indx
, NULL
, 0);
2143 if (deny_controlling_tty
) {
2144 session_lock(sessp
);
2145 sessp
->s_flags
&= ~S_NOCTTY
;
2146 session_unlock(sessp
);
2148 if (sessp
!= SESSION_NULL
)
2149 session_rele(sessp
);
2153 if (error
== ERESTART
)
2155 fp_free(p
, indx
, fp
);
2157 if (deny_controlling_tty
) {
2158 session_lock(sessp
);
2159 sessp
->s_flags
&= ~S_NOCTTY
;
2160 session_unlock(sessp
);
2162 if (sessp
!= SESSION_NULL
)
2163 session_rele(sessp
);
2169 fp
->f_fglob
->fg_flag
= flags
& (FMASK
| O_EVTONLY
);
2170 fp
->f_fglob
->fg_type
= DTYPE_VNODE
;
2171 fp
->f_fglob
->fg_ops
= &vnops
;
2172 fp
->f_fglob
->fg_data
= (caddr_t
)vp
;
2174 if (flags
& (O_EXLOCK
| O_SHLOCK
)) {
2175 lf
.l_whence
= SEEK_SET
;
2178 if (flags
& O_EXLOCK
)
2179 lf
.l_type
= F_WRLCK
;
2181 lf
.l_type
= F_RDLCK
;
2183 if ((flags
& FNONBLOCK
) == 0)
2186 error
= mac_file_check_lock(vfs_context_ucred(ctx
), fp
->f_fglob
,
2191 if ((error
= VNOP_ADVLOCK(vp
, (caddr_t
)fp
->f_fglob
, F_SETLK
, &lf
, type
, ctx
)))
2193 fp
->f_fglob
->fg_flag
|= FHASLOCK
;
2196 /* try to truncate by setting the size attribute */
2197 if ((flags
& O_TRUNC
) && ((error
= vnode_setsize(vp
, (off_t
)0, 0, ctx
)) != 0))
2201 * If the open flags denied the acquisition of a controlling tty,
2202 * clear the flag in the session structure that prevented the lower
2203 * level code from assigning one.
2205 if (deny_controlling_tty
) {
2206 session_lock(sessp
);
2207 sessp
->s_flags
&= ~S_NOCTTY
;
2208 session_unlock(sessp
);
2212 * If a controlling tty was set by the tty line discipline, then we
2213 * want to set the vp of the tty into the session structure. We have
2214 * a race here because we can't get to the vp for the tp in ttyopen,
2215 * because it's not passed as a parameter in the open path.
2217 if (no_controlling_tty
&& (p
->p_flag
& P_CONTROLT
)) {
2220 session_lock(sessp
);
2221 ttyvp
= sessp
->s_ttyvp
;
2222 sessp
->s_ttyvp
= vp
;
2223 sessp
->s_ttyvid
= vnode_vid(vp
);
2224 session_unlock(sessp
);
2225 if (ttyvp
!= NULLVP
)
2232 procfdtbl_releasefd(p
, indx
, NULL
);
2233 fp_drop(p
, indx
, fp
, 1);
2238 if (sessp
!= SESSION_NULL
)
2239 session_rele(sessp
);
2242 if (deny_controlling_tty
) {
2243 session_lock(sessp
);
2244 sessp
->s_flags
&= ~S_NOCTTY
;
2245 session_unlock(sessp
);
2247 if (sessp
!= SESSION_NULL
)
2248 session_rele(sessp
);
2250 /* Modify local copy (to not damage thread copy) */
2251 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
2253 vn_close(vp
, fp
->f_fglob
->fg_flag
, &context
);
2255 fp_free(p
, indx
, fp
);
2262 * An open system call using an extended argument list compared to the regular
2263 * system call 'open'.
2265 * Parameters: p Process requesting the open
2266 * uap User argument descriptor (see below)
2267 * retval Pointer to an area to receive the
2268 * return calue from the system call
2270 * Indirect: uap->path Path to open (same as 'open')
2271 * uap->flags Flags to open (same as 'open'
2272 * uap->uid UID to set, if creating
2273 * uap->gid GID to set, if creating
2274 * uap->mode File mode, if creating (same as 'open')
2275 * uap->xsecurity ACL to set, if creating
2277 * Returns: 0 Success
2280 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
2282 * XXX: We should enummerate the possible errno values here, and where
2283 * in the code they originated.
2286 open_extended(proc_t p
, struct open_extended_args
*uap
, register_t
*retval
)
2288 struct filedesc
*fdp
= p
->p_fd
;
2290 kauth_filesec_t xsecdst
;
2291 struct vnode_attr va
;
2292 struct nameidata nd
;
2296 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
2297 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
2301 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
2302 VATTR_SET(&va
, va_mode
, cmode
);
2303 if (uap
->uid
!= KAUTH_UID_NONE
)
2304 VATTR_SET(&va
, va_uid
, uap
->uid
);
2305 if (uap
->gid
!= KAUTH_GID_NONE
)
2306 VATTR_SET(&va
, va_gid
, uap
->gid
);
2307 if (xsecdst
!= NULL
)
2308 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2310 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, vfs_context_current());
2312 ciferror
= open1(vfs_context_current(), &nd
, uap
->flags
, &va
, retval
);
2313 if (xsecdst
!= NULL
)
2314 kauth_filesec_free(xsecdst
);
2320 open(proc_t p
, struct open_args
*uap
, register_t
*retval
)
2322 __pthread_testcancel(1);
2323 return(open_nocancel(p
, (struct open_nocancel_args
*)uap
, retval
));
2328 open_nocancel(proc_t p
, struct open_nocancel_args
*uap
, register_t
*retval
)
2330 struct filedesc
*fdp
= p
->p_fd
;
2331 struct vnode_attr va
;
2332 struct nameidata nd
;
2336 /* Mask off all but regular access permissions */
2337 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
2338 VATTR_SET(&va
, va_mode
, cmode
& ACCESSPERMS
);
2340 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, vfs_context_current());
2342 return(open1(vfs_context_current(), &nd
, uap
->flags
, &va
, retval
));
2347 * Create a special file.
2349 static int mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
);
2352 mknod(proc_t p
, struct mknod_args
*uap
, __unused register_t
*retval
)
2354 struct vnode_attr va
;
2355 vfs_context_t ctx
= vfs_context_current();
2358 struct nameidata nd
;
2362 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
2363 VATTR_SET(&va
, va_rdev
, uap
->dev
);
2365 /* If it's a mknod() of a FIFO, call mkfifo1() instead */
2366 if ((uap
->mode
& S_IFMT
) == S_IFIFO
)
2367 return(mkfifo1(ctx
, uap
->path
, &va
));
2369 AUDIT_ARG(mode
, uap
->mode
);
2370 AUDIT_ARG(dev
, uap
->dev
);
2372 if ((error
= suser(vfs_context_ucred(ctx
), &p
->p_acflag
)))
2374 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
2375 UIO_USERSPACE
, uap
->path
, ctx
);
2387 switch (uap
->mode
& S_IFMT
) {
2388 case S_IFMT
: /* used by badsect to flag bad sectors */
2389 VATTR_SET(&va
, va_type
, VBAD
);
2392 VATTR_SET(&va
, va_type
, VCHR
);
2395 VATTR_SET(&va
, va_type
, VBLK
);
2407 error
= mac_vnode_check_create(ctx
,
2408 nd
.ni_dvp
, &nd
.ni_cnd
, &va
);
2414 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
2418 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, CREATE
, ctx
);
2420 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, &va
, 0, ctx
);
2426 int update_flags
= 0;
2428 // Make sure the name & parent pointers are hooked up
2429 if (vp
->v_name
== NULL
)
2430 update_flags
|= VNODE_UPDATE_NAME
;
2431 if (vp
->v_parent
== NULLVP
)
2432 update_flags
|= VNODE_UPDATE_PARENT
;
2435 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
2438 add_fsevent(FSE_CREATE_FILE
, ctx
,
2446 * nameidone has to happen before we vnode_put(dvp)
2447 * since it may need to release the fs_nodelock on the dvp
2459 * Create a named pipe.
2461 * Returns: 0 Success
2464 * vnode_authorize:???
2468 mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
)
2472 struct nameidata nd
;
2474 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
2475 UIO_USERSPACE
, upath
, ctx
);
2482 /* check that this is a new file and authorize addition */
2487 VATTR_SET(vap
, va_type
, VFIFO
);
2490 error
= mac_vnode_check_create(ctx
, nd
.ni_dvp
,
2497 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
2501 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
);
2504 * nameidone has to happen before we vnode_put(dvp)
2505 * since it may need to release the fs_nodelock on the dvp
2518 * A mkfifo system call using an extended argument list compared to the regular
2519 * system call 'mkfifo'.
2521 * Parameters: p Process requesting the open
2522 * uap User argument descriptor (see below)
2525 * Indirect: uap->path Path to fifo (same as 'mkfifo')
2526 * uap->uid UID to set
2527 * uap->gid GID to set
2528 * uap->mode File mode to set (same as 'mkfifo')
2529 * uap->xsecurity ACL to set, if creating
2531 * Returns: 0 Success
2534 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
2536 * XXX: We should enummerate the possible errno values here, and where
2537 * in the code they originated.
2540 mkfifo_extended(proc_t p
, struct mkfifo_extended_args
*uap
, __unused register_t
*retval
)
2543 kauth_filesec_t xsecdst
;
2544 struct vnode_attr va
;
2546 xsecdst
= KAUTH_FILESEC_NONE
;
2547 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
2548 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
2553 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
2554 if (uap
->uid
!= KAUTH_UID_NONE
)
2555 VATTR_SET(&va
, va_uid
, uap
->uid
);
2556 if (uap
->gid
!= KAUTH_GID_NONE
)
2557 VATTR_SET(&va
, va_gid
, uap
->gid
);
2558 if (xsecdst
!= KAUTH_FILESEC_NONE
)
2559 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2561 ciferror
= mkfifo1(vfs_context_current(), uap
->path
, &va
);
2563 if (xsecdst
!= KAUTH_FILESEC_NONE
)
2564 kauth_filesec_free(xsecdst
);
2570 mkfifo(proc_t p
, struct mkfifo_args
*uap
, __unused register_t
*retval
)
2572 struct vnode_attr va
;
2575 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
2577 return(mkfifo1(vfs_context_current(), uap
->path
, &va
));
2581 * Make a hard file link.
2583 * Returns: 0 Success
2588 * vnode_authorize:???
2593 link(__unused proc_t p
, struct link_args
*uap
, __unused register_t
*retval
)
2595 vnode_t vp
, dvp
, lvp
;
2596 struct nameidata nd
;
2597 vfs_context_t ctx
= vfs_context_current();
2600 int need_event
, has_listeners
;
2601 char *target_path
= NULL
;
2603 vp
= dvp
= lvp
= NULLVP
;
2605 /* look up the object we are linking to */
2606 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2607 UIO_USERSPACE
, uap
->path
, ctx
);
2616 * Normally, linking to directories is not supported.
2617 * However, some file systems may have limited support.
2619 if (vp
->v_type
== VDIR
) {
2620 if (!(vp
->v_mount
->mnt_vtable
->vfc_vfsflags
& VFC_VFSDIRLINKS
)) {
2621 error
= EPERM
; /* POSIX */
2624 /* Linking to a directory requires ownership. */
2625 if (!kauth_cred_issuser(vfs_context_ucred(ctx
))) {
2626 struct vnode_attr dva
;
2629 VATTR_WANTED(&dva
, va_uid
);
2630 if (vnode_getattr(vp
, &dva
, ctx
) != 0 ||
2631 !VATTR_IS_SUPPORTED(&dva
, va_uid
) ||
2632 (dva
.va_uid
!= kauth_cred_getuid(vfs_context_ucred(ctx
)))) {
2639 /* lookup the target node */
2640 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2641 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| AUDITVNPATH2
| CN_NBMOUNTLOOK
;
2642 nd
.ni_dirp
= uap
->link
;
2650 if ((error
= mac_vnode_check_link(ctx
, dvp
, vp
, &nd
.ni_cnd
)) != 0)
2654 /* or to anything that kauth doesn't want us to (eg. immutable items) */
2655 if ((error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_LINKTARGET
, ctx
)) != 0)
2658 /* target node must not exist */
2659 if (lvp
!= NULLVP
) {
2663 /* cannot link across mountpoints */
2664 if (vnode_mount(vp
) != vnode_mount(dvp
)) {
2669 /* authorize creation of the target note */
2670 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
2673 /* and finally make the link */
2674 error
= VNOP_LINK(vp
, dvp
, &nd
.ni_cnd
, ctx
);
2679 need_event
= need_fsevent(FSE_CREATE_FILE
, dvp
);
2683 has_listeners
= kauth_authorize_fileop_has_listeners();
2685 if (need_event
|| has_listeners
) {
2686 char *link_to_path
= NULL
;
2687 int len
, link_name_len
;
2689 /* build the path to the new link file */
2690 GET_PATH(target_path
);
2691 if (target_path
== NULL
) {
2697 vn_getpath(dvp
, target_path
, &len
);
2698 if ((len
+ 1 + nd
.ni_cnd
.cn_namelen
+ 1) < MAXPATHLEN
) {
2699 target_path
[len
-1] = '/';
2700 strlcpy(&target_path
[len
], nd
.ni_cnd
.cn_nameptr
, MAXPATHLEN
-len
);
2701 len
+= nd
.ni_cnd
.cn_namelen
;
2704 if (has_listeners
) {
2705 /* build the path to file we are linking to */
2706 GET_PATH(link_to_path
);
2707 if (link_to_path
== NULL
) {
2712 link_name_len
= MAXPATHLEN
;
2713 vn_getpath(vp
, link_to_path
, &link_name_len
);
2716 * Call out to allow 3rd party notification of rename.
2717 * Ignore result of kauth_authorize_fileop call.
2719 kauth_authorize_fileop(vfs_context_ucred(ctx
), KAUTH_FILEOP_LINK
,
2720 (uintptr_t)link_to_path
, (uintptr_t)target_path
);
2721 if (link_to_path
!= NULL
) {
2722 RELEASE_PATH(link_to_path
);
2727 /* construct fsevent */
2728 if (get_fse_info(vp
, &finfo
, ctx
) == 0) {
2729 // build the path to the destination of the link
2730 add_fsevent(FSE_CREATE_FILE
, ctx
,
2731 FSE_ARG_STRING
, len
, target_path
,
2732 FSE_ARG_FINFO
, &finfo
,
2740 * nameidone has to happen before we vnode_put(dvp)
2741 * since it may need to release the fs_nodelock on the dvp
2744 if (target_path
!= NULL
) {
2745 RELEASE_PATH(target_path
);
2757 * Make a symbolic link.
2759 * We could add support for ACLs here too...
2763 symlink(proc_t p
, struct symlink_args
*uap
, __unused register_t
*retval
)
2765 struct vnode_attr va
;
2768 struct nameidata nd
;
2769 vfs_context_t ctx
= vfs_context_current();
2773 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2774 error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
);
2777 AUDIT_ARG(text
, path
); /* This is the link string */
2779 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
2780 UIO_USERSPACE
, uap
->link
, ctx
);
2788 VATTR_SET(&va
, va_type
, VLNK
);
2789 VATTR_SET(&va
, va_mode
, ACCESSPERMS
& ~p
->p_fd
->fd_cmask
);
2791 error
= mac_vnode_check_create(ctx
,
2792 dvp
, &nd
.ni_cnd
, &va
);
2805 error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
);
2806 /* get default ownership, etc. */
2808 error
= vnode_authattr_new(dvp
, &va
, 0, ctx
);
2810 error
= VNOP_SYMLINK(dvp
, &vp
, &nd
.ni_cnd
, &va
, path
, ctx
);
2812 /* do fallback attribute handling */
2814 error
= vnode_setattr_fallback(vp
, &va
, ctx
);
2817 int update_flags
= 0;
2820 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
2821 nd
.ni_cnd
.cn_flags
= 0;
2829 #if 0 /* XXX - kauth_todo - is KAUTH_FILEOP_SYMLINK needed? */
2830 /* call out to allow 3rd party notification of rename.
2831 * Ignore result of kauth_authorize_fileop call.
2833 if (kauth_authorize_fileop_has_listeners() &&
2835 char *new_link_path
= NULL
;
2838 /* build the path to the new link file */
2839 new_link_path
= get_pathbuff();
2841 vn_getpath(dvp
, new_link_path
, &len
);
2842 if ((len
+ 1 + nd
.ni_cnd
.cn_namelen
+ 1) < MAXPATHLEN
) {
2843 new_link_path
[len
- 1] = '/';
2844 strlcpy(&new_link_path
[len
], nd
.ni_cnd
.cn_nameptr
, MAXPATHLEN
-len
);
2847 kauth_authorize_fileop(vfs_context_ucred(ctx
), KAUTH_FILEOP_SYMLINK
,
2848 (uintptr_t)path
, (uintptr_t)new_link_path
);
2849 if (new_link_path
!= NULL
)
2850 release_pathbuff(new_link_path
);
2853 // Make sure the name & parent pointers are hooked up
2854 if (vp
->v_name
== NULL
)
2855 update_flags
|= VNODE_UPDATE_NAME
;
2856 if (vp
->v_parent
== NULLVP
)
2857 update_flags
|= VNODE_UPDATE_PARENT
;
2860 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
2863 add_fsevent(FSE_CREATE_FILE
, ctx
,
2871 * nameidone has to happen before we vnode_put(dvp)
2872 * since it may need to release the fs_nodelock on the dvp
2880 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
2886 * Delete a whiteout from the filesystem.
2889 #warning XXX authorization not implmented for whiteouts
2891 undelete(__unused proc_t p
, struct undelete_args
*uap
, __unused register_t
*retval
)
2894 struct nameidata nd
;
2895 vfs_context_t ctx
= vfs_context_current();
2898 NDINIT(&nd
, DELETE
, LOCKPARENT
|DOWHITEOUT
|AUDITVNPATH1
,
2899 UIO_USERSPACE
, uap
->path
, ctx
);
2906 if (vp
== NULLVP
&& (nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
2907 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, DELETE
, ctx
);
2912 * nameidone has to happen before we vnode_put(dvp)
2913 * since it may need to release the fs_nodelock on the dvp
2925 * Delete a name from the filesystem.
2929 unlink1(vfs_context_t ctx
, struct nameidata
*ndp
, int nodelbusy
)
2933 struct componentname
*cnp
;
2939 int has_listeners
= 0;
2942 /* unlink or delete is allowed on rsrc forks and named streams */
2943 ndp
->ni_cnd
.cn_flags
|= CN_ALLOWRSRCFORK
;
2946 ndp
->ni_cnd
.cn_flags
|= LOCKPARENT
;
2955 /* With Carbon delete semantics, busy files cannot be deleted */
2957 flags
|= VNODE_REMOVE_NODELETEBUSY
;
2961 * Normally, unlinking of directories is not supported.
2962 * However, some file systems may have limited support.
2964 if ((vp
->v_type
== VDIR
) &&
2965 !(vp
->v_mount
->mnt_vtable
->vfc_vfsflags
& VFC_VFSDIRLINKS
)) {
2966 error
= EPERM
; /* POSIX */
2970 * The root of a mounted filesystem cannot be deleted.
2972 if (vp
->v_flag
& VROOT
) {
2979 /* authorize the delete operation */
2982 error
= mac_vnode_check_unlink(ctx
,
2986 error
= vnode_authorize(vp
, ndp
->ni_dvp
, KAUTH_VNODE_DELETE
, ctx
);
2991 need_event
= need_fsevent(FSE_DELETE
, dvp
);
2993 if ((vp
->v_flag
& VISHARDLINK
) == 0) {
2994 get_fse_info(vp
, &finfo
, ctx
);
2998 has_listeners
= kauth_authorize_fileop_has_listeners();
2999 if (need_event
|| has_listeners
) {
3006 vn_getpath(vp
, path
, &len
);
3010 if (ndp
->ni_cnd
.cn_flags
& CN_WANTSRSRCFORK
)
3011 error
= vnode_removenamedstream(dvp
, vp
, XATTR_RESOURCEFORK_NAME
, 0, ctx
);
3014 error
= VNOP_REMOVE(dvp
, vp
, &ndp
->ni_cnd
, flags
, ctx
);
3017 * Call out to allow 3rd party notification of delete.
3018 * Ignore result of kauth_authorize_fileop call.
3021 if (has_listeners
) {
3022 kauth_authorize_fileop(vfs_context_ucred(ctx
),
3023 KAUTH_FILEOP_DELETE
,
3028 if (vp
->v_flag
& VISHARDLINK
) {
3030 // if a hardlink gets deleted we want to blow away the
3031 // v_parent link because the path that got us to this
3032 // instance of the link is no longer valid. this will
3033 // force the next call to get the path to ask the file
3034 // system instead of just following the v_parent link.
3036 vnode_update_identity(vp
, NULL
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
3041 if (vp
->v_flag
& VISHARDLINK
) {
3042 get_fse_info(vp
, &finfo
, ctx
);
3044 add_fsevent(FSE_DELETE
, ctx
,
3045 FSE_ARG_STRING
, len
, path
,
3046 FSE_ARG_FINFO
, &finfo
,
3055 * nameidone has to happen before we vnode_put(dvp)
3056 * since it may need to release the fs_nodelock on the dvp
3060 /* recycle deleted rsrc fork to force reclaim on shadow file if necessary */
3061 if ((vnode_isnamedstream(ndp
->ni_vp
)) &&
3062 (ndp
->ni_vp
->v_parent
!= NULLVP
) &&
3063 (vnode_isshadow(ndp
->ni_vp
))) {
3064 vnode_recycle(ndp
->ni_vp
);
3075 * Delete a name from the filesystem using POSIX semantics.
3078 unlink(__unused proc_t p
, struct unlink_args
*uap
, __unused register_t
*retval
)
3080 struct nameidata nd
;
3081 vfs_context_t ctx
= vfs_context_current();
3083 NDINIT(&nd
, DELETE
, AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, ctx
);
3084 return unlink1(ctx
, &nd
, 0);
3088 * Delete a name from the filesystem using Carbon semantics.
3091 delete(__unused proc_t p
, struct delete_args
*uap
, __unused register_t
*retval
)
3093 struct nameidata nd
;
3094 vfs_context_t ctx
= vfs_context_current();
3096 NDINIT(&nd
, DELETE
, AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, ctx
);
3097 return unlink1(ctx
, &nd
, 1);
3101 * Reposition read/write file offset.
3104 lseek(proc_t p
, struct lseek_args
*uap
, off_t
*retval
)
3106 struct fileproc
*fp
;
3108 struct vfs_context
*ctx
;
3109 off_t offset
= uap
->offset
, file_size
;
3112 if ( (error
= fp_getfvp(p
,uap
->fd
, &fp
, &vp
)) ) {
3113 if (error
== ENOTSUP
)
3117 if (vnode_isfifo(vp
)) {
3123 ctx
= vfs_context_current();
3125 if (uap
->whence
== L_INCR
&& uap
->offset
== 0)
3126 error
= mac_file_check_get_offset(vfs_context_ucred(ctx
),
3129 error
= mac_file_check_change_offset(vfs_context_ucred(ctx
),
3136 if ( (error
= vnode_getwithref(vp
)) ) {
3141 switch (uap
->whence
) {
3143 offset
+= fp
->f_fglob
->fg_offset
;
3146 if ((error
= vnode_size(vp
, &file_size
, ctx
)) != 0)
3148 offset
+= file_size
;
3156 if (uap
->offset
> 0 && offset
< 0) {
3157 /* Incremented/relative move past max size */
3161 * Allow negative offsets on character devices, per
3162 * POSIX 1003.1-2001. Most likely for writing disk
3165 if (offset
< 0 && vp
->v_type
!= VCHR
) {
3166 /* Decremented/relative move before start */
3170 fp
->f_fglob
->fg_offset
= offset
;
3171 *retval
= fp
->f_fglob
->fg_offset
;
3175 (void)vnode_put(vp
);
3182 * Check access permissions.
3184 * Returns: 0 Success
3185 * vnode_authorize:???
3188 access1(vnode_t vp
, vnode_t dvp
, int uflags
, vfs_context_t ctx
)
3190 kauth_action_t action
;
3194 * If just the regular access bits, convert them to something
3195 * that vnode_authorize will understand.
3197 if (!(uflags
& _ACCESS_EXTENDED_MASK
)) {
3200 action
|= KAUTH_VNODE_READ_DATA
; /* aka KAUTH_VNODE_LIST_DIRECTORY */
3201 if (uflags
& W_OK
) {
3202 if (vnode_isdir(vp
)) {
3203 action
|= KAUTH_VNODE_ADD_FILE
|
3204 KAUTH_VNODE_ADD_SUBDIRECTORY
;
3205 /* might want delete rights here too */
3207 action
|= KAUTH_VNODE_WRITE_DATA
;
3210 if (uflags
& X_OK
) {
3211 if (vnode_isdir(vp
)) {
3212 action
|= KAUTH_VNODE_SEARCH
;
3214 action
|= KAUTH_VNODE_EXECUTE
;
3218 /* take advantage of definition of uflags */
3219 action
= uflags
>> 8;
3223 error
= mac_vnode_check_access(ctx
, vp
, uflags
);
3228 /* action == 0 means only check for existence */
3230 error
= vnode_authorize(vp
, dvp
, action
| KAUTH_VNODE_ACCESS
, ctx
);
3243 * Description: uap->entries Pointer to argument descriptor
3244 * uap->size Size of the area pointed to by
3246 * uap->results Pointer to the results array
3248 * Returns: 0 Success
3249 * ENOMEM Insufficient memory
3250 * EINVAL Invalid arguments
3251 * namei:EFAULT Bad address
3252 * namei:ENAMETOOLONG Filename too long
3253 * namei:ENOENT No such file or directory
3254 * namei:ELOOP Too many levels of symbolic links
3255 * namei:EBADF Bad file descriptor
3256 * namei:ENOTDIR Not a directory
3261 * uap->results Array contents modified
3263 * Notes: The uap->entries are structured as an arbitrary length array
3264 * of accessx descriptors, followed by one or more NULL terniated
3267 * struct accessx_descriptor[0]
3269 * struct accessx_descriptor[n]
3270 * char name_data[0];
3272 * We determine the entry count by walking the buffer containing
3273 * the uap->entries argument descriptor. For each descrptor we
3274 * see, the valid values for the offset ad_name_offset will be
3275 * in the byte range:
3277 * [ uap->entries + sizeof(struct accessx_descriptor) ]
3279 * [ uap->entries + uap->size - 2 ]
3281 * since we must have at least one string, and the string must
3282 * be at least one character plus the NUL terminator in length.
3284 * XXX: Need to support the check-as uid argument
3287 access_extended(__unused proc_t p
, struct access_extended_args
*uap
, __unused register_t
*retval
)
3289 struct accessx_descriptor
*input
= NULL
;
3290 errno_t
*result
= NULL
;
3293 unsigned int desc_max
, desc_actual
, i
, j
;
3294 struct vfs_context context
;
3295 struct nameidata nd
;
3299 #define ACCESSX_MAX_DESCR_ON_STACK 10
3300 struct accessx_descriptor stack_input
[ACCESSX_MAX_DESCR_ON_STACK
];
3302 context
.vc_ucred
= NULL
;
3305 * Validate parameters; if valid, copy the descriptor array and string
3306 * arguments into local memory. Before proceeding, the following
3307 * conditions must have been met:
3309 * o The total size is not permitted to exceed ACCESSX_MAX_TABLESIZE
3310 * o There must be sufficient room in the request for at least one
3311 * descriptor and a one yte NUL terminated string.
3312 * o The allocation of local storage must not fail.
3314 if (uap
->size
> ACCESSX_MAX_TABLESIZE
)
3316 if (uap
->size
< (sizeof(struct accessx_descriptor
) + 2))
3318 if (uap
->size
<= sizeof (stack_input
)) {
3319 input
= stack_input
;
3321 MALLOC(input
, struct accessx_descriptor
*, uap
->size
, M_TEMP
, M_WAITOK
);
3322 if (input
== NULL
) {
3327 error
= copyin(uap
->entries
, input
, uap
->size
);
3332 * Force NUL termination of the copyin buffer to avoid nami() running
3333 * off the end. If the caller passes us bogus data, they may get a
3336 ((char *)input
)[uap
->size
- 1] = 0;
3339 * Access is defined as checking against the process' real identity,
3340 * even if operations are checking the effective identity. This
3341 * requires that we use a local vfs context.
3343 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
3344 context
.vc_thread
= current_thread();
3347 * Find out how many entries we have, so we can allocate the result
3348 * array by walking the list and adjusting the count downward by the
3349 * earliest string offset we see.
3351 desc_max
= (uap
->size
- 2) / sizeof(struct accessx_descriptor
);
3352 desc_actual
= desc_max
;
3353 for (i
= 0; i
< desc_actual
; i
++) {
3355 * Take the offset to the name string for this entry and
3356 * convert to an input array index, which would be one off
3357 * the end of the array if this entry was the lowest-addressed
3360 j
= input
[i
].ad_name_offset
/ sizeof(struct accessx_descriptor
);
3363 * An offset greater than the max allowable offset is an error.
3364 * It is also an error for any valid entry to point
3365 * to a location prior to the end of the current entry, if
3366 * it's not a reference to the string of the previous entry.
3368 if (j
> desc_max
|| (j
!= 0 && j
<= i
)) {
3374 * An offset of 0 means use the previous descriptor's offset;
3375 * this is used to chain multiple requests for the same file
3376 * to avoid multiple lookups.
3379 /* This is not valid for the first entry */
3388 * If the offset of the string for this descriptor is before
3389 * what we believe is the current actual last descriptor,
3390 * then we need to adjust our estimate downward; this permits
3391 * the string table following the last descriptor to be out
3392 * of order relative to the descriptor list.
3394 if (j
< desc_actual
)
3399 * We limit the actual number of descriptors we are willing to process
3400 * to a hard maximum of ACCESSX_MAX_DESCRIPTORS. If the number being
3401 * requested does not exceed this limit,
3403 if (desc_actual
> ACCESSX_MAX_DESCRIPTORS
) {
3407 MALLOC(result
, errno_t
*, desc_actual
* sizeof(errno_t
), M_TEMP
, M_WAITOK
);
3408 if (result
== NULL
) {
3414 * Do the work by iterating over the descriptor entries we know to
3415 * at least appear to contain valid data.
3418 for (i
= 0; i
< desc_actual
; i
++) {
3420 * If the ad_name_offset is 0, then we use the previous
3421 * results to make the check; otherwise, we are looking up
3424 if (input
[i
].ad_name_offset
!= 0) {
3425 /* discard old vnodes */
3436 * Scan forward in the descriptor list to see if we
3437 * need the parent vnode. We will need it if we are
3438 * deleting, since we must have rights to remove
3439 * entries in the parent directory, as well as the
3440 * rights to delete the object itself.
3442 wantdelete
= input
[i
].ad_flags
& _DELETE_OK
;
3443 for (j
= i
+ 1; (j
< desc_actual
) && (input
[j
].ad_name_offset
== 0); j
++)
3444 if (input
[j
].ad_flags
& _DELETE_OK
)
3447 niopts
= FOLLOW
| AUDITVNPATH1
;
3449 /* need parent for vnode_authorize for deletion test */
3451 niopts
|= WANTPARENT
;
3454 NDINIT(&nd
, LOOKUP
, niopts
, UIO_SYSSPACE
, CAST_USER_ADDR_T(((const char *)input
) + input
[i
].ad_name_offset
), &context
);
3465 * Handle lookup errors.
3475 /* run this access check */
3476 result
[i
] = access1(vp
, dvp
, input
[i
].ad_flags
, &context
);
3479 /* fatal lookup error */
3485 /* copy out results */
3486 error
= copyout(result
, uap
->results
, desc_actual
* sizeof(errno_t
));
3489 if (input
&& input
!= stack_input
)
3490 FREE(input
, M_TEMP
);
3492 FREE(result
, M_TEMP
);
3497 if (IS_VALID_CRED(context
.vc_ucred
))
3498 kauth_cred_unref(&context
.vc_ucred
);
3504 * Returns: 0 Success
3505 * namei:EFAULT Bad address
3506 * namei:ENAMETOOLONG Filename too long
3507 * namei:ENOENT No such file or directory
3508 * namei:ELOOP Too many levels of symbolic links
3509 * namei:EBADF Bad file descriptor
3510 * namei:ENOTDIR Not a directory
3515 access(__unused proc_t p
, struct access_args
*uap
, __unused register_t
*retval
)
3518 struct nameidata nd
;
3520 struct vfs_context context
;
3523 int is_namedstream
= 0;
3527 * Access is defined as checking against the process'
3528 * real identity, even if operations are checking the
3529 * effective identity. So we need to tweak the credential
3532 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
3533 context
.vc_thread
= current_thread();
3535 niopts
= FOLLOW
| AUDITVNPATH1
;
3536 /* need parent for vnode_authorize for deletion test */
3537 if (uap
->flags
& _DELETE_OK
)
3538 niopts
|= WANTPARENT
;
3539 NDINIT(&nd
, LOOKUP
, niopts
, UIO_USERSPACE
, uap
->path
, &context
);
3542 /* access(F_OK) calls are allowed for resource forks. */
3543 if (uap
->flags
== F_OK
)
3544 nd
.ni_cnd
.cn_flags
|= CN_ALLOWRSRCFORK
;
3551 /* Grab reference on the shadow stream file vnode to
3552 * force an inactive on release which will mark it for
3555 if (vnode_isnamedstream(nd
.ni_vp
) &&
3556 (nd
.ni_vp
->v_parent
!= NULLVP
) &&
3557 (vnode_isshadow(nd
.ni_vp
))) {
3559 vnode_ref(nd
.ni_vp
);
3563 error
= access1(nd
.ni_vp
, nd
.ni_dvp
, uap
->flags
, &context
);
3566 if (is_namedstream
) {
3567 vnode_rele(nd
.ni_vp
);
3571 vnode_put(nd
.ni_vp
);
3572 if (uap
->flags
& _DELETE_OK
)
3573 vnode_put(nd
.ni_dvp
);
3577 kauth_cred_unref(&context
.vc_ucred
);
3583 * Returns: 0 Success
3590 stat2(vfs_context_t ctx
, struct nameidata
*ndp
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
, int isstat64
)
3594 struct user_stat user_sb
;
3595 struct user_stat64 user_sb64
;
3598 kauth_filesec_t fsec
;
3599 size_t xsecurity_bufsize
;
3603 int is_namedstream
= 0;
3604 /* stat calls are allowed for resource forks. */
3605 ndp
->ni_cnd
.cn_flags
|= CN_ALLOWRSRCFORK
;
3610 fsec
= KAUTH_FILESEC_NONE
;
3612 statptr
= (void *)&sb64
;
3614 statptr
= (void *)&sb
;
3617 /* Grab reference on the shadow stream file vnode to
3618 * force an inactive on release which will mark it for
3621 if (vnode_isnamedstream(ndp
->ni_vp
) &&
3622 (ndp
->ni_vp
->v_parent
!= NULLVP
) &&
3623 (vnode_isshadow(ndp
->ni_vp
))) {
3625 vnode_ref (ndp
->ni_vp
);
3629 error
= vn_stat(ndp
->ni_vp
, statptr
, (xsecurity
!= USER_ADDR_NULL
? &fsec
: NULL
), isstat64
, ctx
);
3632 if (is_namedstream
) {
3633 vnode_rele (ndp
->ni_vp
);
3637 vnode_put(ndp
->ni_vp
);
3642 /* Zap spare fields */
3643 if (isstat64
!= 0) {
3645 sb64
.st_qspare
[0] = 0LL;
3646 sb64
.st_qspare
[1] = 0LL;
3647 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
3648 munge_stat64(&sb64
, &user_sb64
);
3649 my_size
= sizeof(user_sb64
);
3650 sbp
= (caddr_t
)&user_sb64
;
3652 my_size
= sizeof(sb64
);
3653 sbp
= (caddr_t
)&sb64
;
3656 * Check if we raced (post lookup) against the last unlink of a file.
3658 if ((sb64
.st_nlink
== 0) && S_ISREG(sb64
.st_mode
)) {
3663 sb
.st_qspare
[0] = 0LL;
3664 sb
.st_qspare
[1] = 0LL;
3665 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
3666 munge_stat(&sb
, &user_sb
);
3667 my_size
= sizeof(user_sb
);
3668 sbp
= (caddr_t
)&user_sb
;
3670 my_size
= sizeof(sb
);
3675 * Check if we raced (post lookup) against the last unlink of a file.
3677 if ((sb
.st_nlink
== 0) && S_ISREG(sb
.st_mode
)) {
3681 if ((error
= copyout(sbp
, ub
, my_size
)) != 0)
3684 /* caller wants extended security information? */
3685 if (xsecurity
!= USER_ADDR_NULL
) {
3687 /* did we get any? */
3688 if (fsec
== KAUTH_FILESEC_NONE
) {
3689 if (susize(xsecurity_size
, 0) != 0) {
3694 /* find the user buffer size */
3695 xsecurity_bufsize
= fusize(xsecurity_size
);
3697 /* copy out the actual data size */
3698 if (susize(xsecurity_size
, KAUTH_FILESEC_COPYSIZE(fsec
)) != 0) {
3703 /* if the caller supplied enough room, copy out to it */
3704 if (xsecurity_bufsize
>= KAUTH_FILESEC_COPYSIZE(fsec
))
3705 error
= copyout(fsec
, xsecurity
, KAUTH_FILESEC_COPYSIZE(fsec
));
3709 if (fsec
!= KAUTH_FILESEC_NONE
)
3710 kauth_filesec_free(fsec
);
3715 * Get file status; this version follows links.
3717 * Returns: 0 Success
3718 * stat2:??? [see stat2() in this file]
3721 stat1(user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
, int isstat64
)
3723 struct nameidata nd
;
3724 vfs_context_t ctx
= vfs_context_current();
3726 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
3727 UIO_USERSPACE
, path
, ctx
);
3728 return(stat2(ctx
, &nd
, ub
, xsecurity
, xsecurity_size
, isstat64
));
3732 stat_extended(__unused proc_t p
, struct stat_extended_args
*uap
, __unused register_t
*retval
)
3734 return (stat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 0));
3738 * Returns: 0 Success
3739 * stat1:??? [see stat1() in this file]
3742 stat(__unused proc_t p
, struct stat_args
*uap
, __unused register_t
*retval
)
3744 return(stat1(uap
->path
, uap
->ub
, 0, 0, 0));
3748 stat64(__unused proc_t p
, struct stat64_args
*uap
, __unused register_t
*retval
)
3750 return(stat1(uap
->path
, uap
->ub
, 0, 0, 1));
3754 stat64_extended(__unused proc_t p
, struct stat64_extended_args
*uap
, __unused register_t
*retval
)
3756 return (stat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 1));
3759 * Get file status; this version does not follow links.
3762 lstat1(user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
, int isstat64
)
3764 struct nameidata nd
;
3765 vfs_context_t ctx
= vfs_context_current();
3767 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| NOFOLLOW
| AUDITVNPATH1
,
3768 UIO_USERSPACE
, path
, ctx
);
3770 return(stat2(ctx
, &nd
, ub
, xsecurity
, xsecurity_size
, isstat64
));
3774 lstat_extended(__unused proc_t p
, struct lstat_extended_args
*uap
, __unused register_t
*retval
)
3776 return (lstat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 0));
3780 lstat(__unused proc_t p
, struct lstat_args
*uap
, __unused register_t
*retval
)
3782 return(lstat1(uap
->path
, uap
->ub
, 0, 0, 0));
3785 lstat64(__unused proc_t p
, struct lstat64_args
*uap
, __unused register_t
*retval
)
3787 return(lstat1(uap
->path
, uap
->ub
, 0, 0, 1));
3791 lstat64_extended(__unused proc_t p
, struct lstat64_extended_args
*uap
, __unused register_t
*retval
)
3793 return (lstat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 1));
3797 * Get configurable pathname variables.
3799 * Returns: 0 Success
3803 * Notes: Global implementation constants are intended to be
3804 * implemented in this function directly; all other constants
3805 * are per-FS implementation, and therefore must be handled in
3806 * each respective FS, instead.
3808 * XXX We implement some things globally right now that should actually be
3809 * XXX per-FS; we will need to deal with this at some point.
3813 pathconf(__unused proc_t p
, struct pathconf_args
*uap
, register_t
*retval
)
3816 struct nameidata nd
;
3817 vfs_context_t ctx
= vfs_context_current();
3819 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3820 UIO_USERSPACE
, uap
->path
, ctx
);
3825 error
= vn_pathconf(nd
.ni_vp
, uap
->name
, retval
, ctx
);
3827 vnode_put(nd
.ni_vp
);
3833 * Return target name of a symbolic link.
3837 readlink(proc_t p
, struct readlink_args
*uap
, register_t
*retval
)
3841 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
3843 struct nameidata nd
;
3844 vfs_context_t ctx
= vfs_context_current();
3845 char uio_buf
[ UIO_SIZEOF(1) ];
3847 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
3848 UIO_USERSPACE
, uap
->path
, ctx
);
3856 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
3857 &uio_buf
[0], sizeof(uio_buf
));
3858 uio_addiov(auio
, uap
->buf
, uap
->count
);
3859 if (vp
->v_type
!= VLNK
)
3863 error
= mac_vnode_check_readlink(ctx
,
3867 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, ctx
);
3869 error
= VNOP_READLINK(vp
, auio
, ctx
);
3872 // LP64todo - fix this
3873 *retval
= uap
->count
- (int)uio_resid(auio
);
3878 * Change file flags.
3881 chflags1(vnode_t vp
, int flags
, vfs_context_t ctx
)
3883 struct vnode_attr va
;
3884 kauth_action_t action
;
3888 VATTR_SET(&va
, va_flags
, flags
);
3891 error
= mac_vnode_check_setflags(ctx
, vp
, flags
);
3896 /* request authorisation, disregard immutability */
3897 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
3900 * Request that the auth layer disregard those file flags it's allowed to when
3901 * authorizing this operation; we need to do this in order to be able to
3902 * clear immutable flags.
3904 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
| KAUTH_VNODE_NOIMMUTABLE
, ctx
)) != 0))
3906 error
= vnode_setattr(vp
, &va
, ctx
);
3908 if ((error
== 0) && !VATTR_IS_SUPPORTED(&va
, va_flags
)) {
3917 * Change flags of a file given a path name.
3921 chflags(__unused proc_t p
, struct chflags_args
*uap
, __unused register_t
*retval
)
3924 vfs_context_t ctx
= vfs_context_current();
3926 struct nameidata nd
;
3928 AUDIT_ARG(fflags
, uap
->flags
);
3929 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3930 UIO_USERSPACE
, uap
->path
, ctx
);
3937 error
= chflags1(vp
, uap
->flags
, ctx
);
3943 * Change flags of a file given a file descriptor.
3947 fchflags(__unused proc_t p
, struct fchflags_args
*uap
, __unused register_t
*retval
)
3952 AUDIT_ARG(fd
, uap
->fd
);
3953 AUDIT_ARG(fflags
, uap
->flags
);
3954 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
3957 if ((error
= vnode_getwithref(vp
))) {
3962 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3964 error
= chflags1(vp
, uap
->flags
, vfs_context_current());
3971 * Change security information on a filesystem object.
3973 * Returns: 0 Success
3974 * EPERM Operation not permitted
3975 * vnode_authattr:??? [anything vnode_authattr can return]
3976 * vnode_authorize:??? [anything vnode_authorize can return]
3977 * vnode_setattr:??? [anything vnode_setattr can return]
3979 * Notes: If vnode_authattr or vnode_authorize return EACCES, it will be
3980 * translated to EPERM before being returned.
3983 chmod2(vfs_context_t ctx
, vnode_t vp
, struct vnode_attr
*vap
)
3985 kauth_action_t action
;
3988 AUDIT_ARG(mode
, (mode_t
)vap
->va_mode
);
3989 #warning XXX audit new args
3992 /* chmod calls are not allowed for resource forks. */
3993 if (vp
->v_flag
& VISNAMEDSTREAM
) {
3999 error
= mac_vnode_check_setmode(ctx
, vp
, (mode_t
)vap
->va_mode
);
4004 /* make sure that the caller is allowed to set this security information */
4005 if (((error
= vnode_authattr(vp
, vap
, &action
, ctx
)) != 0) ||
4006 ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
4007 if (error
== EACCES
)
4012 error
= vnode_setattr(vp
, vap
, ctx
);
4019 * Change mode of a file given path name.
4021 * Returns: 0 Success
4022 * namei:??? [anything namei can return]
4023 * chmod2:??? [anything chmod2 can return]
4026 chmod1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
4028 struct nameidata nd
;
4031 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4032 UIO_USERSPACE
, path
, ctx
);
4033 if ((error
= namei(&nd
)))
4035 error
= chmod2(ctx
, nd
.ni_vp
, vap
);
4036 vnode_put(nd
.ni_vp
);
4042 * A chmod system call using an extended argument list compared to the regular
4043 * system call 'mkfifo'.
4045 * Parameters: p Process requesting the open
4046 * uap User argument descriptor (see below)
4049 * Indirect: uap->path Path to object (same as 'chmod')
4050 * uap->uid UID to set
4051 * uap->gid GID to set
4052 * uap->mode File mode to set (same as 'chmod')
4053 * uap->xsecurity ACL to set (or delete)
4055 * Returns: 0 Success
4058 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
4060 * XXX: We should enummerate the possible errno values here, and where
4061 * in the code they originated.
4064 chmod_extended(__unused proc_t p
, struct chmod_extended_args
*uap
, __unused register_t
*retval
)
4067 struct vnode_attr va
;
4068 kauth_filesec_t xsecdst
;
4071 if (uap
->mode
!= -1)
4072 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
4073 if (uap
->uid
!= KAUTH_UID_NONE
)
4074 VATTR_SET(&va
, va_uid
, uap
->uid
);
4075 if (uap
->gid
!= KAUTH_GID_NONE
)
4076 VATTR_SET(&va
, va_gid
, uap
->gid
);
4079 switch(uap
->xsecurity
) {
4080 /* explicit remove request */
4081 case CAST_USER_ADDR_T((void *)1): /* _FILESEC_REMOVE_ACL */
4082 VATTR_SET(&va
, va_acl
, NULL
);
4085 case USER_ADDR_NULL
:
4088 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
4090 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
4091 KAUTH_DEBUG("CHMOD - setting ACL with %d entries", va
.va_acl
->acl_entrycount
);
4094 error
= chmod1(vfs_context_current(), uap
->path
, &va
);
4096 if (xsecdst
!= NULL
)
4097 kauth_filesec_free(xsecdst
);
4102 * Returns: 0 Success
4103 * chmod1:??? [anything chmod1 can return]
4106 chmod(__unused proc_t p
, struct chmod_args
*uap
, __unused register_t
*retval
)
4108 struct vnode_attr va
;
4111 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
4113 return(chmod1(vfs_context_current(), uap
->path
, &va
));
4117 * Change mode of a file given a file descriptor.
4120 fchmod1(__unused proc_t p
, int fd
, struct vnode_attr
*vap
)
4127 if ((error
= file_vnode(fd
, &vp
)) != 0)
4129 if ((error
= vnode_getwithref(vp
)) != 0) {
4133 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4135 error
= chmod2(vfs_context_current(), vp
, vap
);
4136 (void)vnode_put(vp
);
4143 fchmod_extended(proc_t p
, struct fchmod_extended_args
*uap
, __unused register_t
*retval
)
4146 struct vnode_attr va
;
4147 kauth_filesec_t xsecdst
;
4150 if (uap
->mode
!= -1)
4151 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
4152 if (uap
->uid
!= KAUTH_UID_NONE
)
4153 VATTR_SET(&va
, va_uid
, uap
->uid
);
4154 if (uap
->gid
!= KAUTH_GID_NONE
)
4155 VATTR_SET(&va
, va_gid
, uap
->gid
);
4158 switch(uap
->xsecurity
) {
4159 case USER_ADDR_NULL
:
4160 VATTR_SET(&va
, va_acl
, NULL
);
4162 case CAST_USER_ADDR_T(-1):
4165 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
4167 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
4170 error
= fchmod1(p
, uap
->fd
, &va
);
4173 switch(uap
->xsecurity
) {
4174 case USER_ADDR_NULL
:
4175 case CAST_USER_ADDR_T(-1):
4178 if (xsecdst
!= NULL
)
4179 kauth_filesec_free(xsecdst
);
4185 fchmod(proc_t p
, struct fchmod_args
*uap
, __unused register_t
*retval
)
4187 struct vnode_attr va
;
4190 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
4192 return(fchmod1(p
, uap
->fd
, &va
));
4197 * Set ownership given a path name.
4201 chown1(vfs_context_t ctx
, struct chown_args
*uap
, __unused register_t
*retval
, int follow
)
4204 struct vnode_attr va
;
4206 struct nameidata nd
;
4207 kauth_action_t action
;
4209 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
4211 NDINIT(&nd
, LOOKUP
, (follow
? FOLLOW
: 0) | NOTRIGGER
| AUDITVNPATH1
,
4212 UIO_USERSPACE
, uap
->path
, ctx
);
4221 if (uap
->uid
!= VNOVAL
)
4222 VATTR_SET(&va
, va_uid
, uap
->uid
);
4223 if (uap
->gid
!= VNOVAL
)
4224 VATTR_SET(&va
, va_gid
, uap
->gid
);
4227 error
= mac_vnode_check_setowner(ctx
, vp
, uap
->uid
, uap
->gid
);
4232 /* preflight and authorize attribute changes */
4233 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
4235 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
4237 error
= vnode_setattr(vp
, &va
, ctx
);
4241 * EACCES is only allowed from namei(); permissions failure should
4242 * return EPERM, so we need to translate the error code.
4244 if (error
== EACCES
)
4252 chown(__unused proc_t p
, struct chown_args
*uap
, register_t
*retval
)
4254 return chown1(vfs_context_current(), uap
, retval
, 1);
4258 lchown(__unused proc_t p
, struct lchown_args
*uap
, register_t
*retval
)
4260 /* Argument list identical, but machine generated; cast for chown1() */
4261 return chown1(vfs_context_current(), (struct chown_args
*)uap
, retval
, 0);
4265 * Set ownership given a file descriptor.
4269 fchown(__unused proc_t p
, struct fchown_args
*uap
, __unused register_t
*retval
)
4271 struct vnode_attr va
;
4272 vfs_context_t ctx
= vfs_context_current();
4275 kauth_action_t action
;
4277 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
4278 AUDIT_ARG(fd
, uap
->fd
);
4280 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
4283 if ( (error
= vnode_getwithref(vp
)) ) {
4287 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4290 if (uap
->uid
!= VNOVAL
)
4291 VATTR_SET(&va
, va_uid
, uap
->uid
);
4292 if (uap
->gid
!= VNOVAL
)
4293 VATTR_SET(&va
, va_gid
, uap
->gid
);
4296 /* chown calls are not allowed for resource forks. */
4297 if (vp
->v_flag
& VISNAMEDSTREAM
) {
4304 error
= mac_vnode_check_setowner(ctx
, vp
, uap
->uid
, uap
->gid
);
4309 /* preflight and authorize attribute changes */
4310 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
4312 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
4313 if (error
== EACCES
)
4317 error
= vnode_setattr(vp
, &va
, ctx
);
4320 (void)vnode_put(vp
);
4326 getutimes(user_addr_t usrtvp
, struct timespec
*tsp
)
4328 struct user_timeval tv
[2];
4331 if (usrtvp
== USER_ADDR_NULL
) {
4332 struct timeval old_tv
;
4333 /* XXX Y2038 bug because of microtime argument */
4335 TIMEVAL_TO_TIMESPEC(&old_tv
, &tsp
[0]);
4338 if (IS_64BIT_PROCESS(current_proc())) {
4339 error
= copyin(usrtvp
, (void *)tv
, sizeof(tv
));
4341 struct timeval old_tv
[2];
4342 error
= copyin(usrtvp
, (void *)old_tv
, sizeof(old_tv
));
4343 tv
[0].tv_sec
= old_tv
[0].tv_sec
;
4344 tv
[0].tv_usec
= old_tv
[0].tv_usec
;
4345 tv
[1].tv_sec
= old_tv
[1].tv_sec
;
4346 tv
[1].tv_usec
= old_tv
[1].tv_usec
;
4350 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
4351 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
4357 setutimes(vfs_context_t ctx
, vnode_t vp
, const struct timespec
*ts
,
4361 struct vnode_attr va
;
4362 kauth_action_t action
;
4364 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4367 VATTR_SET(&va
, va_access_time
, ts
[0]);
4368 VATTR_SET(&va
, va_modify_time
, ts
[1]);
4370 va
.va_vaflags
|= VA_UTIMES_NULL
;
4373 /* utimes calls are not allowed for resource forks. */
4374 if (vp
->v_flag
& VISNAMEDSTREAM
) {
4381 error
= mac_vnode_check_setutimes(ctx
, vp
, ts
[0], ts
[1]);
4385 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0) {
4386 if (!nullflag
&& error
== EACCES
)
4391 /* since we may not need to auth anything, check here */
4392 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
4393 if (!nullflag
&& error
== EACCES
)
4397 error
= vnode_setattr(vp
, &va
, ctx
);
4404 * Set the access and modification times of a file.
4408 utimes(__unused proc_t p
, struct utimes_args
*uap
, __unused register_t
*retval
)
4410 struct timespec ts
[2];
4413 struct nameidata nd
;
4414 vfs_context_t ctx
= vfs_context_current();
4417 * AUDIT: Needed to change the order of operations to do the
4418 * name lookup first because auditing wants the path.
4420 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4421 UIO_USERSPACE
, uap
->path
, ctx
);
4428 * Fetch the user-supplied time. If usrtvp is USER_ADDR_NULL, we fetch
4429 * the current time instead.
4432 if ((error
= getutimes(usrtvp
, ts
)) != 0)
4435 error
= setutimes(ctx
, nd
.ni_vp
, ts
, usrtvp
== USER_ADDR_NULL
);
4438 vnode_put(nd
.ni_vp
);
4443 * Set the access and modification times of a file.
4447 futimes(__unused proc_t p
, struct futimes_args
*uap
, __unused register_t
*retval
)
4449 struct timespec ts
[2];
4454 AUDIT_ARG(fd
, uap
->fd
);
4456 if ((error
= getutimes(usrtvp
, ts
)) != 0)
4458 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
4460 if((error
= vnode_getwithref(vp
))) {
4465 error
= setutimes(vfs_context_current(), vp
, ts
, usrtvp
== 0);
4472 * Truncate a file given its path name.
4476 truncate(__unused proc_t p
, struct truncate_args
*uap
, __unused register_t
*retval
)
4479 struct vnode_attr va
;
4480 vfs_context_t ctx
= vfs_context_current();
4482 struct nameidata nd
;
4483 kauth_action_t action
;
4485 if (uap
->length
< 0)
4487 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4488 UIO_USERSPACE
, uap
->path
, ctx
);
4489 if ((error
= namei(&nd
)))
4496 VATTR_SET(&va
, va_data_size
, uap
->length
);
4499 error
= mac_vnode_check_truncate(ctx
, NOCRED
, vp
);
4504 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
4506 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
4508 error
= vnode_setattr(vp
, &va
, ctx
);
4515 * Truncate a file given a file descriptor.
4519 ftruncate(proc_t p
, struct ftruncate_args
*uap
, register_t
*retval
)
4521 vfs_context_t ctx
= vfs_context_current();
4522 struct vnode_attr va
;
4524 struct fileproc
*fp
;
4528 AUDIT_ARG(fd
, uap
->fd
);
4529 if (uap
->length
< 0)
4532 if ( (error
= fp_lookup(p
,fd
,&fp
,0)) ) {
4536 if (fp
->f_fglob
->fg_type
== DTYPE_PSXSHM
) {
4537 error
= pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
);
4540 if (fp
->f_fglob
->fg_type
!= DTYPE_VNODE
) {
4545 vp
= (vnode_t
)fp
->f_fglob
->fg_data
;
4547 if ((fp
->f_fglob
->fg_flag
& FWRITE
) == 0) {
4548 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4553 if ((error
= vnode_getwithref(vp
)) != 0) {
4557 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4560 error
= mac_vnode_check_truncate(ctx
,
4561 fp
->f_fglob
->fg_cred
, vp
);
4563 (void)vnode_put(vp
);
4568 VATTR_SET(&va
, va_data_size
, uap
->length
);
4569 error
= vnode_setattr(vp
, &va
, ctx
);
4570 (void)vnode_put(vp
);
4578 * Sync an open file.
4582 fsync(proc_t p
, struct fsync_args
*uap
, register_t
*retval
)
4584 __pthread_testcancel(1);
4585 return(fsync_nocancel(p
, (struct fsync_nocancel_args
*)uap
, retval
));
4589 fsync_nocancel(proc_t p
, struct fsync_nocancel_args
*uap
, __unused register_t
*retval
)
4592 struct fileproc
*fp
;
4593 vfs_context_t ctx
= vfs_context_current();
4596 if ( (error
= fp_getfvp(p
, uap
->fd
, &fp
, &vp
)) )
4598 if ( (error
= vnode_getwithref(vp
)) ) {
4603 error
= VNOP_FSYNC(vp
, MNT_WAIT
, ctx
);
4606 /* Sync resource fork shadow file if necessary. */
4608 (vp
->v_flag
& VISNAMEDSTREAM
) &&
4609 (vp
->v_parent
!= NULLVP
) &&
4610 (vnode_isshadow(vp
)) &&
4611 (fp
->f_flags
& FP_WRITTEN
)) {
4612 (void) vnode_flushnamedstream(vp
->v_parent
, vp
, ctx
);
4616 (void)vnode_put(vp
);
4622 * Duplicate files. Source must be a file, target must be a file or
4625 * XXX Copyfile authorisation checking is woefully inadequate, and will not
4626 * perform inheritance correctly.
4630 copyfile(__unused proc_t p
, struct copyfile_args
*uap
, __unused register_t
*retval
)
4632 vnode_t tvp
, fvp
, tdvp
, sdvp
;
4633 struct nameidata fromnd
, tond
;
4635 vfs_context_t ctx
= vfs_context_current();
4637 /* Check that the flags are valid. */
4639 if (uap
->flags
& ~CPF_MASK
) {
4643 NDINIT(&fromnd
, LOOKUP
, SAVESTART
| AUDITVNPATH1
,
4644 UIO_USERSPACE
, uap
->from
, ctx
);
4645 if ((error
= namei(&fromnd
)))
4649 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
| AUDITVNPATH2
| CN_NBMOUNTLOOK
,
4650 UIO_USERSPACE
, uap
->to
, ctx
);
4651 if ((error
= namei(&tond
))) {
4658 if (!(uap
->flags
& CPF_OVERWRITE
)) {
4663 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
4668 if ((error
= vnode_authorize(tdvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
4674 * If source is the same as the destination (that is the
4675 * same inode number) then there is nothing to do.
4676 * (fixed to have POSIX semantics - CSM 3/2/98)
4681 error
= VNOP_COPYFILE(fvp
, tdvp
, tvp
, &tond
.ni_cnd
, uap
->mode
, uap
->flags
, ctx
);
4683 sdvp
= tond
.ni_startdir
;
4685 * nameidone has to happen before we vnode_put(tdvp)
4686 * since it may need to release the fs_nodelock on the tdvp
4697 if (fromnd
.ni_startdir
)
4698 vnode_put(fromnd
.ni_startdir
);
4708 * Rename files. Source and destination must either both be directories,
4709 * or both not be directories. If target is a directory, it must be empty.
4713 rename(__unused proc_t p
, struct rename_args
*uap
, __unused register_t
*retval
)
4717 struct nameidata fromnd
, tond
;
4718 vfs_context_t ctx
= vfs_context_current();
4724 char *from_name
= NULL
, *to_name
= NULL
;
4725 int from_len
, to_len
;
4726 int holding_mntlock
;
4727 mount_t locked_mp
= NULL
;
4729 fse_info from_finfo
, to_finfo
;
4731 holding_mntlock
= 0;
4738 NDINIT(&fromnd
, DELETE
, WANTPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->from
, ctx
);
4740 if ( (error
= namei(&fromnd
)) )
4742 fdvp
= fromnd
.ni_dvp
;
4746 error
= mac_vnode_check_rename_from(ctx
, fdvp
, fvp
, &fromnd
.ni_cnd
);
4751 NDINIT(&tond
, RENAME
, WANTPARENT
| AUDITVNPATH2
| CN_NBMOUNTLOOK
, UIO_USERSPACE
, uap
->to
, ctx
);
4752 if (fvp
->v_type
== VDIR
)
4753 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
4755 if ( (error
= namei(&tond
)) ) {
4757 * Translate error code for rename("dir1", "dir2/.").
4759 if (error
== EISDIR
&& fvp
->v_type
== VDIR
)
4767 error
= mac_vnode_check_rename_to(ctx
,
4768 tdvp
, tvp
, fdvp
== tdvp
, &tond
.ni_cnd
);
4774 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
4777 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
4787 * If the source and destination are the same (i.e. they're
4788 * links to the same vnode) and the target file system is
4789 * case sensitive, then there is nothing to do.
4795 * Note: if _PC_CASE_SENSITIVE selector isn't supported,
4796 * then assume that this file system is case sensitive.
4798 if (VNOP_PATHCONF(fvp
, _PC_CASE_SENSITIVE
, &pathconf_val
, ctx
) != 0 ||
4799 pathconf_val
!= 0) {
4807 * If tvp is a directory and not the same as fdvp, or tdvp is not
4808 * the same as fdvp, the node is moving between directories and we
4809 * need rights to remove from the old and add to the new.
4811 * If tvp already exists and is not a directory, we need to be
4812 * allowed to delete it.
4814 * Note that we do not inherit when renaming.
4816 * XXX This needs to be revisited to implement the deferred-inherit bit
4822 if ((tvp
!= NULL
) && vnode_isdir(tvp
)) {
4825 } else if (tdvp
!= fdvp
) {
4829 * must have delete rights to remove the old name even in
4830 * the simple case of fdvp == tdvp.
4832 * If fvp is a directory, and we are changing it's parent,
4833 * then we also need rights to rewrite its ".." entry as well.
4835 if (vnode_isdir(fvp
)) {
4836 if ((error
= vnode_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
| KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
)) != 0)
4839 if ((error
= vnode_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
, ctx
)) != 0)
4843 /* moving into tdvp or tvp, must have rights to add */
4844 if ((error
= vnode_authorize(((tvp
!= NULL
) && vnode_isdir(tvp
)) ? tvp
: tdvp
,
4846 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
4849 * We could encounter a race where after doing the namei, tvp stops
4850 * being valid. If so, simply re-drive the rename call from the
4853 if (error
== ENOENT
) {
4859 /* node staying in same directory, must be allowed to add new name */
4860 if ((error
= vnode_authorize(fdvp
, NULL
,
4861 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
4864 /* overwriting tvp */
4865 if ((tvp
!= NULL
) && !vnode_isdir(tvp
) &&
4866 ((error
= vnode_authorize(tvp
, tdvp
, KAUTH_VNODE_DELETE
, ctx
)) != 0)) {
4868 * We could encounter a race where after doing the namei, tvp stops
4869 * being valid. If so, simply re-drive the rename call from the
4872 if (error
== ENOENT
) {
4878 /* XXX more checks? */
4881 /* authorization denied */
4886 * Allow the renaming of mount points.
4887 * - target must not exist
4888 * - target must reside in the same directory as source
4889 * - union mounts cannot be renamed
4890 * - "/" cannot be renamed
4892 if ((fvp
->v_flag
& VROOT
) &&
4893 (fvp
->v_type
== VDIR
) &&
4895 (fvp
->v_mountedhere
== NULL
) &&
4897 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
4898 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
4901 /* switch fvp to the covered vnode */
4902 coveredvp
= fvp
->v_mount
->mnt_vnodecovered
;
4903 if ( (vnode_getwithref(coveredvp
)) ) {
4913 * Check for cross-device rename.
4915 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
4916 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
4921 * Avoid renaming "." and "..".
4923 if (fvp
->v_type
== VDIR
&&
4925 (fromnd
.ni_cnd
.cn_namelen
== 1 && fromnd
.ni_cnd
.cn_nameptr
[0] == '.') ||
4926 ((fromnd
.ni_cnd
.cn_flags
| tond
.ni_cnd
.cn_flags
) & ISDOTDOT
)) ) {
4931 * The following edge case is caught here:
4932 * (to cannot be a descendent of from)
4945 if (tdvp
->v_parent
== fvp
) {
4951 * If source is the same as the destination (that is the
4952 * same inode number) then there is nothing to do...
4953 * EXCEPT if the underlying file system supports case
4954 * insensitivity and is case preserving. In this case
4955 * the file system needs to handle the special case of
4956 * getting the same vnode as target (fvp) and source (tvp).
4958 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
4959 * and _PC_CASE_PRESERVING can have this exception, and they need to
4960 * handle the special case of getting the same vnode as target and
4961 * source. NOTE: Then the target is unlocked going into vnop_rename,
4962 * so not to cause locking problems. There is a single reference on tvp.
4964 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
4965 * that correct behaviour then is just to remove the source (link)
4967 if (fvp
== tvp
&& fdvp
== tdvp
) {
4968 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
4969 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
4970 fromnd
.ni_cnd
.cn_namelen
)) {
4975 if (holding_mntlock
&& fvp
->v_mount
!= locked_mp
) {
4977 * we're holding a reference and lock
4978 * on locked_mp, but it no longer matches
4979 * what we want to do... so drop our hold
4981 mount_unlock_renames(locked_mp
);
4982 mount_drop(locked_mp
, 0);
4983 holding_mntlock
= 0;
4985 if (tdvp
!= fdvp
&& fvp
->v_type
== VDIR
) {
4987 * serialize renames that re-shape
4988 * the tree... if holding_mntlock is
4989 * set, then we're ready to go...
4991 * first need to drop the iocounts
4992 * we picked up, second take the
4993 * lock to serialize the access,
4994 * then finally start the lookup
4995 * process over with the lock held
4997 if (!holding_mntlock
) {
4999 * need to grab a reference on
5000 * the mount point before we
5001 * drop all the iocounts... once
5002 * the iocounts are gone, the mount
5005 locked_mp
= fvp
->v_mount
;
5006 mount_ref(locked_mp
, 0);
5009 * nameidone has to happen before we vnode_put(tvp)
5010 * since it may need to release the fs_nodelock on the tvp
5019 * nameidone has to happen before we vnode_put(fdvp)
5020 * since it may need to release the fs_nodelock on the fvp
5027 mount_lock_renames(locked_mp
);
5028 holding_mntlock
= 1;
5034 * when we dropped the iocounts to take
5035 * the lock, we allowed the identity of
5036 * the various vnodes to change... if they did,
5037 * we may no longer be dealing with a rename
5038 * that reshapes the tree... once we're holding
5039 * the iocounts, the vnodes can't change type
5040 * so we're free to drop the lock at this point
5043 if (holding_mntlock
) {
5044 mount_unlock_renames(locked_mp
);
5045 mount_drop(locked_mp
, 0);
5046 holding_mntlock
= 0;
5049 // save these off so we can later verify that fvp is the same
5050 oname
= fvp
->v_name
;
5051 oparent
= fvp
->v_parent
;
5054 need_event
= need_fsevent(FSE_RENAME
, fvp
);
5056 get_fse_info(fvp
, &from_finfo
, ctx
);
5059 get_fse_info(tvp
, &to_finfo
, ctx
);
5064 #endif /* CONFIG_FSE */
5066 if (need_event
|| kauth_authorize_fileop_has_listeners()) {
5067 GET_PATH(from_name
);
5068 if (from_name
== NULL
) {
5072 from_len
= MAXPATHLEN
;
5073 vn_getpath(fdvp
, from_name
, &from_len
);
5074 if ((from_len
+ 1 + fromnd
.ni_cnd
.cn_namelen
+ 1) < MAXPATHLEN
) {
5076 from_name
[from_len
-1] = '/';
5080 strlcpy(&from_name
[from_len
], fromnd
.ni_cnd
.cn_nameptr
, MAXPATHLEN
-from_len
);
5081 from_len
+= fromnd
.ni_cnd
.cn_namelen
+ 1;
5082 from_name
[from_len
] = '\0';
5086 if (to_name
== NULL
) {
5091 to_len
= MAXPATHLEN
;
5092 vn_getpath(tdvp
, to_name
, &to_len
);
5093 // if the path is not just "/", then append a "/"
5094 if ((to_len
+ 1 + tond
.ni_cnd
.cn_namelen
+ 1) < MAXPATHLEN
) {
5096 to_name
[to_len
-1] = '/';
5100 strlcpy(&to_name
[to_len
], tond
.ni_cnd
.cn_nameptr
, MAXPATHLEN
-to_len
);
5101 to_len
+= tond
.ni_cnd
.cn_namelen
+ 1;
5102 to_name
[to_len
] = '\0';
5106 error
= VNOP_RENAME(fdvp
, fvp
, &fromnd
.ni_cnd
,
5107 tdvp
, tvp
, &tond
.ni_cnd
,
5110 if (holding_mntlock
) {
5112 * we can drop our serialization
5115 mount_unlock_renames(locked_mp
);
5116 mount_drop(locked_mp
, 0);
5117 holding_mntlock
= 0;
5121 * We may encounter a race in the VNOP where the destination didn't
5122 * exist when we did the namei, but it does by the time we go and
5123 * try to create the entry. In this case, we should re-drive this rename
5124 * call from the top again. Currently, only HFS bubbles out ERECYCLE,
5125 * but other filesystem susceptible to this race could return it, too.
5127 if (error
== ERECYCLE
) {
5134 /* call out to allow 3rd party notification of rename.
5135 * Ignore result of kauth_authorize_fileop call.
5137 kauth_authorize_fileop(vfs_context_ucred(ctx
),
5138 KAUTH_FILEOP_RENAME
,
5139 (uintptr_t)from_name
, (uintptr_t)to_name
);
5142 if (from_name
!= NULL
&& to_name
!= NULL
) {
5144 add_fsevent(FSE_RENAME
, ctx
,
5145 FSE_ARG_STRING
, from_len
, from_name
,
5146 FSE_ARG_FINFO
, &from_finfo
,
5147 FSE_ARG_STRING
, to_len
, to_name
,
5148 FSE_ARG_FINFO
, &to_finfo
,
5151 add_fsevent(FSE_RENAME
, ctx
,
5152 FSE_ARG_STRING
, from_len
, from_name
,
5153 FSE_ARG_FINFO
, &from_finfo
,
5154 FSE_ARG_STRING
, to_len
, to_name
,
5158 #endif /* CONFIG_FSE */
5161 * update filesystem's mount point data
5164 char *cp
, *pathend
, *mpname
;
5170 mp
= fvp
->v_mountedhere
;
5172 if (vfs_busy(mp
, LK_NOWAIT
)) {
5176 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
5178 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
5180 /* find current mount point prefix */
5181 pathend
= &mp
->mnt_vfsstat
.f_mntonname
[0];
5182 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
5186 /* find last component of target name */
5187 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
5191 /* append name to prefix */
5192 maxlen
= MAXPATHLEN
- (pathend
- mp
->mnt_vfsstat
.f_mntonname
);
5193 bzero(pathend
, maxlen
);
5194 strlcpy(pathend
, mpname
, maxlen
);
5196 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
5201 * fix up name & parent pointers. note that we first
5202 * check that fvp has the same name/parent pointers it
5203 * had before the rename call... this is a 'weak' check
5206 if (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
) {
5209 update_flags
= VNODE_UPDATE_NAME
;
5212 update_flags
|= VNODE_UPDATE_PARENT
;
5214 vnode_update_identity(fvp
, tdvp
, tond
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_namelen
, tond
.ni_cnd
.cn_hash
, update_flags
);
5217 if (to_name
!= NULL
) {
5218 RELEASE_PATH(to_name
);
5221 if (from_name
!= NULL
) {
5222 RELEASE_PATH(from_name
);
5225 if (holding_mntlock
) {
5226 mount_unlock_renames(locked_mp
);
5227 mount_drop(locked_mp
, 0);
5228 holding_mntlock
= 0;
5232 * nameidone has to happen before we vnode_put(tdvp)
5233 * since it may need to release the fs_nodelock on the tdvp
5243 * nameidone has to happen before we vnode_put(fdvp)
5244 * since it may need to release the fs_nodelock on the fdvp
5254 * If things changed after we did the namei, then we will re-drive
5255 * this rename call from the top.
5266 * Make a directory file.
5268 * Returns: 0 Success
5271 * vnode_authorize:???
5276 mkdir1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
5280 int update_flags
= 0;
5281 struct nameidata nd
;
5283 AUDIT_ARG(mode
, vap
->va_mode
);
5284 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
5285 UIO_USERSPACE
, path
, ctx
);
5286 nd
.ni_cnd
.cn_flags
|= WILLBEDIR
;
5298 VATTR_SET(vap
, va_type
, VDIR
);
5301 error
= mac_vnode_check_create(ctx
,
5302 nd
.ni_dvp
, &nd
.ni_cnd
, vap
);
5307 /* authorize addition of a directory to the parent */
5308 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
)) != 0)
5312 /* make the directory */
5313 if ((error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
)) != 0)
5316 // Make sure the name & parent pointers are hooked up
5317 if (vp
->v_name
== NULL
)
5318 update_flags
|= VNODE_UPDATE_NAME
;
5319 if (vp
->v_parent
== NULLVP
)
5320 update_flags
|= VNODE_UPDATE_PARENT
;
5323 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
5326 add_fsevent(FSE_CREATE_DIR
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
5331 * nameidone has to happen before we vnode_put(dvp)
5332 * since it may need to release the fs_nodelock on the dvp
5345 mkdir_extended(proc_t p
, struct mkdir_extended_args
*uap
, __unused register_t
*retval
)
5348 kauth_filesec_t xsecdst
;
5349 struct vnode_attr va
;
5352 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
5353 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
5357 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
5358 if (xsecdst
!= NULL
)
5359 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
5361 ciferror
= mkdir1(vfs_context_current(), uap
->path
, &va
);
5362 if (xsecdst
!= NULL
)
5363 kauth_filesec_free(xsecdst
);
5368 mkdir(proc_t p
, struct mkdir_args
*uap
, __unused register_t
*retval
)
5370 struct vnode_attr va
;
5373 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
5375 return(mkdir1(vfs_context_current(), uap
->path
, &va
));
5379 * Remove a directory file.
5383 rmdir(__unused proc_t p
, struct rmdir_args
*uap
, __unused register_t
*retval
)
5387 struct nameidata nd
;
5388 vfs_context_t ctx
= vfs_context_current();
5390 int restart_flag
, oldvp_id
= -1;
5393 * This loop exists to restart rmdir in the unlikely case that two
5394 * processes are simultaneously trying to remove the same directory
5395 * containing orphaned appleDouble files.
5400 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
5401 UIO_USERSPACE
, uap
->path
, ctx
);
5411 * If being restarted check if the new vp
5412 * still has the same v_id.
5414 if (oldvp_id
!= -1 && oldvp_id
!= vp
->v_id
) {
5419 if (vp
->v_type
!= VDIR
) {
5421 * rmdir only deals with directories
5424 } else if (dvp
== vp
) {
5426 * No rmdir "." please.
5429 } else if (vp
->v_flag
& VROOT
) {
5431 * The root of a mounted filesystem cannot be deleted.
5436 error
= mac_vnode_check_unlink(ctx
, dvp
,
5440 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, ctx
);
5446 int has_listeners
= 0;
5450 need_event
= need_fsevent(FSE_DELETE
, dvp
);
5452 get_fse_info(vp
, &finfo
, ctx
);
5455 has_listeners
= kauth_authorize_fileop_has_listeners();
5456 if (need_event
|| has_listeners
) {
5463 vn_getpath(vp
, path
, &len
);
5466 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, ctx
);
5469 * Special case to remove orphaned AppleDouble
5470 * files. I don't like putting this in the kernel,
5471 * but carbon does not like putting this in carbon either,
5474 if (error
== ENOTEMPTY
) {
5475 error
= rmdir_remove_orphaned_appleDouble(vp
, ctx
, &restart_flag
);
5476 if (error
== EBUSY
) {
5477 oldvp_id
= vp
->v_id
;
5483 * Assuming everything went well, we will try the RMDIR again
5486 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, ctx
);
5490 * Call out to allow 3rd party notification of delete.
5491 * Ignore result of kauth_authorize_fileop call.
5494 if (has_listeners
) {
5495 kauth_authorize_fileop(vfs_context_ucred(ctx
),
5496 KAUTH_FILEOP_DELETE
,
5501 if (vp
->v_flag
& VISHARDLINK
) {
5502 // see the comment in unlink1() about why we update
5503 // the parent of a hard link when it is removed
5504 vnode_update_identity(vp
, NULL
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
5509 add_fsevent(FSE_DELETE
, ctx
,
5510 FSE_ARG_STRING
, len
, path
,
5511 FSE_ARG_FINFO
, &finfo
,
5522 * nameidone has to happen before we vnode_put(dvp)
5523 * since it may need to release the fs_nodelock on the dvp
5530 if (restart_flag
== 0) {
5531 wakeup_one((caddr_t
)vp
);
5534 tsleep(vp
, PVFS
, "rm AD", 1);
5536 } while (restart_flag
!= 0);
5542 /* Get direntry length padded to 8 byte alignment */
5543 #define DIRENT64_LEN(namlen) \
5544 ((sizeof(struct direntry) + (namlen) - (MAXPATHLEN-1) + 7) & ~7)
5547 vnode_readdir64(struct vnode
*vp
, struct uio
*uio
, int flags
, int *eofflag
,
5548 int *numdirent
, vfs_context_t ctxp
)
5550 /* Check if fs natively supports VNODE_READDIR_EXTENDED */
5551 if (vp
->v_mount
->mnt_vtable
->vfc_vfsflags
& VFC_VFSREADDIR_EXTENDED
) {
5552 return VNOP_READDIR(vp
, uio
, flags
, eofflag
, numdirent
, ctxp
);
5557 struct direntry entry64
;
5563 * Our kernel buffer needs to be smaller since re-packing
5564 * will expand each dirent. The worse case (when the name
5565 * length is 3) corresponds to a struct direntry size of 32
5566 * bytes (8-byte aligned) and a struct dirent size of 12 bytes
5567 * (4-byte aligned). So having a buffer that is 3/8 the size
5568 * will prevent us from reading more than we can pack.
5570 * Since this buffer is wired memory, we will limit the
5571 * buffer size to a maximum of 32K. We would really like to
5572 * use 32K in the MIN(), but we use magic number 87371 to
5573 * prevent uio_resid() * 3 / 8 from overflowing.
5575 bufsize
= 3 * MIN(uio_resid(uio
), 87371) / 8;
5576 MALLOC(bufptr
, void *, bufsize
, M_TEMP
, M_WAITOK
);
5578 auio
= uio_create(1, 0, UIO_SYSSPACE32
, UIO_READ
);
5579 uio_addiov(auio
, (uintptr_t)bufptr
, bufsize
);
5580 auio
->uio_offset
= uio
->uio_offset
;
5582 error
= VNOP_READDIR(vp
, auio
, 0, eofflag
, numdirent
, ctxp
);
5584 dep
= (struct dirent
*)bufptr
;
5585 bytesread
= bufsize
- uio_resid(auio
);
5588 * Convert all the entries and copy them out to user's buffer.
5590 while (error
== 0 && (char *)dep
< ((char *)bufptr
+ bytesread
)) {
5591 /* Convert a dirent to a dirent64. */
5592 entry64
.d_ino
= dep
->d_ino
;
5593 entry64
.d_seekoff
= 0;
5594 entry64
.d_reclen
= DIRENT64_LEN(dep
->d_namlen
);
5595 entry64
.d_namlen
= dep
->d_namlen
;
5596 entry64
.d_type
= dep
->d_type
;
5597 bcopy(dep
->d_name
, entry64
.d_name
, dep
->d_namlen
+ 1);
5599 /* Move to next entry. */
5600 dep
= (struct dirent
*)((char *)dep
+ dep
->d_reclen
);
5602 /* Copy entry64 to user's buffer. */
5603 error
= uiomove((caddr_t
)&entry64
, entry64
.d_reclen
, uio
);
5606 /* Update the real offset using the offset we got from VNOP_READDIR. */
5608 uio
->uio_offset
= auio
->uio_offset
;
5611 FREE(bufptr
, M_TEMP
);
5617 * Read a block of directory entries in a file system independent format.
5620 getdirentries_common(int fd
, user_addr_t bufp
, user_size_t bufsize
, ssize_t
*bytesread
,
5621 off_t
*offset
, int flags
)
5624 struct vfs_context context
= *vfs_context_current(); /* local copy */
5625 struct fileproc
*fp
;
5627 int spacetype
= proc_is64bit(vfs_context_proc(&context
)) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5629 int error
, eofflag
, numdirent
;
5630 char uio_buf
[ UIO_SIZEOF(1) ];
5632 error
= fp_getfvp(vfs_context_proc(&context
), fd
, &fp
, &vp
);
5636 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
5637 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
5643 error
= mac_file_check_change_offset(vfs_context_ucred(&context
), fp
->f_fglob
);
5647 if ( (error
= vnode_getwithref(vp
)) ) {
5650 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
5653 if (vp
->v_type
!= VDIR
) {
5654 (void)vnode_put(vp
);
5660 error
= mac_vnode_check_readdir(&context
, vp
);
5662 (void)vnode_put(vp
);
5667 loff
= fp
->f_fglob
->fg_offset
;
5668 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
5669 uio_addiov(auio
, bufp
, bufsize
);
5671 if (flags
& VNODE_READDIR_EXTENDED
) {
5672 error
= vnode_readdir64(vp
, auio
, flags
, &eofflag
, &numdirent
, &context
);
5673 fp
->f_fglob
->fg_offset
= uio_offset(auio
);
5675 error
= VNOP_READDIR(vp
, auio
, 0, &eofflag
, &numdirent
, &context
);
5676 fp
->f_fglob
->fg_offset
= uio_offset(auio
);
5679 (void)vnode_put(vp
);
5683 if ((user_ssize_t
)bufsize
== uio_resid(auio
)){
5684 if (union_dircheckp
) {
5685 error
= union_dircheckp(&vp
, fp
, &context
);
5692 if ((vp
->v_flag
& VROOT
) && (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
5693 struct vnode
*tvp
= vp
;
5694 vp
= vp
->v_mount
->mnt_vnodecovered
;
5695 vnode_getwithref(vp
);
5697 fp
->f_fglob
->fg_data
= (caddr_t
) vp
;
5698 fp
->f_fglob
->fg_offset
= 0;
5709 // LP64todo - fix this
5710 *bytesread
= bufsize
- uio_resid(auio
);
5718 getdirentries(__unused
struct proc
*p
, struct getdirentries_args
*uap
, register_t
*retval
)
5725 AUDIT_ARG(fd
, uap
->fd
);
5726 error
= getdirentries_common(uap
->fd
, uap
->buf
, uap
->count
, &bytesread
, &offset
, 0);
5729 loff
= (long)offset
;
5730 error
= copyout((caddr_t
)&loff
, uap
->basep
, sizeof(long));
5731 *retval
= bytesread
;
5737 getdirentries64(__unused
struct proc
*p
, struct getdirentries64_args
*uap
, user_ssize_t
*retval
)
5743 AUDIT_ARG(fd
, uap
->fd
);
5744 error
= getdirentries_common(uap
->fd
, uap
->buf
, uap
->bufsize
, &bytesread
, &offset
, VNODE_READDIR_EXTENDED
);
5747 *retval
= bytesread
;
5748 error
= copyout((caddr_t
)&offset
, uap
->position
, sizeof(off_t
));
5755 * Set the mode mask for creation of filesystem nodes.
5757 #warning XXX implement xsecurity
5759 #define UMASK_NOXSECURITY (void *)1 /* leave existing xsecurity alone */
5761 umask1(proc_t p
, int newmask
, __unused kauth_filesec_t fsec
, register_t
*retval
)
5763 struct filedesc
*fdp
;
5765 AUDIT_ARG(mask
, newmask
);
5768 *retval
= fdp
->fd_cmask
;
5769 fdp
->fd_cmask
= newmask
& ALLPERMS
;
5776 umask_extended(proc_t p
, struct umask_extended_args
*uap
, register_t
*retval
)
5779 kauth_filesec_t xsecdst
;
5781 xsecdst
= KAUTH_FILESEC_NONE
;
5782 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
5783 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
5786 xsecdst
= KAUTH_FILESEC_NONE
;
5789 ciferror
= umask1(p
, uap
->newmask
, xsecdst
, retval
);
5791 if (xsecdst
!= KAUTH_FILESEC_NONE
)
5792 kauth_filesec_free(xsecdst
);
5797 umask(proc_t p
, struct umask_args
*uap
, register_t
*retval
)
5799 return(umask1(p
, uap
->newmask
, UMASK_NOXSECURITY
, retval
));
5803 * Void all references to file by ripping underlying filesystem
5808 revoke(proc_t p
, struct revoke_args
*uap
, __unused register_t
*retval
)
5811 struct vnode_attr va
;
5812 vfs_context_t ctx
= vfs_context_current();
5814 struct nameidata nd
;
5816 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
5817 UIO_USERSPACE
, uap
->path
, ctx
);
5826 error
= mac_vnode_check_revoke(ctx
, vp
);
5832 VATTR_WANTED(&va
, va_uid
);
5833 if ((error
= vnode_getattr(vp
, &va
, ctx
)))
5835 if (kauth_cred_getuid(vfs_context_ucred(ctx
)) != va
.va_uid
&&
5836 (error
= suser(vfs_context_ucred(ctx
), &p
->p_acflag
)))
5838 if (vp
->v_usecount
> 1 || (vp
->v_flag
& VALIASED
))
5839 VNOP_REVOKE(vp
, REVOKEALL
, ctx
);
5847 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
5848 * The following system calls are designed to support features
5849 * which are specific to the HFS & HFS Plus volume formats
5852 #ifdef __APPLE_API_OBSOLETE
5854 /************************************************/
5855 /* *** Following calls will be deleted soon *** */
5856 /************************************************/
5859 * Make a complex file. A complex file is one with multiple forks (data streams)
5863 mkcomplex(__unused proc_t p
, __unused
struct mkcomplex_args
*uap
, __unused register_t
*retval
)
5869 * Extended stat call which returns volumeid and vnodeid as well as other info
5873 statv(__unused proc_t p
,
5874 __unused
struct statv_args
*uap
,
5875 __unused register_t
*retval
)
5877 return (ENOTSUP
); /* We'll just return an error for now */
5879 } /* end of statv system call */
5882 * Extended lstat call which returns volumeid and vnodeid as well as other info
5886 lstatv(__unused proc_t p
,
5887 __unused
struct lstatv_args
*uap
,
5888 __unused register_t
*retval
)
5890 return (ENOTSUP
); /* We'll just return an error for now */
5891 } /* end of lstatv system call */
5894 * Extended fstat call which returns volumeid and vnodeid as well as other info
5898 fstatv(__unused proc_t p
,
5899 __unused
struct fstatv_args
*uap
,
5900 __unused register_t
*retval
)
5902 return (ENOTSUP
); /* We'll just return an error for now */
5903 } /* end of fstatv system call */
5906 /************************************************/
5907 /* *** Preceding calls will be deleted soon *** */
5908 /************************************************/
5910 #endif /* __APPLE_API_OBSOLETE */
5913 * Obtain attribute information on objects in a directory while enumerating
5914 * the directory. This call does not yet support union mounted directories.
5916 * 1.union mounted directories.
5921 getdirentriesattr (proc_t p
, struct getdirentriesattr_args
*uap
, register_t
*retval
)
5924 struct fileproc
*fp
;
5926 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5931 struct attrlist attributelist
;
5932 vfs_context_t ctx
= vfs_context_current();
5934 char uio_buf
[ UIO_SIZEOF(1) ];
5935 kauth_action_t action
;
5939 /* Get the attributes into kernel space */
5940 if ((error
= copyin(uap
->alist
, (caddr_t
)&attributelist
, sizeof(attributelist
)))) {
5943 if ((error
= copyin(uap
->count
, (caddr_t
)&count
, sizeof(count
)))) {
5946 if ( (error
= fp_getfvp(p
, fd
, &fp
, &vp
)) ) {
5949 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
5950 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
5957 error
= mac_file_check_change_offset(vfs_context_ucred(ctx
),
5964 if ( (error
= vnode_getwithref(vp
)) )
5967 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
5969 if (vp
->v_type
!= VDIR
) {
5970 (void)vnode_put(vp
);
5976 error
= mac_vnode_check_readdir(ctx
, vp
);
5978 (void)vnode_put(vp
);
5983 /* set up the uio structure which will contain the users return buffer */
5984 loff
= fp
->f_fglob
->fg_offset
;
5985 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
5986 &uio_buf
[0], sizeof(uio_buf
));
5987 uio_addiov(auio
, uap
->buffer
, uap
->buffersize
);
5990 * If the only item requested is file names, we can let that past with
5991 * just LIST_DIRECTORY. If they want any other attributes, that means
5992 * they need SEARCH as well.
5994 action
= KAUTH_VNODE_LIST_DIRECTORY
;
5995 if ((attributelist
.commonattr
& ~ATTR_CMN_NAME
) ||
5996 attributelist
.fileattr
|| attributelist
.dirattr
)
5997 action
|= KAUTH_VNODE_SEARCH
;
5999 if ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) == 0) {
6000 u_long ulcount
= count
;
6002 error
= VNOP_READDIRATTR(vp
, &attributelist
, auio
,
6004 uap
->options
, (unsigned long *)&newstate
, &eofflag
,
6009 (void)vnode_put(vp
);
6013 fp
->f_fglob
->fg_offset
= uio_offset(auio
); /* should be multiple of dirent, not variable */
6015 if ((error
= copyout((caddr_t
) &count
, uap
->count
, sizeof(count
))))
6017 if ((error
= copyout((caddr_t
) &newstate
, uap
->newstate
, sizeof(newstate
))))
6019 if ((error
= copyout((caddr_t
) &loff
, uap
->basep
, sizeof(loff
))))
6022 *retval
= eofflag
; /* similar to getdirentries */
6026 return (error
); /* return error earlier, an retval of 0 or 1 now */
6028 } /* end of getdirentryattr system call */
6031 * Exchange data between two files
6036 exchangedata (__unused proc_t p
, struct exchangedata_args
*uap
, __unused register_t
*retval
)
6039 struct nameidata fnd
, snd
;
6040 vfs_context_t ctx
= vfs_context_current();
6048 fse_info f_finfo
, s_finfo
;
6051 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
6053 NDINIT(&fnd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
6054 UIO_USERSPACE
, uap
->path1
, ctx
);
6056 error
= namei(&fnd
);
6063 NDINIT(&snd
, LOOKUP
| CN_NBMOUNTLOOK
, nameiflags
| AUDITVNPATH2
,
6064 UIO_USERSPACE
, uap
->path2
, ctx
);
6066 error
= namei(&snd
);
6075 * if the files are the same, return an inval error
6083 * if the files are on different volumes, return an error
6085 if (svp
->v_mount
!= fvp
->v_mount
) {
6091 error
= mac_vnode_check_exchangedata(ctx
,
6096 if (((error
= vnode_authorize(fvp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, ctx
)) != 0) ||
6097 ((error
= vnode_authorize(svp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, ctx
)) != 0))
6102 need_fsevent(FSE_EXCHANGE
, fvp
) ||
6104 kauth_authorize_fileop_has_listeners()) {
6107 if (fpath
== NULL
|| spath
== NULL
) {
6113 if (vn_getpath(fvp
, fpath
, &flen
) != 0 || fpath
[0] == '\0') {
6114 printf("exchange: vn_getpath(fvp=%p) failed <<%s>>\n",
6117 if (vn_getpath(svp
, spath
, &slen
) != 0 || spath
[0] == '\0') {
6118 printf("exchange: vn_getpath(svp=%p) failed <<%s>>\n",
6122 get_fse_info(fvp
, &f_finfo
, ctx
);
6123 get_fse_info(svp
, &s_finfo
, ctx
);
6126 /* Ok, make the call */
6127 error
= VNOP_EXCHANGE(fvp
, svp
, 0, ctx
);
6130 const char *tmpname
;
6132 if (fpath
!= NULL
&& spath
!= NULL
) {
6133 /* call out to allow 3rd party notification of exchangedata.
6134 * Ignore result of kauth_authorize_fileop call.
6136 kauth_authorize_fileop(vfs_context_ucred(ctx
), KAUTH_FILEOP_EXCHANGE
,
6137 (uintptr_t)fpath
, (uintptr_t)spath
);
6141 tmpname
= fvp
->v_name
;
6142 fvp
->v_name
= svp
->v_name
;
6143 svp
->v_name
= tmpname
;
6145 if (fvp
->v_parent
!= svp
->v_parent
) {
6148 tmp
= fvp
->v_parent
;
6149 fvp
->v_parent
= svp
->v_parent
;
6150 svp
->v_parent
= tmp
;
6152 name_cache_unlock();
6155 if (fpath
!= NULL
&& spath
!= NULL
) {
6156 add_fsevent(FSE_EXCHANGE
, ctx
,
6157 FSE_ARG_STRING
, flen
, fpath
,
6158 FSE_ARG_FINFO
, &f_finfo
,
6159 FSE_ARG_STRING
, slen
, spath
,
6160 FSE_ARG_FINFO
, &s_finfo
,
6168 RELEASE_PATH(fpath
);
6170 RELEASE_PATH(spath
);
6181 searchfs(proc_t p
, struct searchfs_args
*uap
, __unused register_t
*retval
)
6186 struct nameidata nd
;
6187 struct user_fssearchblock searchblock
;
6188 struct searchstate
*state
;
6189 struct attrlist
*returnattrs
;
6190 void *searchparams1
,*searchparams2
;
6192 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6196 vfs_context_t ctx
= vfs_context_current();
6197 char uio_buf
[ UIO_SIZEOF(1) ];
6199 /* Start by copying in fsearchblock paramater list */
6200 if (IS_64BIT_PROCESS(p
)) {
6201 error
= copyin(uap
->searchblock
, (caddr_t
) &searchblock
, sizeof(searchblock
));
6204 struct fssearchblock tmp_searchblock
;
6205 error
= copyin(uap
->searchblock
, (caddr_t
) &tmp_searchblock
, sizeof(tmp_searchblock
));
6206 // munge into 64-bit version
6207 searchblock
.returnattrs
= CAST_USER_ADDR_T(tmp_searchblock
.returnattrs
);
6208 searchblock
.returnbuffer
= CAST_USER_ADDR_T(tmp_searchblock
.returnbuffer
);
6209 searchblock
.returnbuffersize
= tmp_searchblock
.returnbuffersize
;
6210 searchblock
.maxmatches
= tmp_searchblock
.maxmatches
;
6211 searchblock
.timelimit
.tv_sec
= tmp_searchblock
.timelimit
.tv_sec
;
6212 searchblock
.timelimit
.tv_usec
= tmp_searchblock
.timelimit
.tv_usec
;
6213 searchblock
.searchparams1
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams1
);
6214 searchblock
.sizeofsearchparams1
= tmp_searchblock
.sizeofsearchparams1
;
6215 searchblock
.searchparams2
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams2
);
6216 searchblock
.sizeofsearchparams2
= tmp_searchblock
.sizeofsearchparams2
;
6217 searchblock
.searchattrs
= tmp_searchblock
.searchattrs
;
6222 /* Do a sanity check on sizeofsearchparams1 and sizeofsearchparams2.
6224 if (searchblock
.sizeofsearchparams1
> SEARCHFS_MAX_SEARCHPARMS
||
6225 searchblock
.sizeofsearchparams2
> SEARCHFS_MAX_SEARCHPARMS
)
6228 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
6229 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
6230 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
6233 mallocsize
= searchblock
.sizeofsearchparams1
+ searchblock
.sizeofsearchparams2
+
6234 sizeof(struct attrlist
) + sizeof(struct searchstate
);
6236 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
6238 /* Now set up the various pointers to the correct place in our newly allocated memory */
6240 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
6241 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
6242 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
6244 /* Now copy in the stuff given our local variables. */
6246 if ((error
= copyin(searchblock
.searchparams1
, searchparams1
, searchblock
.sizeofsearchparams1
)))
6249 if ((error
= copyin(searchblock
.searchparams2
, searchparams2
, searchblock
.sizeofsearchparams2
)))
6252 if ((error
= copyin(searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
))))
6255 if ((error
= copyin(uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
))))
6258 /* set up the uio structure which will contain the users return buffer */
6260 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
6261 &uio_buf
[0], sizeof(uio_buf
));
6262 uio_addiov(auio
, searchblock
.returnbuffer
, searchblock
.returnbuffersize
);
6265 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
6266 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
6267 UIO_USERSPACE
, uap
->path
, ctx
);
6278 * If searchblock.maxmatches == 0, then skip the search. This has happened
6279 * before and sometimes the underlyning code doesnt deal with it well.
6281 if (searchblock
.maxmatches
== 0) {
6287 Allright, we have everything we need, so lets make that call.
6289 We keep special track of the return value from the file system:
6290 EAGAIN is an acceptable error condition that shouldn't keep us
6291 from copying out any results...
6294 fserror
= VNOP_SEARCHFS(vp
,
6297 &searchblock
.searchattrs
,
6298 searchblock
.maxmatches
,
6299 &searchblock
.timelimit
,
6312 /* Now copy out the stuff that needs copying out. That means the number of matches, the
6313 search state. Everything was already put into he return buffer by the vop call. */
6315 if ((error
= copyout((caddr_t
) state
, uap
->state
, sizeof(struct searchstate
))) != 0)
6318 if ((error
= suulong(uap
->nummatches
, (uint64_t)nummatches
)) != 0)
6325 FREE(searchparams1
,M_TEMP
);
6330 } /* end of searchfs system call */
6334 * Make a filesystem-specific control call:
6338 fsctl (proc_t p
, struct fsctl_args
*uap
, __unused register_t
*retval
)
6342 struct nameidata nd
;
6344 u_long cmd
= uap
->cmd
;
6346 #define STK_PARAMS 128
6347 char stkbuf
[STK_PARAMS
];
6349 vfs_context_t ctx
= vfs_context_current();
6351 size
= IOCPARM_LEN(cmd
);
6352 if (size
> IOCPARM_MAX
) return (EINVAL
);
6354 is64bit
= proc_is64bit(p
);
6357 if (size
> sizeof (stkbuf
)) {
6358 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
6366 error
= copyin(uap
->data
, data
, size
);
6367 if (error
) goto FSCtl_Exit
;
6370 *(user_addr_t
*)data
= uap
->data
;
6373 *(uint32_t *)data
= (uint32_t)uap
->data
;
6376 } else if ((cmd
& IOC_OUT
) && size
) {
6378 * Zero the buffer so the user always
6379 * gets back something deterministic.
6382 } else if (cmd
& IOC_VOID
) {
6384 *(user_addr_t
*)data
= uap
->data
;
6387 *(uint32_t *)data
= (uint32_t)uap
->data
;
6391 /* Get the vnode for the file we are getting info on: */
6393 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
6394 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, uap
->path
, ctx
);
6395 if ((error
= namei(&nd
))) goto FSCtl_Exit
;
6398 error
= mac_mount_check_fsctl(ctx
, vnode_mount(nd
.ni_vp
), cmd
);
6400 vnode_put(nd
.ni_vp
);
6406 /* Invoke the filesystem-specific code */
6407 error
= VNOP_IOCTL(nd
.ni_vp
, IOCBASECMD(cmd
), data
, uap
->options
, ctx
);
6409 vnode_put(nd
.ni_vp
);
6413 * Copy any data to user, size was
6414 * already set and checked above.
6416 if (error
== 0 && (cmd
& IOC_OUT
) && size
)
6417 error
= copyout(data
, uap
->data
, size
);
6420 if (memp
) kfree(memp
, size
);
6424 /* end of fsctl system call */
6427 * An in-kernel sync for power management to call.
6429 __private_extern__
int
6434 struct sync_args data
;
6439 error
= sync(current_proc(), &data
, &retval
[0]);
6443 } /* end of sync_internal call */
6447 * Retrieve the data of an extended attribute.
6450 getxattr(proc_t p
, struct getxattr_args
*uap
, user_ssize_t
*retval
)
6453 struct nameidata nd
;
6454 char attrname
[XATTR_MAXNAMELEN
+1];
6455 vfs_context_t ctx
= vfs_context_current();
6457 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6458 size_t attrsize
= 0;
6462 char uio_buf
[ UIO_SIZEOF(1) ];
6464 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6467 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
6468 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, ctx
);
6469 if ((error
= namei(&nd
))) {
6475 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
6478 if (xattr_protected(attrname
)) {
6482 if (uap
->value
&& uap
->size
> 0) {
6483 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
6484 &uio_buf
[0], sizeof(uio_buf
));
6485 uio_addiov(auio
, uap
->value
, uap
->size
);
6488 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, ctx
);
6493 *retval
= uap
->size
- uio_resid(auio
);
6495 *retval
= (user_ssize_t
)attrsize
;
6502 * Retrieve the data of an extended attribute.
6505 fgetxattr(proc_t p
, struct fgetxattr_args
*uap
, user_ssize_t
*retval
)
6508 char attrname
[XATTR_MAXNAMELEN
+1];
6510 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6511 size_t attrsize
= 0;
6514 char uio_buf
[ UIO_SIZEOF(1) ];
6516 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6519 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
6522 if ( (error
= vnode_getwithref(vp
)) ) {
6526 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
6529 if (xattr_protected(attrname
)) {
6533 if (uap
->value
&& uap
->size
> 0) {
6534 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
6535 &uio_buf
[0], sizeof(uio_buf
));
6536 uio_addiov(auio
, uap
->value
, uap
->size
);
6539 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, vfs_context_current());
6541 (void)vnode_put(vp
);
6545 *retval
= uap
->size
- uio_resid(auio
);
6547 *retval
= (user_ssize_t
)attrsize
;
6553 * Set the data of an extended attribute.
6556 setxattr(proc_t p
, struct setxattr_args
*uap
, int *retval
)
6559 struct nameidata nd
;
6560 char attrname
[XATTR_MAXNAMELEN
+1];
6561 vfs_context_t ctx
= vfs_context_current();
6563 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6567 char uio_buf
[ UIO_SIZEOF(1) ];
6569 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6572 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
6575 if (xattr_protected(attrname
))
6577 if (uap
->size
!= 0 && uap
->value
== 0) {
6581 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
6582 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, ctx
);
6583 if ((error
= namei(&nd
))) {
6589 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
6590 &uio_buf
[0], sizeof(uio_buf
));
6591 uio_addiov(auio
, uap
->value
, uap
->size
);
6593 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, ctx
);
6596 add_fsevent(FSE_XATTR_MODIFIED
, ctx
,
6607 * Set the data of an extended attribute.
6610 fsetxattr(proc_t p
, struct fsetxattr_args
*uap
, int *retval
)
6613 char attrname
[XATTR_MAXNAMELEN
+1];
6615 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6618 char uio_buf
[ UIO_SIZEOF(1) ];
6619 vfs_context_t ctx
= vfs_context_current();
6621 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6624 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
6627 if (xattr_protected(attrname
))
6629 if (uap
->size
!= 0 && uap
->value
== 0) {
6632 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
6635 if ( (error
= vnode_getwithref(vp
)) ) {
6639 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
6640 &uio_buf
[0], sizeof(uio_buf
));
6641 uio_addiov(auio
, uap
->value
, uap
->size
);
6643 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, vfs_context_current());
6646 add_fsevent(FSE_XATTR_MODIFIED
, ctx
,
6658 * Remove an extended attribute.
6660 #warning "code duplication"
6662 removexattr(proc_t p
, struct removexattr_args
*uap
, int *retval
)
6665 struct nameidata nd
;
6666 char attrname
[XATTR_MAXNAMELEN
+1];
6667 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6668 vfs_context_t ctx
= vfs_context_current();
6673 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6676 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
6680 if (xattr_protected(attrname
))
6682 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
6683 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, ctx
);
6684 if ((error
= namei(&nd
))) {
6690 error
= vn_removexattr(vp
, attrname
, uap
->options
, ctx
);
6693 add_fsevent(FSE_XATTR_REMOVED
, ctx
,
6704 * Remove an extended attribute.
6706 #warning "code duplication"
6708 fremovexattr(__unused proc_t p
, struct fremovexattr_args
*uap
, int *retval
)
6711 char attrname
[XATTR_MAXNAMELEN
+1];
6714 vfs_context_t ctx
= vfs_context_current();
6716 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6719 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
6723 if (xattr_protected(attrname
))
6725 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
6728 if ( (error
= vnode_getwithref(vp
)) ) {
6733 error
= vn_removexattr(vp
, attrname
, uap
->options
, vfs_context_current());
6736 add_fsevent(FSE_XATTR_REMOVED
, ctx
,
6748 * Retrieve the list of extended attribute names.
6750 #warning "code duplication"
6752 listxattr(proc_t p
, struct listxattr_args
*uap
, user_ssize_t
*retval
)
6755 struct nameidata nd
;
6756 vfs_context_t ctx
= vfs_context_current();
6758 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6759 size_t attrsize
= 0;
6762 char uio_buf
[ UIO_SIZEOF(1) ];
6764 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6767 nameiflags
= ((uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
) | NOTRIGGER
;
6768 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, ctx
);
6769 if ((error
= namei(&nd
))) {
6774 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
6775 // LP64todo - fix this!
6776 auio
= uio_createwithbuffer(1, 0, spacetype
,
6777 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
6778 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
6781 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, ctx
);
6785 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
6787 *retval
= (user_ssize_t
)attrsize
;
6793 * Retrieve the list of extended attribute names.
6795 #warning "code duplication"
6797 flistxattr(proc_t p
, struct flistxattr_args
*uap
, user_ssize_t
*retval
)
6801 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6802 size_t attrsize
= 0;
6804 char uio_buf
[ UIO_SIZEOF(1) ];
6806 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6809 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
6812 if ( (error
= vnode_getwithref(vp
)) ) {
6816 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
6817 // LP64todo - fix this!
6818 auio
= uio_createwithbuffer(1, 0, spacetype
,
6819 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
6820 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
6823 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, vfs_context_current());
6828 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
6830 *retval
= (user_ssize_t
)attrsize
;
6836 * Common routine to handle various flavors of statfs data heading out
6839 * Returns: 0 Success
6843 munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
6844 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
6845 boolean_t partial_copy
)
6848 int my_size
, copy_size
;
6851 struct user_statfs sfs
;
6852 my_size
= copy_size
= sizeof(sfs
);
6853 bzero(&sfs
, my_size
);
6854 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
6855 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
6856 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
6857 sfs
.f_bsize
= (user_long_t
)sfsp
->f_bsize
;
6858 sfs
.f_iosize
= (user_long_t
)sfsp
->f_iosize
;
6859 sfs
.f_blocks
= (user_long_t
)sfsp
->f_blocks
;
6860 sfs
.f_bfree
= (user_long_t
)sfsp
->f_bfree
;
6861 sfs
.f_bavail
= (user_long_t
)sfsp
->f_bavail
;
6862 sfs
.f_files
= (user_long_t
)sfsp
->f_files
;
6863 sfs
.f_ffree
= (user_long_t
)sfsp
->f_ffree
;
6864 sfs
.f_fsid
= sfsp
->f_fsid
;
6865 sfs
.f_owner
= sfsp
->f_owner
;
6866 strlcpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
);
6867 strlcpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
);
6868 strlcpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
);
6871 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
6873 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
6877 my_size
= copy_size
= sizeof(sfs
);
6878 bzero(&sfs
, my_size
);
6880 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
6881 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
6882 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
6885 * It's possible for there to be more than 2^^31 blocks in the filesystem, so we
6886 * have to fudge the numbers here in that case. We inflate the blocksize in order
6887 * to reflect the filesystem size as best we can.
6889 if ((sfsp
->f_blocks
> LONG_MAX
)
6890 /* Hack for 4061702 . I think the real fix is for Carbon to
6891 * look for some volume capability and not depend on hidden
6892 * semantics agreed between a FS and carbon.
6893 * f_blocks, f_bfree, and f_bavail set to -1 is the trigger
6894 * for Carbon to set bNoVolumeSizes volume attribute.
6895 * Without this the webdavfs files cannot be copied onto
6896 * disk as they look huge. This change should not affect
6897 * XSAN as they should not setting these to -1..
6899 && (sfsp
->f_blocks
!= 0xffffffffffffffffULL
)
6900 && (sfsp
->f_bfree
!= 0xffffffffffffffffULL
)
6901 && (sfsp
->f_bavail
!= 0xffffffffffffffffULL
)) {
6905 * Work out how far we have to shift the block count down to make it fit.
6906 * Note that it's possible to have to shift so far that the resulting
6907 * blocksize would be unreportably large. At that point, we will clip
6908 * any values that don't fit.
6910 * For safety's sake, we also ensure that f_iosize is never reported as
6911 * being smaller than f_bsize.
6913 for (shift
= 0; shift
< 32; shift
++) {
6914 if ((sfsp
->f_blocks
>> shift
) <= LONG_MAX
)
6916 if ((sfsp
->f_bsize
<< (shift
+ 1)) > LONG_MAX
)
6919 #define __SHIFT_OR_CLIP(x, s) ((((x) >> (s)) > LONG_MAX) ? LONG_MAX : ((x) >> (s)))
6920 sfs
.f_blocks
= (long)__SHIFT_OR_CLIP(sfsp
->f_blocks
, shift
);
6921 sfs
.f_bfree
= (long)__SHIFT_OR_CLIP(sfsp
->f_bfree
, shift
);
6922 sfs
.f_bavail
= (long)__SHIFT_OR_CLIP(sfsp
->f_bavail
, shift
);
6923 #undef __SHIFT_OR_CLIP
6924 sfs
.f_bsize
= (long)(sfsp
->f_bsize
<< shift
);
6925 sfs
.f_iosize
= lmax(sfsp
->f_iosize
, sfsp
->f_bsize
);
6927 /* filesystem is small enough to be reported honestly */
6928 sfs
.f_bsize
= (long)sfsp
->f_bsize
;
6929 sfs
.f_iosize
= (long)sfsp
->f_iosize
;
6930 sfs
.f_blocks
= (long)sfsp
->f_blocks
;
6931 sfs
.f_bfree
= (long)sfsp
->f_bfree
;
6932 sfs
.f_bavail
= (long)sfsp
->f_bavail
;
6934 sfs
.f_files
= (long)sfsp
->f_files
;
6935 sfs
.f_ffree
= (long)sfsp
->f_ffree
;
6936 sfs
.f_fsid
= sfsp
->f_fsid
;
6937 sfs
.f_owner
= sfsp
->f_owner
;
6938 strlcpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
);
6939 strlcpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
);
6940 strlcpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
);
6943 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
6945 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
6948 if (sizep
!= NULL
) {
6955 * copy stat structure into user_stat structure.
6957 void munge_stat(struct stat
*sbp
, struct user_stat
*usbp
)
6959 bzero(usbp
, sizeof(struct user_stat
));
6961 usbp
->st_dev
= sbp
->st_dev
;
6962 usbp
->st_ino
= sbp
->st_ino
;
6963 usbp
->st_mode
= sbp
->st_mode
;
6964 usbp
->st_nlink
= sbp
->st_nlink
;
6965 usbp
->st_uid
= sbp
->st_uid
;
6966 usbp
->st_gid
= sbp
->st_gid
;
6967 usbp
->st_rdev
= sbp
->st_rdev
;
6968 #ifndef _POSIX_C_SOURCE
6969 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
6970 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
6971 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
6972 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
6973 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
6974 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
6976 usbp
->st_atime
= sbp
->st_atime
;
6977 usbp
->st_atimensec
= sbp
->st_atimensec
;
6978 usbp
->st_mtime
= sbp
->st_mtime
;
6979 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
6980 usbp
->st_ctime
= sbp
->st_ctime
;
6981 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
6983 usbp
->st_size
= sbp
->st_size
;
6984 usbp
->st_blocks
= sbp
->st_blocks
;
6985 usbp
->st_blksize
= sbp
->st_blksize
;
6986 usbp
->st_flags
= sbp
->st_flags
;
6987 usbp
->st_gen
= sbp
->st_gen
;
6988 usbp
->st_lspare
= sbp
->st_lspare
;
6989 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
6990 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];
6994 * copy stat64 structure into user_stat64 structure.
6996 void munge_stat64(struct stat64
*sbp
, struct user_stat64
*usbp
)
6998 bzero(usbp
, sizeof(struct user_stat
));
7000 usbp
->st_dev
= sbp
->st_dev
;
7001 usbp
->st_ino
= sbp
->st_ino
;
7002 usbp
->st_mode
= sbp
->st_mode
;
7003 usbp
->st_nlink
= sbp
->st_nlink
;
7004 usbp
->st_uid
= sbp
->st_uid
;
7005 usbp
->st_gid
= sbp
->st_gid
;
7006 usbp
->st_rdev
= sbp
->st_rdev
;
7007 #ifndef _POSIX_C_SOURCE
7008 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
7009 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
7010 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
7011 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
7012 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
7013 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
7014 usbp
->st_birthtimespec
.tv_sec
= sbp
->st_birthtimespec
.tv_sec
;
7015 usbp
->st_birthtimespec
.tv_nsec
= sbp
->st_birthtimespec
.tv_nsec
;
7017 usbp
->st_atime
= sbp
->st_atime
;
7018 usbp
->st_atimensec
= sbp
->st_atimensec
;
7019 usbp
->st_mtime
= sbp
->st_mtime
;
7020 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
7021 usbp
->st_ctime
= sbp
->st_ctime
;
7022 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
7023 usbp
->st_birthtime
= sbp
->st_birthtime
;
7024 usbp
->st_birthtimensec
= sbp
->st_birthtimensec
;
7026 usbp
->st_size
= sbp
->st_size
;
7027 usbp
->st_blocks
= sbp
->st_blocks
;
7028 usbp
->st_blksize
= sbp
->st_blksize
;
7029 usbp
->st_flags
= sbp
->st_flags
;
7030 usbp
->st_gen
= sbp
->st_gen
;
7031 usbp
->st_lspare
= sbp
->st_lspare
;
7032 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
7033 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];