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>
98 #include <machine/cons.h>
99 #include <machine/limits.h>
100 #include <miscfs/specfs/specdev.h>
101 #include <miscfs/union/union.h>
103 #include <bsm/audit_kernel.h>
104 #include <bsm/audit_kevents.h>
106 #include <mach/mach_types.h>
107 #include <kern/kern_types.h>
108 #include <kern/kalloc.h>
110 #include <vm/vm_pageout.h>
112 #include <libkern/OSAtomic.h>
115 #include <security/mac.h>
116 #include <security/mac_framework.h>
120 #define GET_PATH(x) \
121 (x) = get_pathbuff();
122 #define RELEASE_PATH(x) \
125 #define GET_PATH(x) \
126 MALLOC_ZONE((x), char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
127 #define RELEASE_PATH(x) \
128 FREE_ZONE((x), MAXPATHLEN, M_NAMEI);
129 #endif /* CONFIG_FSE */
131 /* struct for checkdirs iteration */
136 /* callback for checkdirs iteration */
137 static int checkdirs_callback(proc_t p
, void * arg
);
139 static int change_dir(struct nameidata
*ndp
, vfs_context_t ctx
);
140 static int checkdirs(vnode_t olddp
, vfs_context_t ctx
);
141 void enablequotas(struct mount
*mp
, vfs_context_t ctx
);
142 static int getfsstat_callback(mount_t mp
, void * arg
);
143 static int getutimes(user_addr_t usrtvp
, struct timespec
*tsp
);
144 static int setutimes(vfs_context_t ctx
, vnode_t vp
, const struct timespec
*ts
, int nullflag
);
145 static int sync_callback(mount_t
, void *);
146 static int munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
147 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
148 boolean_t partial_copy
);
149 static int statfs64_common(struct mount
*mp
, struct vfsstatfs
*sfsp
, user_addr_t bufp
);
150 int (*union_dircheckp
)(struct vnode
**, struct fileproc
*, vfs_context_t
);
153 int sync_internal(void);
156 int open1(vfs_context_t
, struct nameidata
*, int, struct vnode_attr
*, register_t
*);
159 int unlink1(vfs_context_t
, struct nameidata
*, int);
162 #ifdef __APPLE_API_OBSOLETE
164 int fd
; /* file descriptor of the target file */
165 struct vstat
*vsb
; /* vstat structure for returned info */
168 const char *path
; /* pathname of the target file */
169 struct vstat
*vsb
; /* vstat structure for returned info */
171 struct mkcomplex_args
{
172 const char *path
; /* pathname of the file to be created */
173 mode_t mode
; /* access mode for the newly created file */
174 u_long type
; /* format of the complex file */
177 const char *path
; /* pathname of the target file */
178 struct vstat
*vsb
; /* vstat structure for returned info */
181 int fstatv(proc_t p
, struct fstatv_args
*uap
, register_t
*retval
);
182 int lstatv(proc_t p
, struct lstatv_args
*uap
, register_t
*retval
);
183 int mkcomplex(proc_t p
, struct mkcomplex_args
*uap
, register_t
*retval
);
184 int statv(proc_t p
, struct statv_args
*uap
, register_t
*retval
);
186 #endif /* __APPLE_API_OBSOLETE */
189 * incremented each time a mount or unmount operation occurs
190 * used to invalidate the cached value of the rootvp in the
191 * mount structure utilized by cache_lookup_path
193 int mount_generation
= 0;
195 /* counts number of mount and unmount operations */
196 unsigned int vfs_nummntops
=0;
198 extern struct fileops vnops
;
199 extern errno_t
rmdir_remove_orphaned_appleDouble(vnode_t
, vfs_context_t
, int *);
203 * Virtual File System System Calls
207 * Mount a file system.
211 mount(proc_t p
, struct mount_args
*uap
, __unused register_t
*retval
)
213 struct __mac_mount_args muap
;
215 muap
.type
= uap
->type
;
216 muap
.path
= uap
->path
;
217 muap
.flags
= uap
->flags
;
218 muap
.data
= uap
->data
;
219 muap
.mac_p
= USER_ADDR_NULL
;
220 return (__mac_mount(p
, &muap
, retval
));
224 __mac_mount(struct proc
*p
, register struct __mac_mount_args
*uap
, __unused register_t
*retval
)
227 struct vnode
*devvp
= NULLVP
;
228 struct vnode
*device_vnode
= NULLVP
;
233 struct vfstable
*vfsp
= (struct vfstable
*)0;
235 struct vnode_attr va
;
236 vfs_context_t ctx
= vfs_context_current();
238 struct nameidata nd1
;
239 char fstypename
[MFSNAMELEN
];
241 user_addr_t devpath
= USER_ADDR_NULL
;
242 user_addr_t fsmountargs
= uap
->data
;
247 boolean_t is_rwlock_locked
= FALSE
;
249 AUDIT_ARG(fflags
, uap
->flags
);
251 is_64bit
= proc_is64bit(p
);
254 * Get vnode to be covered
256 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
257 UIO_USERSPACE
, uap
->path
, ctx
);
263 if ((vp
->v_flag
& VROOT
) &&
264 (vp
->v_mount
->mnt_flag
& MNT_ROOTFS
))
265 uap
->flags
|= MNT_UPDATE
;
267 error
= copyinstr(uap
->type
, fstypename
, MFSNAMELEN
, &dummy
);
271 if (uap
->flags
& MNT_UPDATE
) {
272 if ((vp
->v_flag
& VROOT
) == 0) {
278 /* unmount in progress return error */
280 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
286 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
287 is_rwlock_locked
= TRUE
;
289 * We only allow the filesystem to be reloaded if it
290 * is currently mounted read-only.
292 if ((uap
->flags
& MNT_RELOAD
) &&
293 ((mp
->mnt_flag
& MNT_RDONLY
) == 0)) {
298 * Only root, or the user that did the original mount is
299 * permitted to update it.
301 if (mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(vfs_context_ucred(ctx
)) &&
302 (error
= suser(vfs_context_ucred(ctx
), &p
->p_acflag
))) {
306 error
= mac_mount_check_remount(ctx
, mp
);
308 lck_rw_done(&mp
->mnt_rwlock
);
313 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV,
314 * and MNT_NOEXEC if mount point is already MNT_NOEXEC.
316 if (suser(vfs_context_ucred(ctx
), NULL
)) {
317 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
318 if (mp
->mnt_flag
& MNT_NOEXEC
)
319 uap
->flags
|= MNT_NOEXEC
;
324 uap
->flags
& (MNT_RELOAD
| MNT_FORCE
| MNT_UPDATE
);
326 vfsp
= mp
->mnt_vtable
;
330 * If the user is not root, ensure that they own the directory
331 * onto which we are attempting to mount.
334 VATTR_WANTED(&va
, va_uid
);
335 if ((error
= vnode_getattr(vp
, &va
, ctx
)) ||
336 (va
.va_uid
!= kauth_cred_getuid(vfs_context_ucred(ctx
)) &&
337 (error
= suser(vfs_context_ucred(ctx
), &p
->p_acflag
)))) {
341 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV, and
342 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
344 if (suser(vfs_context_ucred(ctx
), NULL
)) {
345 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
346 if (vp
->v_mount
->mnt_flag
& MNT_NOEXEC
)
347 uap
->flags
|= MNT_NOEXEC
;
349 if ( (error
= VNOP_FSYNC(vp
, MNT_WAIT
, ctx
)) )
352 if ( (error
= buf_invalidateblks(vp
, BUF_WRITE_DATA
, 0, 0)) )
355 if (vp
->v_type
!= VDIR
) {
360 /* XXXAUDIT: Should we capture the type on the error path as well? */
361 AUDIT_ARG(text
, fstypename
);
363 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
364 if (!strncmp(vfsp
->vfc_name
, fstypename
, MFSNAMELEN
))
372 error
= mac_mount_check_mount(ctx
, vp
,
373 &nd
.ni_cnd
, vfsp
->vfc_name
);
377 if (ISSET(vp
->v_flag
, VMOUNT
) && (vp
->v_mountedhere
!= NULL
)) {
382 SET(vp
->v_flag
, VMOUNT
);
386 * Allocate and initialize the filesystem.
388 MALLOC_ZONE(mp
, struct mount
*, (u_long
)sizeof(struct mount
),
390 bzero((char *)mp
, (u_long
)sizeof(struct mount
));
393 /* Initialize the default IO constraints */
394 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
395 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
396 mp
->mnt_maxsegreadsize
= mp
->mnt_maxreadcnt
;
397 mp
->mnt_maxsegwritesize
= mp
->mnt_maxwritecnt
;
398 mp
->mnt_devblocksize
= DEV_BSIZE
;
399 mp
->mnt_alignmentmask
= PAGE_MASK
;
401 mp
->mnt_realrootvp
= NULLVP
;
402 mp
->mnt_authcache_ttl
= CACHED_LOOKUP_RIGHT_TTL
;
404 TAILQ_INIT(&mp
->mnt_vnodelist
);
405 TAILQ_INIT(&mp
->mnt_workerqueue
);
406 TAILQ_INIT(&mp
->mnt_newvnodes
);
408 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
409 is_rwlock_locked
= TRUE
;
410 mp
->mnt_op
= vfsp
->vfc_vfsops
;
411 mp
->mnt_vtable
= vfsp
;
413 vfsp
->vfc_refcount
++;
415 //mp->mnt_stat.f_type = vfsp->vfc_typenum;
416 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
417 strncpy(mp
->mnt_vfsstat
.f_fstypename
, vfsp
->vfc_name
, MFSTYPENAMELEN
);
418 strncpy(mp
->mnt_vfsstat
.f_mntonname
, nd
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
419 mp
->mnt_vnodecovered
= vp
;
420 mp
->mnt_vfsstat
.f_owner
= kauth_cred_getuid(vfs_context_ucred(ctx
));
422 /* XXX 3762912 hack to support HFS filesystem 'owner' - filesystem may update later */
423 vfs_setowner(mp
, KAUTH_UID_NONE
, KAUTH_GID_NONE
);
427 * Set the mount level flags.
429 if (uap
->flags
& MNT_RDONLY
)
430 mp
->mnt_flag
|= MNT_RDONLY
;
431 else if (mp
->mnt_flag
& MNT_RDONLY
)
432 mp
->mnt_kern_flag
|= MNTK_WANTRDWR
;
433 mp
->mnt_flag
&= ~(MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
434 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
435 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
|
436 MNT_DEFWRITE
| MNT_NOATIME
| MNT_QUARANTINE
);
437 mp
->mnt_flag
|= uap
->flags
& (MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
438 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
439 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
|
440 MNT_DEFWRITE
| MNT_NOATIME
| MNT_QUARANTINE
);
443 if (uap
->flags
& MNT_MULTILABEL
) {
444 if (vfsp
->vfc_vfsflags
& VFC_VFSNOMACLABEL
) {
448 mp
->mnt_flag
|= MNT_MULTILABEL
;
452 if (vfsp
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
454 if ( (error
= copyin(fsmountargs
, (caddr_t
)&devpath
, sizeof(devpath
))) )
456 fsmountargs
+= sizeof(devpath
);
459 if ( (error
= copyin(fsmountargs
, (caddr_t
)&tmp
, sizeof(tmp
))) )
461 /* munge into LP64 addr */
462 devpath
= CAST_USER_ADDR_T(tmp
);
463 fsmountargs
+= sizeof(tmp
);
466 /* if it is not update and device name needs to be parsed */
468 NDINIT(&nd1
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, devpath
, ctx
);
469 if ( (error
= namei(&nd1
)) )
472 strncpy(mp
->mnt_vfsstat
.f_mntfromname
, nd1
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
477 if (devvp
->v_type
!= VBLK
) {
481 if (major(devvp
->v_rdev
) >= nblkdev
) {
486 * If mount by non-root, then verify that user has necessary
487 * permissions on the device.
489 if (suser(vfs_context_ucred(ctx
), NULL
) != 0) {
490 accessmode
= KAUTH_VNODE_READ_DATA
;
491 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
492 accessmode
|= KAUTH_VNODE_WRITE_DATA
;
493 if ((error
= vnode_authorize(devvp
, NULL
, accessmode
, ctx
)) != 0)
497 if (devpath
&& ((uap
->flags
& MNT_UPDATE
) == 0)) {
498 if ( (error
= vnode_ref(devvp
)) )
501 * Disallow multiple mounts of the same device.
502 * Disallow mounting of a device that is currently in use
503 * (except for root, which might share swap device for miniroot).
504 * Flush out any old buffers remaining from a previous use.
506 if ( (error
= vfs_mountedon(devvp
)) )
509 if (vcount(devvp
) > 1 && !(vfs_flags(mp
) & MNT_ROOTFS
)) {
513 if ( (error
= VNOP_FSYNC(devvp
, MNT_WAIT
, ctx
)) ) {
517 if ( (error
= buf_invalidateblks(devvp
, BUF_WRITE_DATA
, 0, 0)) )
520 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
522 error
= mac_vnode_check_open(ctx
,
524 ronly
? FREAD
: FREAD
|FWRITE
);
528 if ( (error
= VNOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, ctx
)) )
531 mp
->mnt_devvp
= devvp
;
532 device_vnode
= devvp
;
534 if ((mp
->mnt_flag
& MNT_RDONLY
) && (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)) {
536 * If upgrade to read-write by non-root, then verify
537 * that user has necessary permissions on the device.
539 device_vnode
= mp
->mnt_devvp
;
540 if (device_vnode
&& suser(vfs_context_ucred(ctx
), NULL
)) {
541 if ((error
= vnode_authorize(device_vnode
, NULL
,
542 KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, ctx
)) != 0)
546 device_vnode
= NULLVP
;
550 if ((uap
->flags
& MNT_UPDATE
) == 0) {
551 mac_mount_label_init(mp
);
552 mac_mount_label_associate(ctx
, mp
);
554 if (uap
->mac_p
!= USER_ADDR_NULL
) {
556 char *labelstr
= NULL
;
559 if ((uap
->flags
& MNT_UPDATE
) != 0) {
560 error
= mac_mount_check_label_update(
566 error
= copyin(uap
->mac_p
, &mac
, sizeof(mac
));
569 error
= copyin(uap
->mac_p
, &mac32
, sizeof(mac32
));
570 mac
.m_buflen
= mac32
.m_buflen
;
571 mac
.m_string
= CAST_USER_ADDR_T(mac32
.m_string
);
575 if ((mac
.m_buflen
> MAC_MAX_LABEL_BUF_LEN
) ||
576 (mac
.m_buflen
< 2)) {
580 MALLOC(labelstr
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
581 error
= copyinstr(mac
.m_string
, labelstr
, mac
.m_buflen
, &ulen
);
583 FREE(labelstr
, M_MACTEMP
);
586 AUDIT_ARG(mac_string
, labelstr
);
587 error
= mac_mount_label_internalize(mp
->mnt_mntlabel
, labelstr
);
588 FREE(labelstr
, M_MACTEMP
);
594 * Mount the filesystem.
596 error
= VFS_MOUNT(mp
, device_vnode
, fsmountargs
, ctx
);
598 if (uap
->flags
& MNT_UPDATE
) {
599 if (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)
600 mp
->mnt_flag
&= ~MNT_RDONLY
;
602 (MNT_UPDATE
| MNT_RELOAD
| MNT_FORCE
);
603 mp
->mnt_kern_flag
&=~ MNTK_WANTRDWR
;
606 vfs_event_signal(NULL
, VQ_UPDATE
, (intptr_t)NULL
);
607 lck_rw_done(&mp
->mnt_rwlock
);
608 is_rwlock_locked
= FALSE
;
610 enablequotas(mp
, ctx
);
614 * Put the new filesystem on the mount list after root.
617 struct vfs_attr vfsattr
;
619 if (vfs_flags(mp
) & MNT_MULTILABEL
) {
620 error
= VFS_ROOT(mp
, &rvp
, ctx
);
622 printf("%s() VFS_ROOT returned %d\n", __func__
, error
);
626 /* VFS_ROOT provides reference so needref = 0 */
627 error
= vnode_label(mp
, NULL
, rvp
, NULL
, 0, ctx
);
634 CLR(vp
->v_flag
, VMOUNT
);
635 vp
->v_mountedhere
= mp
;
639 * taking the name_cache_lock exclusively will
640 * insure that everyone is out of the fast path who
641 * might be trying to use a now stale copy of
642 * vp->v_mountedhere->mnt_realrootvp
643 * bumping mount_generation causes the cached values
652 error
= checkdirs(vp
, ctx
);
654 /* Unmount the filesystem as cdir/rdirs cannot be updated */
658 * there is no cleanup code here so I have made it void
659 * we need to revisit this
661 (void)VFS_START(mp
, 0, ctx
);
664 lck_rw_done(&mp
->mnt_rwlock
);
665 is_rwlock_locked
= FALSE
;
667 /* Check if this mounted file system supports EAs or named streams. */
668 /* Skip WebDAV file systems for now since they hang in VFS_GETATTR here. */
669 VFSATTR_INIT(&vfsattr
);
670 VFSATTR_WANTED(&vfsattr
, f_capabilities
);
671 if (strncmp(mp
->mnt_vfsstat
.f_fstypename
, "webdav", sizeof("webdav")) != 0 &&
672 vfs_getattr(mp
, &vfsattr
, ctx
) == 0 &&
673 VFSATTR_IS_SUPPORTED(&vfsattr
, f_capabilities
)) {
674 if ((vfsattr
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] & VOL_CAP_INT_EXTENDED_ATTR
) &&
675 (vfsattr
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] & VOL_CAP_INT_EXTENDED_ATTR
)) {
676 mp
->mnt_kern_flag
|= MNTK_EXTENDED_ATTRS
;
679 if ((vfsattr
.f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] & VOL_CAP_INT_NAMEDSTREAMS
) &&
680 (vfsattr
.f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] & VOL_CAP_INT_NAMEDSTREAMS
)) {
681 mp
->mnt_kern_flag
|= MNTK_NAMED_STREAMS
;
684 /* Check if this file system supports path from id lookups. */
685 if ((vfsattr
.f_capabilities
.capabilities
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_PATH_FROM_ID
) &&
686 (vfsattr
.f_capabilities
.valid
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_PATH_FROM_ID
)) {
687 mp
->mnt_kern_flag
|= MNTK_PATH_FROM_ID
;
688 } else if (mp
->mnt_flag
& MNT_DOVOLFS
) {
689 /* Legacy MNT_DOVOLFS flag also implies path from id lookups. */
690 mp
->mnt_kern_flag
|= MNTK_PATH_FROM_ID
;
693 if (mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSNATIVEXATTR
) {
694 mp
->mnt_kern_flag
|= MNTK_EXTENDED_ATTRS
;
696 if (mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSPREFLIGHT
) {
697 mp
->mnt_kern_flag
|= MNTK_UNMOUNT_PREFLIGHT
;
699 /* increment the operations count */
700 OSAddAtomic(1, (SInt32
*)&vfs_nummntops
);
701 enablequotas(mp
, ctx
);
704 device_vnode
->v_specflags
|= SI_MOUNTEDON
;
707 * cache the IO attributes for the underlying physical media...
708 * an error return indicates the underlying driver doesn't
709 * support all the queries necessary... however, reasonable
710 * defaults will have been set, so no reason to bail or care
712 vfs_init_io_attributes(device_vnode
, mp
);
715 /* Now that mount is setup, notify the listeners */
716 vfs_event_signal(NULL
, VQ_MOUNT
, (intptr_t)NULL
);
719 CLR(vp
->v_flag
, VMOUNT
);
722 mp
->mnt_vtable
->vfc_refcount
--;
726 VNOP_CLOSE(device_vnode
, ronly
? FREAD
: FREAD
|FWRITE
, ctx
);
727 vnode_rele(device_vnode
);
729 lck_rw_done(&mp
->mnt_rwlock
);
730 is_rwlock_locked
= FALSE
;
731 mount_lock_destroy(mp
);
733 mac_mount_label_destroy(mp
);
735 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
740 * drop I/O count on covered 'vp' and
741 * on the device vp if there was one
743 if (devpath
&& devvp
)
749 (void)VFS_UNMOUNT(mp
, MNT_FORCE
, ctx
);
750 if (device_vnode
!= NULLVP
) {
751 VNOP_CLOSE(device_vnode
, mp
->mnt_flag
& MNT_RDONLY
? FREAD
: FREAD
|FWRITE
,
756 vp
->v_mountedhere
= (mount_t
) 0;
760 if (devpath
&& ((uap
->flags
& MNT_UPDATE
) == 0))
763 if (devpath
&& devvp
)
766 /* Release mnt_rwlock only when it was taken */
767 if (is_rwlock_locked
== TRUE
) {
768 lck_rw_done(&mp
->mnt_rwlock
);
772 mac_mount_label_destroy(mp
);
775 vfsp
->vfc_refcount
--;
777 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
786 enablequotas(struct mount
*mp
, vfs_context_t ctx
)
788 struct nameidata qnd
;
790 char qfpath
[MAXPATHLEN
];
791 const char *qfname
= QUOTAFILENAME
;
792 const char *qfopsname
= QUOTAOPSNAME
;
793 const char *qfextension
[] = INITQFNAMES
;
795 /* XXX Shoulkd be an MNTK_ flag, instead of strncmp()'s */
796 if ((strncmp(mp
->mnt_vfsstat
.f_fstypename
, "hfs", sizeof("hfs")) != 0 )
797 && (strncmp( mp
->mnt_vfsstat
.f_fstypename
, "ufs", sizeof("ufs")) != 0))
801 * Enable filesystem disk quotas if necessary.
802 * We ignore errors as this should not interfere with final mount
804 for (type
=0; type
< MAXQUOTAS
; type
++) {
805 snprintf(qfpath
, sizeof(qfpath
), "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfopsname
, qfextension
[type
]);
806 NDINIT(&qnd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE32
, CAST_USER_ADDR_T(qfpath
), ctx
);
807 if (namei(&qnd
) != 0)
808 continue; /* option file to trigger quotas is not present */
809 vnode_put(qnd
.ni_vp
);
811 snprintf(qfpath
, sizeof(qfpath
), "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfname
, qfextension
[type
]);
813 (void) VFS_QUOTACTL(mp
, QCMD(Q_QUOTAON
, type
), 0, qfpath
, ctx
);
820 checkdirs_callback(proc_t p
, void * arg
)
822 struct cdirargs
* cdrp
= (struct cdirargs
* )arg
;
823 vnode_t olddp
= cdrp
->olddp
;
824 vnode_t newdp
= cdrp
->newdp
;
825 struct filedesc
*fdp
;
829 int cdir_changed
= 0;
830 int rdir_changed
= 0;
833 * XXX Also needs to iterate each thread in the process to see if it
834 * XXX is using a per-thread current working directory, and, if so,
835 * XXX update that as well.
840 if (fdp
== (struct filedesc
*)0) {
842 return(PROC_RETURNED
);
844 fdp_cvp
= fdp
->fd_cdir
;
845 fdp_rvp
= fdp
->fd_rdir
;
848 if (fdp_cvp
== olddp
) {
855 if (fdp_rvp
== olddp
) {
862 if (cdir_changed
|| rdir_changed
) {
864 fdp
->fd_cdir
= fdp_cvp
;
865 fdp
->fd_rdir
= fdp_rvp
;
868 return(PROC_RETURNED
);
874 * Scan all active processes to see if any of them have a current
875 * or root directory onto which the new filesystem has just been
876 * mounted. If so, replace them with the new mount point.
879 checkdirs(vnode_t olddp
, vfs_context_t ctx
)
885 struct uthread
* uth
= get_bsdthread_info(current_thread());
887 if (olddp
->v_usecount
== 1)
889 if (uth
!= (struct uthread
*)0)
890 uth
->uu_notrigger
= 1;
891 err
= VFS_ROOT(olddp
->v_mountedhere
, &newdp
, ctx
);
892 if (uth
!= (struct uthread
*)0)
893 uth
->uu_notrigger
= 0;
897 panic("mount: lost mount: error %d", err
);
904 /* do not block for exec/fork trans as the vp in cwd & rootdir are not changing */
905 proc_iterate(PROC_ALLPROCLIST
| PROC_NOWAITTRANS
, checkdirs_callback
, (void *)&cdr
, NULL
, NULL
);
907 if (rootvnode
== olddp
) {
919 * Unmount a file system.
921 * Note: unmount takes a path to the vnode mounted on as argument,
922 * not special file (as before).
926 unmount(__unused proc_t p
, struct unmount_args
*uap
, __unused register_t
*retval
)
932 vfs_context_t ctx
= vfs_context_current();
934 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
935 UIO_USERSPACE
, uap
->path
, ctx
);
944 error
= mac_mount_check_umount(ctx
, mp
);
951 * Must be the root of the filesystem
953 if ((vp
->v_flag
& VROOT
) == 0) {
959 /* safedounmount consumes the mount ref */
960 return (safedounmount(mp
, uap
->flags
, ctx
));
964 vfs_unmountbyfsid(fsid_t
* fsid
, int flags
, vfs_context_t ctx
)
968 mp
= mount_list_lookupby_fsid(fsid
, 0, 1);
969 if (mp
== (mount_t
)0) {
974 /* safedounmount consumes the mount ref */
975 return(safedounmount(mp
, flags
, ctx
));
980 * The mount struct comes with a mount ref which will be consumed.
981 * Do the actual file system unmount, prevent some common foot shooting.
984 safedounmount(struct mount
*mp
, int flags
, vfs_context_t ctx
)
987 proc_t p
= vfs_context_proc(ctx
);
990 * Only root, or the user that did the original mount is
991 * permitted to unmount this filesystem.
993 if ((mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(kauth_cred_get())) &&
994 (error
= suser(kauth_cred_get(), &p
->p_acflag
)))
998 * Don't allow unmounting the root file system.
1000 if (mp
->mnt_flag
& MNT_ROOTFS
) {
1001 error
= EBUSY
; /* the root is always busy */
1005 return (dounmount(mp
, flags
, 1, ctx
));
1013 * Do the actual file system unmount.
1016 dounmount(struct mount
*mp
, int flags
, int withref
, vfs_context_t ctx
)
1018 vnode_t coveredvp
= (vnode_t
)0;
1021 int forcedunmount
= 0;
1024 if (flags
& MNT_FORCE
)
1027 /* XXX post jaguar fix LK_DRAIN - then clean this up */
1028 if ((flags
& MNT_FORCE
)) {
1029 mp
->mnt_kern_flag
|= MNTK_FRCUNMOUNT
;
1030 mp
->mnt_lflag
|= MNT_LFORCE
;
1032 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
1033 mp
->mnt_lflag
|= MNT_LWAIT
;
1036 msleep((caddr_t
)mp
, &mp
->mnt_mlock
, (PVFS
| PDROP
), "dounmount", NULL
);
1038 * The prior unmount attempt has probably succeeded.
1039 * Do not dereference mp here - returning EBUSY is safest.
1043 mp
->mnt_kern_flag
|= MNTK_UNMOUNT
;
1044 mp
->mnt_lflag
|= MNT_LUNMOUNT
;
1045 mp
->mnt_flag
&=~ MNT_ASYNC
;
1047 * anyone currently in the fast path that
1048 * trips over the cached rootvp will be
1049 * dumped out and forced into the slow path
1050 * to regenerate a new cached value
1052 mp
->mnt_realrootvp
= NULLVP
;
1056 * taking the name_cache_lock exclusively will
1057 * insure that everyone is out of the fast path who
1058 * might be trying to use a now stale copy of
1059 * vp->v_mountedhere->mnt_realrootvp
1060 * bumping mount_generation causes the cached values
1065 name_cache_unlock();
1068 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
1072 fsevent_unmount(mp
); /* has to come first! */
1075 if (forcedunmount
== 0) {
1076 ubc_umount(mp
); /* release cached vnodes */
1077 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
1078 error
= VFS_SYNC(mp
, MNT_WAIT
, ctx
);
1081 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
1082 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
1083 mp
->mnt_lflag
&= ~MNT_LFORCE
;
1090 lflags
|= FORCECLOSE
;
1091 error
= vflush(mp
, NULLVP
, SKIPSWAP
| SKIPSYSTEM
| SKIPROOT
| lflags
);
1092 if ((forcedunmount
== 0) && error
) {
1094 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
1095 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
1096 mp
->mnt_lflag
&= ~MNT_LFORCE
;
1100 /* make sure there are no one in the mount iterations or lookup */
1101 mount_iterdrain(mp
);
1103 error
= VFS_UNMOUNT(mp
, flags
, ctx
);
1105 mount_iterreset(mp
);
1107 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
1108 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
1109 mp
->mnt_lflag
&= ~MNT_LFORCE
;
1113 /* increment the operations count */
1115 OSAddAtomic(1, (SInt32
*)&vfs_nummntops
);
1117 if ( mp
->mnt_devvp
&& mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
1118 mp
->mnt_devvp
->v_specflags
&= ~SI_MOUNTEDON
;
1119 VNOP_CLOSE(mp
->mnt_devvp
, mp
->mnt_flag
& MNT_RDONLY
? FREAD
: FREAD
|FWRITE
,
1121 vnode_rele(mp
->mnt_devvp
);
1123 lck_rw_done(&mp
->mnt_rwlock
);
1124 mount_list_remove(mp
);
1125 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
1127 /* mark the mount point hook in the vp but not drop the ref yet */
1128 if ((coveredvp
= mp
->mnt_vnodecovered
) != NULLVP
) {
1129 vnode_getwithref(coveredvp
);
1130 vnode_lock_spin(coveredvp
);
1131 coveredvp
->v_mountedhere
= (struct mount
*)0;
1132 vnode_unlock(coveredvp
);
1133 vnode_put(coveredvp
);
1137 mp
->mnt_vtable
->vfc_refcount
--;
1138 mount_list_unlock();
1140 cache_purgevfs(mp
); /* remove cache entries for this file sys */
1141 vfs_event_signal(NULL
, VQ_UNMOUNT
, (intptr_t)NULL
);
1143 mp
->mnt_lflag
|= MNT_LDEAD
;
1145 if (mp
->mnt_lflag
& MNT_LWAIT
) {
1147 * do the wakeup here
1148 * in case we block in mount_refdrain
1149 * which will drop the mount lock
1150 * and allow anyone blocked in vfs_busy
1151 * to wakeup and see the LDEAD state
1153 mp
->mnt_lflag
&= ~MNT_LWAIT
;
1154 wakeup((caddr_t
)mp
);
1158 if (mp
->mnt_lflag
& MNT_LWAIT
) {
1159 mp
->mnt_lflag
&= ~MNT_LWAIT
;
1163 lck_rw_done(&mp
->mnt_rwlock
);
1166 wakeup((caddr_t
)mp
);
1168 if ((coveredvp
!= NULLVP
)) {
1169 vnode_getwithref(coveredvp
);
1170 vnode_rele(coveredvp
);
1171 vnode_lock_spin(coveredvp
);
1172 if(mp
->mnt_crossref
== 0) {
1173 vnode_unlock(coveredvp
);
1174 mount_lock_destroy(mp
);
1176 mac_mount_label_destroy(mp
);
1178 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
1180 coveredvp
->v_lflag
|= VL_MOUNTDEAD
;
1181 vnode_unlock(coveredvp
);
1183 vnode_put(coveredvp
);
1184 } else if (mp
->mnt_flag
& MNT_ROOTFS
) {
1185 mount_lock_destroy(mp
);
1187 mac_mount_label_destroy(mp
);
1189 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
1191 panic("dounmount: no coveredvp");
1197 mount_dropcrossref(mount_t mp
, vnode_t dp
, int need_put
)
1201 if (mp
->mnt_crossref
< 0)
1202 panic("mount cross refs -ve");
1203 if (((dp
->v_lflag
& VL_MOUNTDEAD
) == VL_MOUNTDEAD
) && (mp
->mnt_crossref
== 0)) {
1204 dp
->v_lflag
&= ~VL_MOUNTDEAD
;
1206 vnode_put_locked(dp
);
1208 mount_lock_destroy(mp
);
1210 mac_mount_label_destroy(mp
);
1212 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
1216 vnode_put_locked(dp
);
1222 * Sync each mounted filesystem.
1226 struct ctldebug debug0
= { "syncprt", &syncprt
};
1229 int print_vmpage_stat
=0;
1232 sync_callback(mount_t mp
, __unused
void * arg
)
1236 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
1237 asyncflag
= mp
->mnt_flag
& MNT_ASYNC
;
1238 mp
->mnt_flag
&= ~MNT_ASYNC
;
1239 VFS_SYNC(mp
, MNT_NOWAIT
, vfs_context_current());
1241 mp
->mnt_flag
|= MNT_ASYNC
;
1243 return(VFS_RETURNED
);
1247 extern unsigned int vp_pagein
, vp_pgodirty
, vp_pgoclean
;
1248 extern unsigned int dp_pgins
, dp_pgouts
;
1252 sync(__unused proc_t p
, __unused
struct sync_args
*uap
, __unused register_t
*retval
)
1255 vfs_iterate(LK_NOWAIT
, sync_callback
, (void *)0);
1257 if(print_vmpage_stat
) {
1258 vm_countdirtypages();
1259 printf("VP: %d: %d: %d: %d: %d\n", vp_pgodirty
, vp_pgoclean
, vp_pagein
,
1260 dp_pgins
, dp_pgouts
);
1266 #endif /* DIAGNOSTIC */
1271 * Change filesystem quotas.
1274 static int quotactl_funneled(proc_t p
, struct quotactl_args
*uap
, register_t
*retval
);
1277 quotactl(proc_t p
, struct quotactl_args
*uap
, register_t
*retval
)
1279 boolean_t funnel_state
;
1282 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
1283 error
= quotactl_funneled(p
, uap
, retval
);
1284 thread_funnel_set(kernel_flock
, funnel_state
);
1289 quotactl_funneled(proc_t p
, struct quotactl_args
*uap
, __unused register_t
*retval
)
1292 int error
, quota_cmd
, quota_status
;
1295 struct nameidata nd
;
1296 vfs_context_t ctx
= vfs_context_current();
1297 struct dqblk my_dqblk
;
1299 AUDIT_ARG(uid
, uap
->uid
, 0, 0, 0);
1300 AUDIT_ARG(cmd
, uap
->cmd
);
1301 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1302 UIO_USERSPACE
, uap
->path
, ctx
);
1306 mp
= nd
.ni_vp
->v_mount
;
1307 vnode_put(nd
.ni_vp
);
1310 /* copyin any data we will need for downstream code */
1311 quota_cmd
= uap
->cmd
>> SUBCMDSHIFT
;
1313 switch (quota_cmd
) {
1315 /* uap->arg specifies a file from which to take the quotas */
1316 fnamelen
= MAXPATHLEN
;
1317 datap
= kalloc(MAXPATHLEN
);
1318 error
= copyinstr(uap
->arg
, datap
, MAXPATHLEN
, &fnamelen
);
1321 /* uap->arg is a pointer to a dqblk structure. */
1322 datap
= (caddr_t
) &my_dqblk
;
1326 /* uap->arg is a pointer to a dqblk structure. */
1327 datap
= (caddr_t
) &my_dqblk
;
1328 if (proc_is64bit(p
)) {
1329 struct user_dqblk my_dqblk64
;
1330 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk64
, sizeof (my_dqblk64
));
1332 munge_dqblk(&my_dqblk
, &my_dqblk64
, FALSE
);
1336 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk
, sizeof (my_dqblk
));
1340 /* uap->arg is a pointer to an integer */
1341 datap
= (caddr_t
) "a_status
;
1349 error
= VFS_QUOTACTL(mp
, uap
->cmd
, uap
->uid
, datap
, ctx
);
1352 switch (quota_cmd
) {
1355 kfree(datap
, MAXPATHLEN
);
1358 /* uap->arg is a pointer to a dqblk structure we need to copy out to */
1360 if (proc_is64bit(p
)) {
1361 struct user_dqblk my_dqblk64
;
1362 munge_dqblk(&my_dqblk
, &my_dqblk64
, TRUE
);
1363 error
= copyout((caddr_t
)&my_dqblk64
, uap
->arg
, sizeof (my_dqblk64
));
1366 error
= copyout(datap
, uap
->arg
, sizeof (struct dqblk
));
1371 /* uap->arg is a pointer to an integer */
1373 error
= copyout(datap
, uap
->arg
, sizeof(quota_status
));
1384 quotactl(__unused proc_t p
, __unused
struct quotactl_args
*uap
, __unused register_t
*retval
)
1386 return (EOPNOTSUPP
);
1391 * Get filesystem statistics.
1393 * Returns: 0 Success
1395 * vfs_update_vfsstat:???
1396 * munge_statfs:EFAULT
1400 statfs(__unused proc_t p
, struct statfs_args
*uap
, __unused register_t
*retval
)
1403 struct vfsstatfs
*sp
;
1405 struct nameidata nd
;
1406 vfs_context_t ctx
= vfs_context_current();
1409 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
1410 UIO_USERSPACE
, uap
->path
, ctx
);
1416 sp
= &mp
->mnt_vfsstat
;
1419 error
= vfs_update_vfsstat(mp
, ctx
, VFS_USER_EVENT
);
1424 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1429 * Get filesystem statistics.
1433 fstatfs(__unused proc_t p
, struct fstatfs_args
*uap
, __unused register_t
*retval
)
1437 struct vfsstatfs
*sp
;
1440 AUDIT_ARG(fd
, uap
->fd
);
1442 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1445 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
1452 sp
= &mp
->mnt_vfsstat
;
1453 if ((error
= vfs_update_vfsstat(mp
,vfs_context_current(),VFS_USER_EVENT
)) != 0) {
1459 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1465 * Common routine to handle copying of statfs64 data to user space
1468 statfs64_common(struct mount
*mp
, struct vfsstatfs
*sfsp
, user_addr_t bufp
)
1471 struct statfs64 sfs
;
1473 bzero(&sfs
, sizeof(sfs
));
1475 sfs
.f_bsize
= sfsp
->f_bsize
;
1476 sfs
.f_iosize
= (int32_t)sfsp
->f_iosize
;
1477 sfs
.f_blocks
= sfsp
->f_blocks
;
1478 sfs
.f_bfree
= sfsp
->f_bfree
;
1479 sfs
.f_bavail
= sfsp
->f_bavail
;
1480 sfs
.f_files
= sfsp
->f_files
;
1481 sfs
.f_ffree
= sfsp
->f_ffree
;
1482 sfs
.f_fsid
= sfsp
->f_fsid
;
1483 sfs
.f_owner
= sfsp
->f_owner
;
1484 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
1485 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
1486 sfs
.f_fssubtype
= sfsp
->f_fssubtype
;
1487 strlcpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSTYPENAMELEN
);
1488 strlcpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MAXPATHLEN
);
1489 strlcpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MAXPATHLEN
);
1491 error
= copyout((caddr_t
)&sfs
, bufp
, sizeof(sfs
));
1497 * Get file system statistics in 64-bit mode
1500 statfs64(__unused
struct proc
*p
, struct statfs64_args
*uap
, __unused register_t
*retval
)
1503 struct vfsstatfs
*sp
;
1505 struct nameidata nd
;
1506 vfs_context_t ctxp
= vfs_context_current();
1509 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
1510 UIO_USERSPACE
, uap
->path
, ctxp
);
1516 sp
= &mp
->mnt_vfsstat
;
1519 error
= vfs_update_vfsstat(mp
, ctxp
, VFS_USER_EVENT
);
1524 error
= statfs64_common(mp
, sp
, uap
->buf
);
1530 * Get file system statistics in 64-bit mode
1533 fstatfs64(__unused
struct proc
*p
, struct fstatfs64_args
*uap
, __unused register_t
*retval
)
1537 struct vfsstatfs
*sp
;
1540 AUDIT_ARG(fd
, uap
->fd
);
1542 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1545 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
1552 sp
= &mp
->mnt_vfsstat
;
1553 if ((error
= vfs_update_vfsstat(mp
, vfs_context_current(), VFS_USER_EVENT
)) != 0) {
1559 error
= statfs64_common(mp
, sp
, uap
->buf
);
1564 struct getfsstat_struct
{
1575 getfsstat_callback(mount_t mp
, void * arg
)
1578 struct getfsstat_struct
*fstp
= (struct getfsstat_struct
*)arg
;
1579 struct vfsstatfs
*sp
;
1581 vfs_context_t ctx
= vfs_context_current();
1583 if (fstp
->sfsp
&& fstp
->count
< fstp
->maxcount
) {
1584 sp
= &mp
->mnt_vfsstat
;
1586 * If MNT_NOWAIT is specified, do not refresh the
1587 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
1589 if (((fstp
->flags
& MNT_NOWAIT
) == 0 || (fstp
->flags
& MNT_WAIT
)) &&
1590 (error
= vfs_update_vfsstat(mp
, ctx
,
1592 KAUTH_DEBUG("vfs_update_vfsstat returned %d", error
);
1593 return(VFS_RETURNED
);
1597 * Need to handle LP64 version of struct statfs
1599 error
= munge_statfs(mp
, sp
, fstp
->sfsp
, &my_size
, IS_64BIT_PROCESS(vfs_context_proc(ctx
)), FALSE
);
1601 fstp
->error
= error
;
1602 return(VFS_RETURNED_DONE
);
1604 fstp
->sfsp
+= my_size
;
1607 error
= mac_mount_label_get(mp
, *fstp
->mp
);
1609 fstp
->error
= error
;
1610 return(VFS_RETURNED_DONE
);
1616 return(VFS_RETURNED
);
1620 * Get statistics on all filesystems.
1623 getfsstat(__unused proc_t p
, struct getfsstat_args
*uap
, int *retval
)
1625 struct __mac_getfsstat_args muap
;
1627 muap
.buf
= uap
->buf
;
1628 muap
.bufsize
= uap
->bufsize
;
1629 muap
.mac
= USER_ADDR_NULL
;
1631 muap
.flags
= uap
->flags
;
1633 return (__mac_getfsstat(p
, &muap
, retval
));
1637 __mac_getfsstat(__unused proc_t p
, struct __mac_getfsstat_args
*uap
, int *retval
)
1641 int count
, maxcount
;
1642 struct getfsstat_struct fst
;
1644 if (IS_64BIT_PROCESS(p
)) {
1645 maxcount
= uap
->bufsize
/ sizeof(struct user_statfs
);
1648 maxcount
= uap
->bufsize
/ sizeof(struct statfs
);
1656 if (uap
->mac
!= USER_ADDR_NULL
) {
1661 count
= (int)(uap
->macsize
/ (IS_64BIT_PROCESS(p
) ? 8 : 4));
1662 if (count
!= maxcount
)
1665 /* Copy in the array */
1666 MALLOC(mp0
, u_int32_t
*, uap
->macsize
, M_MACTEMP
, M_WAITOK
);
1667 error
= copyin(uap
->mac
, mp0
, uap
->macsize
);
1671 /* Normalize to an array of user_addr_t */
1672 MALLOC(mp
, user_addr_t
*, count
* sizeof(user_addr_t
), M_MACTEMP
, M_WAITOK
);
1673 for (i
= 0; i
< count
; i
++) {
1674 if (IS_64BIT_PROCESS(p
))
1675 mp
[i
] = ((user_addr_t
*)mp0
)[i
];
1677 mp
[i
] = (user_addr_t
)mp0
[i
];
1679 FREE(mp0
, M_MACTEMP
);
1686 fst
.flags
= uap
->flags
;
1689 fst
.maxcount
= maxcount
;
1692 vfs_iterate(0, getfsstat_callback
, &fst
);
1695 FREE(mp
, M_MACTEMP
);
1698 KAUTH_DEBUG("ERROR - %s gets %d", p
->p_comm
, fst
.error
);
1702 if (fst
.sfsp
&& fst
.count
> fst
.maxcount
)
1703 *retval
= fst
.maxcount
;
1705 *retval
= fst
.count
;
1710 getfsstat64_callback(mount_t mp
, void * arg
)
1712 struct getfsstat_struct
*fstp
= (struct getfsstat_struct
*)arg
;
1713 struct vfsstatfs
*sp
;
1716 if (fstp
->sfsp
&& fstp
->count
< fstp
->maxcount
) {
1717 sp
= &mp
->mnt_vfsstat
;
1719 * If MNT_NOWAIT is specified, do not refresh the
1720 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
1722 if (((fstp
->flags
& MNT_NOWAIT
) == 0 || (fstp
->flags
& MNT_WAIT
)) &&
1723 (error
= vfs_update_vfsstat(mp
, vfs_context_current(), VFS_USER_EVENT
))) {
1724 KAUTH_DEBUG("vfs_update_vfsstat returned %d", error
);
1725 return(VFS_RETURNED
);
1728 error
= statfs64_common(mp
, sp
, fstp
->sfsp
);
1730 fstp
->error
= error
;
1731 return(VFS_RETURNED_DONE
);
1733 fstp
->sfsp
+= sizeof(struct statfs64
);
1736 return(VFS_RETURNED
);
1740 * Get statistics on all file systems in 64 bit mode.
1743 getfsstat64(__unused proc_t p
, struct getfsstat64_args
*uap
, int *retval
)
1746 int count
, maxcount
;
1747 struct getfsstat_struct fst
;
1749 maxcount
= uap
->bufsize
/ sizeof(struct statfs64
);
1755 fst
.flags
= uap
->flags
;
1758 fst
.maxcount
= maxcount
;
1760 vfs_iterate(0, getfsstat64_callback
, &fst
);
1763 KAUTH_DEBUG("ERROR - %s gets %d", p
->p_comm
, fst
.error
);
1767 if (fst
.sfsp
&& fst
.count
> fst
.maxcount
)
1768 *retval
= fst
.maxcount
;
1770 *retval
= fst
.count
;
1775 #if COMPAT_GETFSSTAT
1776 ogetfsstat(proc_t p
, struct getfsstat_args
*uap
, register_t
*retval
)
1783 * Change current working directory to a given file descriptor.
1787 common_fchdir(proc_t p
, struct fchdir_args
*uap
, int per_thread
)
1789 struct filedesc
*fdp
= p
->p_fd
;
1795 vfs_context_t ctx
= vfs_context_current();
1797 if (per_thread
&& uap
->fd
== -1) {
1799 * Switching back from per-thread to per process CWD; verify we
1800 * in fact have one before proceeding. The only success case
1801 * for this code path is to return 0 preemptively after zapping
1802 * the thread structure contents.
1804 thread_t th
= vfs_context_thread(ctx
);
1806 uthread_t uth
= get_bsdthread_info(th
);
1808 uth
->uu_cdir
= NULLVP
;
1809 if (tvp
!= NULLVP
) {
1817 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1819 if ( (error
= vnode_getwithref(vp
)) ) {
1824 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
1826 if (vp
->v_type
!= VDIR
) {
1832 error
= mac_vnode_check_chdir(ctx
, vp
);
1836 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, ctx
);
1840 while (!error
&& (mp
= vp
->v_mountedhere
) != NULL
) {
1841 if (vfs_busy(mp
, LK_NOWAIT
)) {
1845 error
= VFS_ROOT(mp
, &tdp
, ctx
);
1854 if ( (error
= vnode_ref(vp
)) )
1859 thread_t th
= vfs_context_thread(ctx
);
1861 uthread_t uth
= get_bsdthread_info(th
);
1864 OSBitOrAtomic(P_THCWD
, (UInt32
*)&p
->p_flag
);
1889 fchdir(proc_t p
, struct fchdir_args
*uap
, __unused register_t
*retval
)
1891 return common_fchdir(p
, uap
, 0);
1895 __pthread_fchdir(proc_t p
, struct __pthread_fchdir_args
*uap
, __unused register_t
*retval
)
1897 return common_fchdir(p
, (void *)uap
, 1);
1901 * Change current working directory (``.'').
1903 * Returns: 0 Success
1904 * change_dir:ENOTDIR
1906 * vnode_ref:ENOENT No such file or directory
1910 common_chdir(proc_t p
, struct chdir_args
*uap
, int per_thread
)
1912 struct filedesc
*fdp
= p
->p_fd
;
1914 struct nameidata nd
;
1916 vfs_context_t ctx
= vfs_context_current();
1918 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1919 UIO_USERSPACE
, uap
->path
, ctx
);
1920 error
= change_dir(&nd
, ctx
);
1923 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
1924 vnode_put(nd
.ni_vp
);
1928 * drop the iocount we picked up in change_dir
1930 vnode_put(nd
.ni_vp
);
1933 thread_t th
= vfs_context_thread(ctx
);
1935 uthread_t uth
= get_bsdthread_info(th
);
1937 uth
->uu_cdir
= nd
.ni_vp
;
1938 OSBitOrAtomic(P_THCWD
, (UInt32
*)&p
->p_flag
);
1940 vnode_rele(nd
.ni_vp
);
1946 fdp
->fd_cdir
= nd
.ni_vp
;
1957 chdir(proc_t p
, struct chdir_args
*uap
, __unused register_t
*retval
)
1959 return common_chdir(p
, (void *)uap
, 0);
1963 __pthread_chdir(proc_t p
, struct __pthread_chdir_args
*uap
, __unused register_t
*retval
)
1965 return common_chdir(p
, (void *)uap
, 1);
1970 * Change notion of root (``/'') directory.
1974 chroot(proc_t p
, struct chroot_args
*uap
, __unused register_t
*retval
)
1976 struct filedesc
*fdp
= p
->p_fd
;
1978 struct nameidata nd
;
1980 vfs_context_t ctx
= vfs_context_current();
1982 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
1985 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1986 UIO_USERSPACE
, uap
->path
, ctx
);
1987 error
= change_dir(&nd
, ctx
);
1992 error
= mac_vnode_check_chroot(ctx
, nd
.ni_vp
,
1995 vnode_put(nd
.ni_vp
);
2000 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
2001 vnode_put(nd
.ni_vp
);
2004 vnode_put(nd
.ni_vp
);
2008 fdp
->fd_rdir
= nd
.ni_vp
;
2009 fdp
->fd_flags
|= FD_CHROOT
;
2019 * Common routine for chroot and chdir.
2021 * Returns: 0 Success
2022 * ENOTDIR Not a directory
2023 * namei:??? [anything namei can return]
2024 * vnode_authorize:??? [anything vnode_authorize can return]
2027 change_dir(struct nameidata
*ndp
, vfs_context_t ctx
)
2032 if ((error
= namei(ndp
)))
2037 if (vp
->v_type
!= VDIR
) {
2043 error
= mac_vnode_check_chdir(ctx
, vp
);
2050 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, ctx
);
2060 * Check permissions, allocate an open file structure,
2061 * and call the device open routine if any.
2063 * Returns: 0 Success
2074 #warning XXX implement uid, gid
2076 open1(vfs_context_t ctx
, struct nameidata
*ndp
, int uflags
, struct vnode_attr
*vap
, register_t
*retval
)
2078 proc_t p
= vfs_context_proc(ctx
);
2079 uthread_t uu
= get_bsdthread_info(vfs_context_thread(ctx
));
2080 struct filedesc
*fdp
= p
->p_fd
;
2081 struct fileproc
*fp
;
2084 struct fileproc
*nfp
;
2085 int type
, indx
, error
;
2087 int no_controlling_tty
= 0;
2088 int deny_controlling_tty
= 0;
2089 struct session
*sessp
= SESSION_NULL
;
2090 struct vfs_context context
= *vfs_context_current(); /* local copy */
2094 if ((oflags
& O_ACCMODE
) == O_ACCMODE
)
2096 flags
= FFLAGS(uflags
);
2098 AUDIT_ARG(fflags
, oflags
);
2099 AUDIT_ARG(mode
, vap
->va_mode
);
2101 if ( (error
= falloc(p
, &nfp
, &indx
, ctx
)) ) {
2105 uu
->uu_dupfd
= -indx
- 1;
2107 if (!(p
->p_flag
& P_CONTROLT
)) {
2108 sessp
= proc_session(p
);
2109 no_controlling_tty
= 1;
2111 * If conditions would warrant getting a controlling tty if
2112 * the device being opened is a tty (see ttyopen in tty.c),
2113 * but the open flags deny it, set a flag in the session to
2116 if (SESS_LEADER(p
, sessp
) &&
2117 sessp
->s_ttyvp
== NULL
&&
2118 (flags
& O_NOCTTY
)) {
2119 session_lock(sessp
);
2120 sessp
->s_flags
|= S_NOCTTY
;
2121 session_unlock(sessp
);
2122 deny_controlling_tty
= 1;
2126 if ((error
= vn_open_auth(ndp
, &flags
, vap
))) {
2127 if ((error
== ENODEV
|| error
== ENXIO
) && (uu
->uu_dupfd
>= 0)){ /* XXX from fdopen */
2128 if ((error
= dupfdopen(fdp
, indx
, uu
->uu_dupfd
, flags
, error
)) == 0) {
2129 fp_drop(p
, indx
, NULL
, 0);
2131 if (deny_controlling_tty
) {
2132 session_lock(sessp
);
2133 sessp
->s_flags
&= ~S_NOCTTY
;
2134 session_unlock(sessp
);
2136 if (sessp
!= SESSION_NULL
)
2137 session_rele(sessp
);
2141 if (error
== ERESTART
)
2143 fp_free(p
, indx
, fp
);
2145 if (deny_controlling_tty
) {
2146 session_lock(sessp
);
2147 sessp
->s_flags
&= ~S_NOCTTY
;
2148 session_unlock(sessp
);
2150 if (sessp
!= SESSION_NULL
)
2151 session_rele(sessp
);
2157 fp
->f_fglob
->fg_flag
= flags
& (FMASK
| O_EVTONLY
);
2158 fp
->f_fglob
->fg_type
= DTYPE_VNODE
;
2159 fp
->f_fglob
->fg_ops
= &vnops
;
2160 fp
->f_fglob
->fg_data
= (caddr_t
)vp
;
2162 if (flags
& (O_EXLOCK
| O_SHLOCK
)) {
2163 lf
.l_whence
= SEEK_SET
;
2166 if (flags
& O_EXLOCK
)
2167 lf
.l_type
= F_WRLCK
;
2169 lf
.l_type
= F_RDLCK
;
2171 if ((flags
& FNONBLOCK
) == 0)
2174 error
= mac_file_check_lock(vfs_context_ucred(ctx
), fp
->f_fglob
,
2179 if ((error
= VNOP_ADVLOCK(vp
, (caddr_t
)fp
->f_fglob
, F_SETLK
, &lf
, type
, ctx
)))
2181 fp
->f_fglob
->fg_flag
|= FHASLOCK
;
2184 /* try to truncate by setting the size attribute */
2185 if ((flags
& O_TRUNC
) && ((error
= vnode_setsize(vp
, (off_t
)0, 0, ctx
)) != 0))
2189 * If the open flags denied the acquisition of a controlling tty,
2190 * clear the flag in the session structure that prevented the lower
2191 * level code from assigning one.
2193 if (deny_controlling_tty
) {
2194 session_lock(sessp
);
2195 sessp
->s_flags
&= ~S_NOCTTY
;
2196 session_unlock(sessp
);
2200 * If a controlling tty was set by the tty line discipline, then we
2201 * want to set the vp of the tty into the session structure. We have
2202 * a race here because we can't get to the vp for the tp in ttyopen,
2203 * because it's not passed as a parameter in the open path.
2205 if (no_controlling_tty
&& (p
->p_flag
& P_CONTROLT
)) {
2208 session_lock(sessp
);
2209 ttyvp
= sessp
->s_ttyvp
;
2210 sessp
->s_ttyvp
= vp
;
2211 sessp
->s_ttyvid
= vnode_vid(vp
);
2212 session_unlock(sessp
);
2213 if (ttyvp
!= NULLVP
)
2220 procfdtbl_releasefd(p
, indx
, NULL
);
2221 fp_drop(p
, indx
, fp
, 1);
2226 if (sessp
!= SESSION_NULL
)
2227 session_rele(sessp
);
2230 if (deny_controlling_tty
) {
2231 session_lock(sessp
);
2232 sessp
->s_flags
&= ~S_NOCTTY
;
2233 session_unlock(sessp
);
2235 if (sessp
!= SESSION_NULL
)
2236 session_rele(sessp
);
2238 /* Modify local copy (to not damage thread copy) */
2239 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
2241 vn_close(vp
, fp
->f_fglob
->fg_flag
, &context
);
2243 fp_free(p
, indx
, fp
);
2250 * An open system call using an extended argument list compared to the regular
2251 * system call 'open'.
2253 * Parameters: p Process requesting the open
2254 * uap User argument descriptor (see below)
2255 * retval Pointer to an area to receive the
2256 * return calue from the system call
2258 * Indirect: uap->path Path to open (same as 'open')
2259 * uap->flags Flags to open (same as 'open'
2260 * uap->uid UID to set, if creating
2261 * uap->gid GID to set, if creating
2262 * uap->mode File mode, if creating (same as 'open')
2263 * uap->xsecurity ACL to set, if creating
2265 * Returns: 0 Success
2268 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
2270 * XXX: We should enummerate the possible errno values here, and where
2271 * in the code they originated.
2274 open_extended(proc_t p
, struct open_extended_args
*uap
, register_t
*retval
)
2276 struct filedesc
*fdp
= p
->p_fd
;
2278 kauth_filesec_t xsecdst
;
2279 struct vnode_attr va
;
2280 struct nameidata nd
;
2284 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
2285 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
2289 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
2290 VATTR_SET(&va
, va_mode
, cmode
);
2291 if (uap
->uid
!= KAUTH_UID_NONE
)
2292 VATTR_SET(&va
, va_uid
, uap
->uid
);
2293 if (uap
->gid
!= KAUTH_GID_NONE
)
2294 VATTR_SET(&va
, va_gid
, uap
->gid
);
2295 if (xsecdst
!= NULL
)
2296 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2298 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, vfs_context_current());
2300 ciferror
= open1(vfs_context_current(), &nd
, uap
->flags
, &va
, retval
);
2301 if (xsecdst
!= NULL
)
2302 kauth_filesec_free(xsecdst
);
2308 open(proc_t p
, struct open_args
*uap
, register_t
*retval
)
2310 __pthread_testcancel(1);
2311 return(open_nocancel(p
, (struct open_nocancel_args
*)uap
, retval
));
2316 open_nocancel(proc_t p
, struct open_nocancel_args
*uap
, register_t
*retval
)
2318 struct filedesc
*fdp
= p
->p_fd
;
2319 struct vnode_attr va
;
2320 struct nameidata nd
;
2324 /* Mask off all but regular access permissions */
2325 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
2326 VATTR_SET(&va
, va_mode
, cmode
& ACCESSPERMS
);
2328 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, vfs_context_current());
2330 return(open1(vfs_context_current(), &nd
, uap
->flags
, &va
, retval
));
2335 * Create a special file.
2337 static int mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
);
2340 mknod(proc_t p
, struct mknod_args
*uap
, __unused register_t
*retval
)
2342 struct vnode_attr va
;
2343 vfs_context_t ctx
= vfs_context_current();
2346 struct nameidata nd
;
2350 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
2351 VATTR_SET(&va
, va_rdev
, uap
->dev
);
2353 /* If it's a mknod() of a FIFO, call mkfifo1() instead */
2354 if ((uap
->mode
& S_IFMT
) == S_IFIFO
)
2355 return(mkfifo1(ctx
, uap
->path
, &va
));
2357 AUDIT_ARG(mode
, uap
->mode
);
2358 AUDIT_ARG(dev
, uap
->dev
);
2360 if ((error
= suser(vfs_context_ucred(ctx
), &p
->p_acflag
)))
2362 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
2363 UIO_USERSPACE
, uap
->path
, ctx
);
2375 switch (uap
->mode
& S_IFMT
) {
2376 case S_IFMT
: /* used by badsect to flag bad sectors */
2377 VATTR_SET(&va
, va_type
, VBAD
);
2380 VATTR_SET(&va
, va_type
, VCHR
);
2383 VATTR_SET(&va
, va_type
, VBLK
);
2395 error
= mac_vnode_check_create(ctx
,
2396 nd
.ni_dvp
, &nd
.ni_cnd
, &va
);
2402 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
2406 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, CREATE
, ctx
);
2408 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, &va
, 0, ctx
);
2414 int update_flags
= 0;
2416 // Make sure the name & parent pointers are hooked up
2417 if (vp
->v_name
== NULL
)
2418 update_flags
|= VNODE_UPDATE_NAME
;
2419 if (vp
->v_parent
== NULLVP
)
2420 update_flags
|= VNODE_UPDATE_PARENT
;
2423 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
2426 add_fsevent(FSE_CREATE_FILE
, ctx
,
2434 * nameidone has to happen before we vnode_put(dvp)
2435 * since it may need to release the fs_nodelock on the dvp
2447 * Create a named pipe.
2449 * Returns: 0 Success
2452 * vnode_authorize:???
2456 mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
)
2460 struct nameidata nd
;
2462 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
2463 UIO_USERSPACE
, upath
, ctx
);
2470 /* check that this is a new file and authorize addition */
2475 VATTR_SET(vap
, va_type
, VFIFO
);
2478 error
= mac_vnode_check_create(ctx
, nd
.ni_dvp
,
2485 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
2489 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
);
2492 * nameidone has to happen before we vnode_put(dvp)
2493 * since it may need to release the fs_nodelock on the dvp
2506 * A mkfifo system call using an extended argument list compared to the regular
2507 * system call 'mkfifo'.
2509 * Parameters: p Process requesting the open
2510 * uap User argument descriptor (see below)
2513 * Indirect: uap->path Path to fifo (same as 'mkfifo')
2514 * uap->uid UID to set
2515 * uap->gid GID to set
2516 * uap->mode File mode to set (same as 'mkfifo')
2517 * uap->xsecurity ACL to set, if creating
2519 * Returns: 0 Success
2522 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
2524 * XXX: We should enummerate the possible errno values here, and where
2525 * in the code they originated.
2528 mkfifo_extended(proc_t p
, struct mkfifo_extended_args
*uap
, __unused register_t
*retval
)
2531 kauth_filesec_t xsecdst
;
2532 struct vnode_attr va
;
2534 xsecdst
= KAUTH_FILESEC_NONE
;
2535 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
2536 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
2541 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
2542 if (uap
->uid
!= KAUTH_UID_NONE
)
2543 VATTR_SET(&va
, va_uid
, uap
->uid
);
2544 if (uap
->gid
!= KAUTH_GID_NONE
)
2545 VATTR_SET(&va
, va_gid
, uap
->gid
);
2546 if (xsecdst
!= KAUTH_FILESEC_NONE
)
2547 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2549 ciferror
= mkfifo1(vfs_context_current(), uap
->path
, &va
);
2551 if (xsecdst
!= KAUTH_FILESEC_NONE
)
2552 kauth_filesec_free(xsecdst
);
2558 mkfifo(proc_t p
, struct mkfifo_args
*uap
, __unused register_t
*retval
)
2560 struct vnode_attr va
;
2563 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
2565 return(mkfifo1(vfs_context_current(), uap
->path
, &va
));
2569 * Make a hard file link.
2571 * Returns: 0 Success
2576 * vnode_authorize:???
2581 link(__unused proc_t p
, struct link_args
*uap
, __unused register_t
*retval
)
2583 vnode_t vp
, dvp
, lvp
;
2584 struct nameidata nd
;
2585 vfs_context_t ctx
= vfs_context_current();
2588 int need_event
, has_listeners
;
2589 char *target_path
= NULL
;
2591 vp
= dvp
= lvp
= NULLVP
;
2593 /* look up the object we are linking to */
2594 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2595 UIO_USERSPACE
, uap
->path
, ctx
);
2604 * Normally, linking to directories is not supported.
2605 * However, some file systems may have limited support.
2607 if (vp
->v_type
== VDIR
) {
2608 if (!(vp
->v_mount
->mnt_vtable
->vfc_vfsflags
& VFC_VFSDIRLINKS
)) {
2609 error
= EPERM
; /* POSIX */
2612 /* Linking to a directory requires ownership. */
2613 if (!kauth_cred_issuser(vfs_context_ucred(ctx
))) {
2614 struct vnode_attr dva
;
2617 VATTR_WANTED(&dva
, va_uid
);
2618 if (vnode_getattr(vp
, &dva
, ctx
) != 0 ||
2619 !VATTR_IS_SUPPORTED(&dva
, va_uid
) ||
2620 (dva
.va_uid
!= kauth_cred_getuid(vfs_context_ucred(ctx
)))) {
2627 /* lookup the target node */
2628 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2629 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| AUDITVNPATH2
| CN_NBMOUNTLOOK
;
2630 nd
.ni_dirp
= uap
->link
;
2638 if ((error
= mac_vnode_check_link(ctx
, dvp
, vp
, &nd
.ni_cnd
)) != 0)
2642 /* or to anything that kauth doesn't want us to (eg. immutable items) */
2643 if ((error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_LINKTARGET
, ctx
)) != 0)
2646 /* target node must not exist */
2647 if (lvp
!= NULLVP
) {
2651 /* cannot link across mountpoints */
2652 if (vnode_mount(vp
) != vnode_mount(dvp
)) {
2657 /* authorize creation of the target note */
2658 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
2661 /* and finally make the link */
2662 error
= VNOP_LINK(vp
, dvp
, &nd
.ni_cnd
, ctx
);
2667 need_event
= need_fsevent(FSE_CREATE_FILE
, dvp
);
2671 has_listeners
= kauth_authorize_fileop_has_listeners();
2673 if (need_event
|| has_listeners
) {
2674 char *link_to_path
= NULL
;
2675 int len
, link_name_len
;
2677 /* build the path to the new link file */
2678 GET_PATH(target_path
);
2679 if (target_path
== NULL
) {
2685 vn_getpath(dvp
, target_path
, &len
);
2686 if ((len
+ 1 + nd
.ni_cnd
.cn_namelen
+ 1) < MAXPATHLEN
) {
2687 target_path
[len
-1] = '/';
2688 strlcpy(&target_path
[len
], nd
.ni_cnd
.cn_nameptr
, MAXPATHLEN
-len
);
2689 len
+= nd
.ni_cnd
.cn_namelen
;
2692 if (has_listeners
) {
2693 /* build the path to file we are linking to */
2694 GET_PATH(link_to_path
);
2695 if (link_to_path
== NULL
) {
2700 link_name_len
= MAXPATHLEN
;
2701 vn_getpath(vp
, link_to_path
, &link_name_len
);
2704 * Call out to allow 3rd party notification of rename.
2705 * Ignore result of kauth_authorize_fileop call.
2707 kauth_authorize_fileop(vfs_context_ucred(ctx
), KAUTH_FILEOP_LINK
,
2708 (uintptr_t)link_to_path
, (uintptr_t)target_path
);
2709 if (link_to_path
!= NULL
) {
2710 RELEASE_PATH(link_to_path
);
2715 /* construct fsevent */
2716 if (get_fse_info(vp
, &finfo
, ctx
) == 0) {
2717 // build the path to the destination of the link
2718 add_fsevent(FSE_CREATE_FILE
, ctx
,
2719 FSE_ARG_STRING
, len
, target_path
,
2720 FSE_ARG_FINFO
, &finfo
,
2728 * nameidone has to happen before we vnode_put(dvp)
2729 * since it may need to release the fs_nodelock on the dvp
2732 if (target_path
!= NULL
) {
2733 RELEASE_PATH(target_path
);
2745 * Make a symbolic link.
2747 * We could add support for ACLs here too...
2751 symlink(proc_t p
, struct symlink_args
*uap
, __unused register_t
*retval
)
2753 struct vnode_attr va
;
2756 struct nameidata nd
;
2757 vfs_context_t ctx
= vfs_context_current();
2761 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2762 error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
);
2765 AUDIT_ARG(text
, path
); /* This is the link string */
2767 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
2768 UIO_USERSPACE
, uap
->link
, ctx
);
2776 VATTR_SET(&va
, va_type
, VLNK
);
2777 VATTR_SET(&va
, va_mode
, ACCESSPERMS
& ~p
->p_fd
->fd_cmask
);
2779 error
= mac_vnode_check_create(ctx
,
2780 dvp
, &nd
.ni_cnd
, &va
);
2793 error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
);
2794 /* get default ownership, etc. */
2796 error
= vnode_authattr_new(dvp
, &va
, 0, ctx
);
2798 error
= VNOP_SYMLINK(dvp
, &vp
, &nd
.ni_cnd
, &va
, path
, ctx
);
2800 /* do fallback attribute handling */
2802 error
= vnode_setattr_fallback(vp
, &va
, ctx
);
2805 int update_flags
= 0;
2808 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
2809 nd
.ni_cnd
.cn_flags
= 0;
2817 #if 0 /* XXX - kauth_todo - is KAUTH_FILEOP_SYMLINK needed? */
2818 /* call out to allow 3rd party notification of rename.
2819 * Ignore result of kauth_authorize_fileop call.
2821 if (kauth_authorize_fileop_has_listeners() &&
2823 char *new_link_path
= NULL
;
2826 /* build the path to the new link file */
2827 new_link_path
= get_pathbuff();
2829 vn_getpath(dvp
, new_link_path
, &len
);
2830 if ((len
+ 1 + nd
.ni_cnd
.cn_namelen
+ 1) < MAXPATHLEN
) {
2831 new_link_path
[len
- 1] = '/';
2832 strlcpy(&new_link_path
[len
], nd
.ni_cnd
.cn_nameptr
, MAXPATHLEN
-len
);
2835 kauth_authorize_fileop(vfs_context_ucred(ctx
), KAUTH_FILEOP_SYMLINK
,
2836 (uintptr_t)path
, (uintptr_t)new_link_path
);
2837 if (new_link_path
!= NULL
)
2838 release_pathbuff(new_link_path
);
2841 // Make sure the name & parent pointers are hooked up
2842 if (vp
->v_name
== NULL
)
2843 update_flags
|= VNODE_UPDATE_NAME
;
2844 if (vp
->v_parent
== NULLVP
)
2845 update_flags
|= VNODE_UPDATE_PARENT
;
2848 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
2851 add_fsevent(FSE_CREATE_FILE
, ctx
,
2859 * nameidone has to happen before we vnode_put(dvp)
2860 * since it may need to release the fs_nodelock on the dvp
2868 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
2874 * Delete a whiteout from the filesystem.
2877 #warning XXX authorization not implmented for whiteouts
2879 undelete(__unused proc_t p
, struct undelete_args
*uap
, __unused register_t
*retval
)
2882 struct nameidata nd
;
2883 vfs_context_t ctx
= vfs_context_current();
2886 NDINIT(&nd
, DELETE
, LOCKPARENT
|DOWHITEOUT
|AUDITVNPATH1
,
2887 UIO_USERSPACE
, uap
->path
, ctx
);
2894 if (vp
== NULLVP
&& (nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
2895 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, DELETE
, ctx
);
2900 * nameidone has to happen before we vnode_put(dvp)
2901 * since it may need to release the fs_nodelock on the dvp
2913 * Delete a name from the filesystem.
2917 unlink1(vfs_context_t ctx
, struct nameidata
*ndp
, int nodelbusy
)
2921 struct componentname
*cnp
;
2927 int has_listeners
= 0;
2929 ndp
->ni_cnd
.cn_flags
|= LOCKPARENT
;
2938 /* With Carbon delete semantics, busy files cannot be deleted */
2940 flags
|= VNODE_REMOVE_NODELETEBUSY
;
2944 * Normally, unlinking of directories is not supported.
2945 * However, some file systems may have limited support.
2947 if ((vp
->v_type
== VDIR
) &&
2948 !(vp
->v_mount
->mnt_vtable
->vfc_vfsflags
& VFC_VFSDIRLINKS
)) {
2949 error
= EPERM
; /* POSIX */
2953 * The root of a mounted filesystem cannot be deleted.
2955 if (vp
->v_flag
& VROOT
) {
2962 /* authorize the delete operation */
2965 error
= mac_vnode_check_unlink(ctx
,
2969 error
= vnode_authorize(vp
, ndp
->ni_dvp
, KAUTH_VNODE_DELETE
, ctx
);
2974 need_event
= need_fsevent(FSE_DELETE
, dvp
);
2976 if ((vp
->v_flag
& VISHARDLINK
) == 0) {
2977 get_fse_info(vp
, &finfo
, ctx
);
2981 has_listeners
= kauth_authorize_fileop_has_listeners();
2982 if (need_event
|| has_listeners
) {
2989 vn_getpath(vp
, path
, &len
);
2993 if (ndp
->ni_cnd
.cn_flags
& CN_WANTSRSRCFORK
)
2994 error
= vnode_removenamedstream(dvp
, vp
, XATTR_RESOURCEFORK_NAME
, 0, ctx
);
2997 error
= VNOP_REMOVE(dvp
, vp
, &ndp
->ni_cnd
, flags
, ctx
);
3000 * Call out to allow 3rd party notification of delete.
3001 * Ignore result of kauth_authorize_fileop call.
3004 if (has_listeners
) {
3005 kauth_authorize_fileop(vfs_context_ucred(ctx
),
3006 KAUTH_FILEOP_DELETE
,
3011 if (vp
->v_flag
& VISHARDLINK
) {
3013 // if a hardlink gets deleted we want to blow away the
3014 // v_parent link because the path that got us to this
3015 // instance of the link is no longer valid. this will
3016 // force the next call to get the path to ask the file
3017 // system instead of just following the v_parent link.
3019 vnode_update_identity(vp
, NULL
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
3024 if (vp
->v_flag
& VISHARDLINK
) {
3025 get_fse_info(vp
, &finfo
, ctx
);
3027 add_fsevent(FSE_DELETE
, ctx
,
3028 FSE_ARG_STRING
, len
, path
,
3029 FSE_ARG_FINFO
, &finfo
,
3038 * nameidone has to happen before we vnode_put(dvp)
3039 * since it may need to release the fs_nodelock on the dvp
3049 * Delete a name from the filesystem using POSIX semantics.
3052 unlink(__unused proc_t p
, struct unlink_args
*uap
, __unused register_t
*retval
)
3054 struct nameidata nd
;
3055 vfs_context_t ctx
= vfs_context_current();
3057 NDINIT(&nd
, DELETE
, AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, ctx
);
3058 return unlink1(ctx
, &nd
, 0);
3062 * Delete a name from the filesystem using Carbon semantics.
3065 delete(__unused proc_t p
, struct delete_args
*uap
, __unused register_t
*retval
)
3067 struct nameidata nd
;
3068 vfs_context_t ctx
= vfs_context_current();
3070 NDINIT(&nd
, DELETE
, AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, ctx
);
3071 return unlink1(ctx
, &nd
, 1);
3075 * Reposition read/write file offset.
3078 lseek(proc_t p
, struct lseek_args
*uap
, off_t
*retval
)
3080 struct fileproc
*fp
;
3082 struct vfs_context
*ctx
;
3083 off_t offset
= uap
->offset
, file_size
;
3086 if ( (error
= fp_getfvp(p
,uap
->fd
, &fp
, &vp
)) ) {
3087 if (error
== ENOTSUP
)
3091 if (vnode_isfifo(vp
)) {
3097 ctx
= vfs_context_current();
3099 if (uap
->whence
== L_INCR
&& uap
->offset
== 0)
3100 error
= mac_file_check_get_offset(vfs_context_ucred(ctx
),
3103 error
= mac_file_check_change_offset(vfs_context_ucred(ctx
),
3110 if ( (error
= vnode_getwithref(vp
)) ) {
3115 switch (uap
->whence
) {
3117 offset
+= fp
->f_fglob
->fg_offset
;
3120 if ((error
= vnode_size(vp
, &file_size
, ctx
)) != 0)
3122 offset
+= file_size
;
3130 if (uap
->offset
> 0 && offset
< 0) {
3131 /* Incremented/relative move past max size */
3135 * Allow negative offsets on character devices, per
3136 * POSIX 1003.1-2001. Most likely for writing disk
3139 if (offset
< 0 && vp
->v_type
!= VCHR
) {
3140 /* Decremented/relative move before start */
3144 fp
->f_fglob
->fg_offset
= offset
;
3145 *retval
= fp
->f_fglob
->fg_offset
;
3149 (void)vnode_put(vp
);
3156 * Check access permissions.
3158 * Returns: 0 Success
3159 * vnode_authorize:???
3162 access1(vnode_t vp
, vnode_t dvp
, int uflags
, vfs_context_t ctx
)
3164 kauth_action_t action
;
3168 * If just the regular access bits, convert them to something
3169 * that vnode_authorize will understand.
3171 if (!(uflags
& _ACCESS_EXTENDED_MASK
)) {
3174 action
|= KAUTH_VNODE_READ_DATA
; /* aka KAUTH_VNODE_LIST_DIRECTORY */
3175 if (uflags
& W_OK
) {
3176 if (vnode_isdir(vp
)) {
3177 action
|= KAUTH_VNODE_ADD_FILE
|
3178 KAUTH_VNODE_ADD_SUBDIRECTORY
;
3179 /* might want delete rights here too */
3181 action
|= KAUTH_VNODE_WRITE_DATA
;
3184 if (uflags
& X_OK
) {
3185 if (vnode_isdir(vp
)) {
3186 action
|= KAUTH_VNODE_SEARCH
;
3188 action
|= KAUTH_VNODE_EXECUTE
;
3192 /* take advantage of definition of uflags */
3193 action
= uflags
>> 8;
3197 error
= mac_vnode_check_access(ctx
, vp
, uflags
);
3202 /* action == 0 means only check for existence */
3204 error
= vnode_authorize(vp
, dvp
, action
| KAUTH_VNODE_ACCESS
, ctx
);
3217 * Description: uap->entries Pointer to argument descriptor
3218 * uap->size Size of the area pointed to by
3220 * uap->results Pointer to the results array
3222 * Returns: 0 Success
3223 * ENOMEM Insufficient memory
3224 * EINVAL Invalid arguments
3225 * namei:EFAULT Bad address
3226 * namei:ENAMETOOLONG Filename too long
3227 * namei:ENOENT No such file or directory
3228 * namei:ELOOP Too many levels of symbolic links
3229 * namei:EBADF Bad file descriptor
3230 * namei:ENOTDIR Not a directory
3235 * uap->results Array contents modified
3237 * Notes: The uap->entries are structured as an arbitrary length array
3238 * of accessx descriptors, followed by one or more NULL terniated
3241 * struct accessx_descriptor[0]
3243 * struct accessx_descriptor[n]
3244 * char name_data[0];
3246 * We determine the entry count by walking the buffer containing
3247 * the uap->entries argument descriptor. For each descrptor we
3248 * see, the valid values for the offset ad_name_offset will be
3249 * in the byte range:
3251 * [ uap->entries + sizeof(struct accessx_descriptor) ]
3253 * [ uap->entries + uap->size - 2 ]
3255 * since we must have at least one string, and the string must
3256 * be at least one character plus the NUL terminator in length.
3258 * XXX: Need to support the check-as uid argument
3261 access_extended(__unused proc_t p
, struct access_extended_args
*uap
, __unused register_t
*retval
)
3263 struct accessx_descriptor
*input
= NULL
;
3264 errno_t
*result
= NULL
;
3267 unsigned int desc_max
, desc_actual
, i
, j
;
3268 struct vfs_context context
;
3269 struct nameidata nd
;
3273 #define ACCESSX_MAX_DESCR_ON_STACK 10
3274 struct accessx_descriptor stack_input
[ACCESSX_MAX_DESCR_ON_STACK
];
3276 context
.vc_ucred
= NULL
;
3279 * Validate parameters; if valid, copy the descriptor array and string
3280 * arguments into local memory. Before proceeding, the following
3281 * conditions must have been met:
3283 * o The total size is not permitted to exceed ACCESSX_MAX_TABLESIZE
3284 * o There must be sufficient room in the request for at least one
3285 * descriptor and a one yte NUL terminated string.
3286 * o The allocation of local storage must not fail.
3288 if (uap
->size
> ACCESSX_MAX_TABLESIZE
)
3290 if (uap
->size
< (sizeof(struct accessx_descriptor
) + 2))
3292 if (uap
->size
<= sizeof (stack_input
)) {
3293 input
= stack_input
;
3295 MALLOC(input
, struct accessx_descriptor
*, uap
->size
, M_TEMP
, M_WAITOK
);
3296 if (input
== NULL
) {
3301 error
= copyin(uap
->entries
, input
, uap
->size
);
3306 * Force NUL termination of the copyin buffer to avoid nami() running
3307 * off the end. If the caller passes us bogus data, they may get a
3310 ((char *)input
)[uap
->size
- 1] = 0;
3313 * Access is defined as checking against the process' real identity,
3314 * even if operations are checking the effective identity. This
3315 * requires that we use a local vfs context.
3317 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
3318 context
.vc_thread
= current_thread();
3321 * Find out how many entries we have, so we can allocate the result
3322 * array by walking the list and adjusting the count downward by the
3323 * earliest string offset we see.
3325 desc_max
= (uap
->size
- 2) / sizeof(struct accessx_descriptor
);
3326 desc_actual
= desc_max
;
3327 for (i
= 0; i
< desc_actual
; i
++) {
3329 * Take the offset to the name string for this entry and
3330 * convert to an input array index, which would be one off
3331 * the end of the array if this entry was the lowest-addressed
3334 j
= input
[i
].ad_name_offset
/ sizeof(struct accessx_descriptor
);
3337 * An offset greater than the max allowable offset is an error.
3338 * It is also an error for any valid entry to point
3339 * to a location prior to the end of the current entry, if
3340 * it's not a reference to the string of the previous entry.
3342 if (j
> desc_max
|| (j
!= 0 && j
<= i
)) {
3348 * An offset of 0 means use the previous descriptor's offset;
3349 * this is used to chain multiple requests for the same file
3350 * to avoid multiple lookups.
3353 /* This is not valid for the first entry */
3362 * If the offset of the string for this descriptor is before
3363 * what we believe is the current actual last descriptor,
3364 * then we need to adjust our estimate downward; this permits
3365 * the string table following the last descriptor to be out
3366 * of order relative to the descriptor list.
3368 if (j
< desc_actual
)
3373 * We limit the actual number of descriptors we are willing to process
3374 * to a hard maximum of ACCESSX_MAX_DESCRIPTORS. If the number being
3375 * requested does not exceed this limit,
3377 if (desc_actual
> ACCESSX_MAX_DESCRIPTORS
) {
3381 MALLOC(result
, errno_t
*, desc_actual
* sizeof(errno_t
), M_TEMP
, M_WAITOK
);
3382 if (result
== NULL
) {
3388 * Do the work by iterating over the descriptor entries we know to
3389 * at least appear to contain valid data.
3392 for (i
= 0; i
< desc_actual
; i
++) {
3394 * If the ad_name_offset is 0, then we use the previous
3395 * results to make the check; otherwise, we are looking up
3398 if (input
[i
].ad_name_offset
!= 0) {
3399 /* discard old vnodes */
3410 * Scan forward in the descriptor list to see if we
3411 * need the parent vnode. We will need it if we are
3412 * deleting, since we must have rights to remove
3413 * entries in the parent directory, as well as the
3414 * rights to delete the object itself.
3416 wantdelete
= input
[i
].ad_flags
& _DELETE_OK
;
3417 for (j
= i
+ 1; (j
< desc_actual
) && (input
[j
].ad_name_offset
== 0); j
++)
3418 if (input
[j
].ad_flags
& _DELETE_OK
)
3421 niopts
= FOLLOW
| AUDITVNPATH1
;
3423 /* need parent for vnode_authorize for deletion test */
3425 niopts
|= WANTPARENT
;
3428 NDINIT(&nd
, LOOKUP
, niopts
, UIO_SYSSPACE
, CAST_USER_ADDR_T(((const char *)input
) + input
[i
].ad_name_offset
), &context
);
3439 * Handle lookup errors.
3449 /* run this access check */
3450 result
[i
] = access1(vp
, dvp
, input
[i
].ad_flags
, &context
);
3453 /* fatal lookup error */
3459 /* copy out results */
3460 error
= copyout(result
, uap
->results
, desc_actual
* sizeof(errno_t
));
3463 if (input
&& input
!= stack_input
)
3464 FREE(input
, M_TEMP
);
3466 FREE(result
, M_TEMP
);
3471 if (IS_VALID_CRED(context
.vc_ucred
))
3472 kauth_cred_unref(&context
.vc_ucred
);
3478 * Returns: 0 Success
3479 * namei:EFAULT Bad address
3480 * namei:ENAMETOOLONG Filename too long
3481 * namei:ENOENT No such file or directory
3482 * namei:ELOOP Too many levels of symbolic links
3483 * namei:EBADF Bad file descriptor
3484 * namei:ENOTDIR Not a directory
3489 access(__unused proc_t p
, struct access_args
*uap
, __unused register_t
*retval
)
3492 struct nameidata nd
;
3494 struct vfs_context context
;
3497 int is_namedstream
= 0;
3501 * Access is defined as checking against the process'
3502 * real identity, even if operations are checking the
3503 * effective identity. So we need to tweak the credential
3506 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
3507 context
.vc_thread
= current_thread();
3509 niopts
= FOLLOW
| AUDITVNPATH1
;
3510 /* need parent for vnode_authorize for deletion test */
3511 if (uap
->flags
& _DELETE_OK
)
3512 niopts
|= WANTPARENT
;
3513 NDINIT(&nd
, LOOKUP
, niopts
, UIO_USERSPACE
, uap
->path
, &context
);
3516 /* access(F_OK) calls are allowed for resource forks. */
3517 if (uap
->flags
== F_OK
)
3518 nd
.ni_cnd
.cn_flags
|= CN_ALLOWRSRCFORK
;
3525 /* Grab reference on the shadow stream file vnode to
3526 * force an inactive on release which will mark it for
3529 if (vnode_isnamedstream(nd
.ni_vp
) &&
3530 (nd
.ni_vp
->v_parent
!= NULLVP
) &&
3531 ((nd
.ni_vp
->v_parent
->v_mount
->mnt_kern_flag
& MNTK_NAMED_STREAMS
) == 0)) {
3533 vnode_ref(nd
.ni_vp
);
3537 error
= access1(nd
.ni_vp
, nd
.ni_dvp
, uap
->flags
, &context
);
3540 if (is_namedstream
) {
3541 vnode_rele(nd
.ni_vp
);
3545 vnode_put(nd
.ni_vp
);
3546 if (uap
->flags
& _DELETE_OK
)
3547 vnode_put(nd
.ni_dvp
);
3551 kauth_cred_unref(&context
.vc_ucred
);
3557 * Returns: 0 Success
3564 stat2(vfs_context_t ctx
, struct nameidata
*ndp
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
, int isstat64
)
3568 struct user_stat user_sb
;
3569 struct user_stat64 user_sb64
;
3572 kauth_filesec_t fsec
;
3573 size_t xsecurity_bufsize
;
3577 int is_namedstream
= 0;
3578 /* stat calls are allowed for resource forks. */
3579 ndp
->ni_cnd
.cn_flags
|= CN_ALLOWRSRCFORK
;
3584 fsec
= KAUTH_FILESEC_NONE
;
3586 statptr
= (void *)&sb64
;
3588 statptr
= (void *)&sb
;
3591 /* Grab reference on the shadow stream file vnode to
3592 * force an inactive on release which will mark it for
3595 if (vnode_isnamedstream(ndp
->ni_vp
) &&
3596 (ndp
->ni_vp
->v_parent
!= NULLVP
) &&
3597 ((ndp
->ni_vp
->v_parent
->v_mount
->mnt_kern_flag
& MNTK_NAMED_STREAMS
) == 0)) {
3599 vnode_ref (ndp
->ni_vp
);
3603 error
= vn_stat(ndp
->ni_vp
, statptr
, (xsecurity
!= USER_ADDR_NULL
? &fsec
: NULL
), isstat64
, ctx
);
3606 if (is_namedstream
) {
3607 vnode_rele (ndp
->ni_vp
);
3611 vnode_put(ndp
->ni_vp
);
3616 /* Zap spare fields */
3617 if (isstat64
!= 0) {
3619 sb64
.st_qspare
[0] = 0LL;
3620 sb64
.st_qspare
[1] = 0LL;
3621 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
3622 munge_stat64(&sb64
, &user_sb64
);
3623 my_size
= sizeof(user_sb64
);
3624 sbp
= (caddr_t
)&user_sb64
;
3626 my_size
= sizeof(sb64
);
3627 sbp
= (caddr_t
)&sb64
;
3630 * Check if we raced (post lookup) against the last unlink of a file.
3632 if ((sb64
.st_nlink
== 0) && S_ISREG(sb64
.st_mode
)) {
3637 sb
.st_qspare
[0] = 0LL;
3638 sb
.st_qspare
[1] = 0LL;
3639 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
3640 munge_stat(&sb
, &user_sb
);
3641 my_size
= sizeof(user_sb
);
3642 sbp
= (caddr_t
)&user_sb
;
3644 my_size
= sizeof(sb
);
3649 * Check if we raced (post lookup) against the last unlink of a file.
3651 if ((sb
.st_nlink
== 0) && S_ISREG(sb
.st_mode
)) {
3655 if ((error
= copyout(sbp
, ub
, my_size
)) != 0)
3658 /* caller wants extended security information? */
3659 if (xsecurity
!= USER_ADDR_NULL
) {
3661 /* did we get any? */
3662 if (fsec
== KAUTH_FILESEC_NONE
) {
3663 if (susize(xsecurity_size
, 0) != 0) {
3668 /* find the user buffer size */
3669 xsecurity_bufsize
= fusize(xsecurity_size
);
3671 /* copy out the actual data size */
3672 if (susize(xsecurity_size
, KAUTH_FILESEC_COPYSIZE(fsec
)) != 0) {
3677 /* if the caller supplied enough room, copy out to it */
3678 if (xsecurity_bufsize
>= KAUTH_FILESEC_COPYSIZE(fsec
))
3679 error
= copyout(fsec
, xsecurity
, KAUTH_FILESEC_COPYSIZE(fsec
));
3683 if (fsec
!= KAUTH_FILESEC_NONE
)
3684 kauth_filesec_free(fsec
);
3689 * Get file status; this version follows links.
3691 * Returns: 0 Success
3692 * stat2:??? [see stat2() in this file]
3695 stat1(user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
, int isstat64
)
3697 struct nameidata nd
;
3698 vfs_context_t ctx
= vfs_context_current();
3700 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
3701 UIO_USERSPACE
, path
, ctx
);
3702 return(stat2(ctx
, &nd
, ub
, xsecurity
, xsecurity_size
, isstat64
));
3706 stat_extended(__unused proc_t p
, struct stat_extended_args
*uap
, __unused register_t
*retval
)
3708 return (stat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 0));
3712 * Returns: 0 Success
3713 * stat1:??? [see stat1() in this file]
3716 stat(__unused proc_t p
, struct stat_args
*uap
, __unused register_t
*retval
)
3718 return(stat1(uap
->path
, uap
->ub
, 0, 0, 0));
3722 stat64(__unused proc_t p
, struct stat64_args
*uap
, __unused register_t
*retval
)
3724 return(stat1(uap
->path
, uap
->ub
, 0, 0, 1));
3728 stat64_extended(__unused proc_t p
, struct stat64_extended_args
*uap
, __unused register_t
*retval
)
3730 return (stat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 1));
3733 * Get file status; this version does not follow links.
3736 lstat1(user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
, int isstat64
)
3738 struct nameidata nd
;
3739 vfs_context_t ctx
= vfs_context_current();
3741 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| NOFOLLOW
| AUDITVNPATH1
,
3742 UIO_USERSPACE
, path
, ctx
);
3744 return(stat2(ctx
, &nd
, ub
, xsecurity
, xsecurity_size
, isstat64
));
3748 lstat_extended(__unused proc_t p
, struct lstat_extended_args
*uap
, __unused register_t
*retval
)
3750 return (lstat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 0));
3754 lstat(__unused proc_t p
, struct lstat_args
*uap
, __unused register_t
*retval
)
3756 return(lstat1(uap
->path
, uap
->ub
, 0, 0, 0));
3759 lstat64(__unused proc_t p
, struct lstat64_args
*uap
, __unused register_t
*retval
)
3761 return(lstat1(uap
->path
, uap
->ub
, 0, 0, 1));
3765 lstat64_extended(__unused proc_t p
, struct lstat64_extended_args
*uap
, __unused register_t
*retval
)
3767 return (lstat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 1));
3771 * Get configurable pathname variables.
3773 * Returns: 0 Success
3777 * Notes: Global implementation constants are intended to be
3778 * implemented in this function directly; all other constants
3779 * are per-FS implementation, and therefore must be handled in
3780 * each respective FS, instead.
3782 * XXX We implement some things globally right now that should actually be
3783 * XXX per-FS; we will need to deal with this at some point.
3787 pathconf(__unused proc_t p
, struct pathconf_args
*uap
, register_t
*retval
)
3790 struct nameidata nd
;
3791 vfs_context_t ctx
= vfs_context_current();
3793 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3794 UIO_USERSPACE
, uap
->path
, ctx
);
3799 error
= vn_pathconf(nd
.ni_vp
, uap
->name
, retval
, ctx
);
3801 vnode_put(nd
.ni_vp
);
3807 * Return target name of a symbolic link.
3811 readlink(proc_t p
, struct readlink_args
*uap
, register_t
*retval
)
3815 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
3817 struct nameidata nd
;
3818 vfs_context_t ctx
= vfs_context_current();
3819 char uio_buf
[ UIO_SIZEOF(1) ];
3821 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
3822 UIO_USERSPACE
, uap
->path
, ctx
);
3830 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
3831 &uio_buf
[0], sizeof(uio_buf
));
3832 uio_addiov(auio
, uap
->buf
, uap
->count
);
3833 if (vp
->v_type
!= VLNK
)
3837 error
= mac_vnode_check_readlink(ctx
,
3841 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, ctx
);
3843 error
= VNOP_READLINK(vp
, auio
, ctx
);
3846 // LP64todo - fix this
3847 *retval
= uap
->count
- (int)uio_resid(auio
);
3852 * Change file flags.
3855 chflags1(vnode_t vp
, int flags
, vfs_context_t ctx
)
3857 struct vnode_attr va
;
3858 kauth_action_t action
;
3862 VATTR_SET(&va
, va_flags
, flags
);
3865 error
= mac_vnode_check_setflags(ctx
, vp
, flags
);
3870 /* request authorisation, disregard immutability */
3871 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
3874 * Request that the auth layer disregard those file flags it's allowed to when
3875 * authorizing this operation; we need to do this in order to be able to
3876 * clear immutable flags.
3878 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
| KAUTH_VNODE_NOIMMUTABLE
, ctx
)) != 0))
3880 error
= vnode_setattr(vp
, &va
, ctx
);
3882 if ((error
== 0) && !VATTR_IS_SUPPORTED(&va
, va_flags
)) {
3891 * Change flags of a file given a path name.
3895 chflags(__unused proc_t p
, struct chflags_args
*uap
, __unused register_t
*retval
)
3898 vfs_context_t ctx
= vfs_context_current();
3900 struct nameidata nd
;
3902 AUDIT_ARG(fflags
, uap
->flags
);
3903 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3904 UIO_USERSPACE
, uap
->path
, ctx
);
3911 error
= chflags1(vp
, uap
->flags
, ctx
);
3917 * Change flags of a file given a file descriptor.
3921 fchflags(__unused proc_t p
, struct fchflags_args
*uap
, __unused register_t
*retval
)
3926 AUDIT_ARG(fd
, uap
->fd
);
3927 AUDIT_ARG(fflags
, uap
->flags
);
3928 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
3931 if ((error
= vnode_getwithref(vp
))) {
3936 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3938 error
= chflags1(vp
, uap
->flags
, vfs_context_current());
3945 * Change security information on a filesystem object.
3947 * Returns: 0 Success
3948 * EPERM Operation not permitted
3949 * vnode_authattr:??? [anything vnode_authattr can return]
3950 * vnode_authorize:??? [anything vnode_authorize can return]
3951 * vnode_setattr:??? [anything vnode_setattr can return]
3953 * Notes: If vnode_authattr or vnode_authorize return EACCES, it will be
3954 * translated to EPERM before being returned.
3957 chmod2(vfs_context_t ctx
, vnode_t vp
, struct vnode_attr
*vap
)
3959 kauth_action_t action
;
3962 AUDIT_ARG(mode
, (mode_t
)vap
->va_mode
);
3963 #warning XXX audit new args
3966 /* chmod calls are not allowed for resource forks. */
3967 if (vp
->v_flag
& VISNAMEDSTREAM
) {
3973 error
= mac_vnode_check_setmode(ctx
, vp
, (mode_t
)vap
->va_mode
);
3978 /* make sure that the caller is allowed to set this security information */
3979 if (((error
= vnode_authattr(vp
, vap
, &action
, ctx
)) != 0) ||
3980 ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
3981 if (error
== EACCES
)
3986 error
= vnode_setattr(vp
, vap
, ctx
);
3993 * Change mode of a file given path name.
3995 * Returns: 0 Success
3996 * namei:??? [anything namei can return]
3997 * chmod2:??? [anything chmod2 can return]
4000 chmod1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
4002 struct nameidata nd
;
4005 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4006 UIO_USERSPACE
, path
, ctx
);
4007 if ((error
= namei(&nd
)))
4009 error
= chmod2(ctx
, nd
.ni_vp
, vap
);
4010 vnode_put(nd
.ni_vp
);
4016 * A chmod system call using an extended argument list compared to the regular
4017 * system call 'mkfifo'.
4019 * Parameters: p Process requesting the open
4020 * uap User argument descriptor (see below)
4023 * Indirect: uap->path Path to object (same as 'chmod')
4024 * uap->uid UID to set
4025 * uap->gid GID to set
4026 * uap->mode File mode to set (same as 'chmod')
4027 * uap->xsecurity ACL to set (or delete)
4029 * Returns: 0 Success
4032 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
4034 * XXX: We should enummerate the possible errno values here, and where
4035 * in the code they originated.
4038 chmod_extended(__unused proc_t p
, struct chmod_extended_args
*uap
, __unused register_t
*retval
)
4041 struct vnode_attr va
;
4042 kauth_filesec_t xsecdst
;
4045 if (uap
->mode
!= -1)
4046 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
4047 if (uap
->uid
!= KAUTH_UID_NONE
)
4048 VATTR_SET(&va
, va_uid
, uap
->uid
);
4049 if (uap
->gid
!= KAUTH_GID_NONE
)
4050 VATTR_SET(&va
, va_gid
, uap
->gid
);
4053 switch(uap
->xsecurity
) {
4054 /* explicit remove request */
4055 case CAST_USER_ADDR_T((void *)1): /* _FILESEC_REMOVE_ACL */
4056 VATTR_SET(&va
, va_acl
, NULL
);
4059 case USER_ADDR_NULL
:
4062 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
4064 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
4065 KAUTH_DEBUG("CHMOD - setting ACL with %d entries", va
.va_acl
->acl_entrycount
);
4068 error
= chmod1(vfs_context_current(), uap
->path
, &va
);
4070 if (xsecdst
!= NULL
)
4071 kauth_filesec_free(xsecdst
);
4076 * Returns: 0 Success
4077 * chmod1:??? [anything chmod1 can return]
4080 chmod(__unused proc_t p
, struct chmod_args
*uap
, __unused register_t
*retval
)
4082 struct vnode_attr va
;
4085 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
4087 return(chmod1(vfs_context_current(), uap
->path
, &va
));
4091 * Change mode of a file given a file descriptor.
4094 fchmod1(__unused proc_t p
, int fd
, struct vnode_attr
*vap
)
4101 if ((error
= file_vnode(fd
, &vp
)) != 0)
4103 if ((error
= vnode_getwithref(vp
)) != 0) {
4107 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4109 error
= chmod2(vfs_context_current(), vp
, vap
);
4110 (void)vnode_put(vp
);
4117 fchmod_extended(proc_t p
, struct fchmod_extended_args
*uap
, __unused register_t
*retval
)
4120 struct vnode_attr va
;
4121 kauth_filesec_t xsecdst
;
4124 if (uap
->mode
!= -1)
4125 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
4126 if (uap
->uid
!= KAUTH_UID_NONE
)
4127 VATTR_SET(&va
, va_uid
, uap
->uid
);
4128 if (uap
->gid
!= KAUTH_GID_NONE
)
4129 VATTR_SET(&va
, va_gid
, uap
->gid
);
4132 switch(uap
->xsecurity
) {
4133 case USER_ADDR_NULL
:
4134 VATTR_SET(&va
, va_acl
, NULL
);
4136 case CAST_USER_ADDR_T(-1):
4139 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
4141 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
4144 error
= fchmod1(p
, uap
->fd
, &va
);
4147 switch(uap
->xsecurity
) {
4148 case USER_ADDR_NULL
:
4149 case CAST_USER_ADDR_T(-1):
4152 if (xsecdst
!= NULL
)
4153 kauth_filesec_free(xsecdst
);
4159 fchmod(proc_t p
, struct fchmod_args
*uap
, __unused register_t
*retval
)
4161 struct vnode_attr va
;
4164 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
4166 return(fchmod1(p
, uap
->fd
, &va
));
4171 * Set ownership given a path name.
4175 chown1(vfs_context_t ctx
, struct chown_args
*uap
, __unused register_t
*retval
, int follow
)
4178 struct vnode_attr va
;
4180 struct nameidata nd
;
4181 kauth_action_t action
;
4183 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
4185 NDINIT(&nd
, LOOKUP
, (follow
? FOLLOW
: 0) | NOTRIGGER
| AUDITVNPATH1
,
4186 UIO_USERSPACE
, uap
->path
, ctx
);
4195 if (uap
->uid
!= VNOVAL
)
4196 VATTR_SET(&va
, va_uid
, uap
->uid
);
4197 if (uap
->gid
!= VNOVAL
)
4198 VATTR_SET(&va
, va_gid
, uap
->gid
);
4201 error
= mac_vnode_check_setowner(ctx
, vp
, uap
->uid
, uap
->gid
);
4206 /* preflight and authorize attribute changes */
4207 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
4209 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
4211 error
= vnode_setattr(vp
, &va
, ctx
);
4215 * EACCES is only allowed from namei(); permissions failure should
4216 * return EPERM, so we need to translate the error code.
4218 if (error
== EACCES
)
4226 chown(__unused proc_t p
, struct chown_args
*uap
, register_t
*retval
)
4228 return chown1(vfs_context_current(), uap
, retval
, 1);
4232 lchown(__unused proc_t p
, struct lchown_args
*uap
, register_t
*retval
)
4234 /* Argument list identical, but machine generated; cast for chown1() */
4235 return chown1(vfs_context_current(), (struct chown_args
*)uap
, retval
, 0);
4239 * Set ownership given a file descriptor.
4243 fchown(__unused proc_t p
, struct fchown_args
*uap
, __unused register_t
*retval
)
4245 struct vnode_attr va
;
4246 vfs_context_t ctx
= vfs_context_current();
4249 kauth_action_t action
;
4251 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
4252 AUDIT_ARG(fd
, uap
->fd
);
4254 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
4257 if ( (error
= vnode_getwithref(vp
)) ) {
4261 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4264 if (uap
->uid
!= VNOVAL
)
4265 VATTR_SET(&va
, va_uid
, uap
->uid
);
4266 if (uap
->gid
!= VNOVAL
)
4267 VATTR_SET(&va
, va_gid
, uap
->gid
);
4270 /* chown calls are not allowed for resource forks. */
4271 if (vp
->v_flag
& VISNAMEDSTREAM
) {
4278 error
= mac_vnode_check_setowner(ctx
, vp
, uap
->uid
, uap
->gid
);
4283 /* preflight and authorize attribute changes */
4284 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
4286 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
4287 if (error
== EACCES
)
4291 error
= vnode_setattr(vp
, &va
, ctx
);
4294 (void)vnode_put(vp
);
4300 getutimes(user_addr_t usrtvp
, struct timespec
*tsp
)
4302 struct user_timeval tv
[2];
4305 if (usrtvp
== USER_ADDR_NULL
) {
4306 struct timeval old_tv
;
4307 /* XXX Y2038 bug because of microtime argument */
4309 TIMEVAL_TO_TIMESPEC(&old_tv
, &tsp
[0]);
4312 if (IS_64BIT_PROCESS(current_proc())) {
4313 error
= copyin(usrtvp
, (void *)tv
, sizeof(tv
));
4315 struct timeval old_tv
[2];
4316 error
= copyin(usrtvp
, (void *)old_tv
, sizeof(old_tv
));
4317 tv
[0].tv_sec
= old_tv
[0].tv_sec
;
4318 tv
[0].tv_usec
= old_tv
[0].tv_usec
;
4319 tv
[1].tv_sec
= old_tv
[1].tv_sec
;
4320 tv
[1].tv_usec
= old_tv
[1].tv_usec
;
4324 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
4325 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
4331 setutimes(vfs_context_t ctx
, vnode_t vp
, const struct timespec
*ts
,
4335 struct vnode_attr va
;
4336 kauth_action_t action
;
4338 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4341 VATTR_SET(&va
, va_access_time
, ts
[0]);
4342 VATTR_SET(&va
, va_modify_time
, ts
[1]);
4344 va
.va_vaflags
|= VA_UTIMES_NULL
;
4347 /* utimes calls are not allowed for resource forks. */
4348 if (vp
->v_flag
& VISNAMEDSTREAM
) {
4355 error
= mac_vnode_check_setutimes(ctx
, vp
, ts
[0], ts
[1]);
4359 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0) {
4360 if (!nullflag
&& error
== EACCES
)
4365 /* since we may not need to auth anything, check here */
4366 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
4367 if (!nullflag
&& error
== EACCES
)
4371 error
= vnode_setattr(vp
, &va
, ctx
);
4378 * Set the access and modification times of a file.
4382 utimes(__unused proc_t p
, struct utimes_args
*uap
, __unused register_t
*retval
)
4384 struct timespec ts
[2];
4387 struct nameidata nd
;
4388 vfs_context_t ctx
= vfs_context_current();
4391 * AUDIT: Needed to change the order of operations to do the
4392 * name lookup first because auditing wants the path.
4394 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4395 UIO_USERSPACE
, uap
->path
, ctx
);
4402 * Fetch the user-supplied time. If usrtvp is USER_ADDR_NULL, we fetch
4403 * the current time instead.
4406 if ((error
= getutimes(usrtvp
, ts
)) != 0)
4409 error
= setutimes(ctx
, nd
.ni_vp
, ts
, usrtvp
== USER_ADDR_NULL
);
4412 vnode_put(nd
.ni_vp
);
4417 * Set the access and modification times of a file.
4421 futimes(__unused proc_t p
, struct futimes_args
*uap
, __unused register_t
*retval
)
4423 struct timespec ts
[2];
4428 AUDIT_ARG(fd
, uap
->fd
);
4430 if ((error
= getutimes(usrtvp
, ts
)) != 0)
4432 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
4434 if((error
= vnode_getwithref(vp
))) {
4439 error
= setutimes(vfs_context_current(), vp
, ts
, usrtvp
== 0);
4446 * Truncate a file given its path name.
4450 truncate(__unused proc_t p
, struct truncate_args
*uap
, __unused register_t
*retval
)
4453 struct vnode_attr va
;
4454 vfs_context_t ctx
= vfs_context_current();
4456 struct nameidata nd
;
4457 kauth_action_t action
;
4459 if (uap
->length
< 0)
4461 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4462 UIO_USERSPACE
, uap
->path
, ctx
);
4463 if ((error
= namei(&nd
)))
4470 VATTR_SET(&va
, va_data_size
, uap
->length
);
4473 error
= mac_vnode_check_truncate(ctx
, NOCRED
, vp
);
4478 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
4480 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
4482 error
= vnode_setattr(vp
, &va
, ctx
);
4489 * Truncate a file given a file descriptor.
4493 ftruncate(proc_t p
, struct ftruncate_args
*uap
, register_t
*retval
)
4495 vfs_context_t ctx
= vfs_context_current();
4496 struct vnode_attr va
;
4498 struct fileproc
*fp
;
4502 AUDIT_ARG(fd
, uap
->fd
);
4503 if (uap
->length
< 0)
4506 if ( (error
= fp_lookup(p
,fd
,&fp
,0)) ) {
4510 if (fp
->f_fglob
->fg_type
== DTYPE_PSXSHM
) {
4511 error
= pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
);
4514 if (fp
->f_fglob
->fg_type
!= DTYPE_VNODE
) {
4519 vp
= (vnode_t
)fp
->f_fglob
->fg_data
;
4521 if ((fp
->f_fglob
->fg_flag
& FWRITE
) == 0) {
4522 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4527 if ((error
= vnode_getwithref(vp
)) != 0) {
4531 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4534 error
= mac_vnode_check_truncate(ctx
,
4535 fp
->f_fglob
->fg_cred
, vp
);
4537 (void)vnode_put(vp
);
4542 VATTR_SET(&va
, va_data_size
, uap
->length
);
4543 error
= vnode_setattr(vp
, &va
, ctx
);
4544 (void)vnode_put(vp
);
4552 * Sync an open file.
4556 fsync(proc_t p
, struct fsync_args
*uap
, register_t
*retval
)
4558 __pthread_testcancel(1);
4559 return(fsync_nocancel(p
, (struct fsync_nocancel_args
*)uap
, retval
));
4563 fsync_nocancel(proc_t p
, struct fsync_nocancel_args
*uap
, __unused register_t
*retval
)
4566 struct fileproc
*fp
;
4567 vfs_context_t ctx
= vfs_context_current();
4570 if ( (error
= fp_getfvp(p
, uap
->fd
, &fp
, &vp
)) )
4572 if ( (error
= vnode_getwithref(vp
)) ) {
4577 error
= VNOP_FSYNC(vp
, MNT_WAIT
, ctx
);
4580 /* Sync resource fork shadow file if necessary. */
4582 (vp
->v_flag
& VISNAMEDSTREAM
) &&
4583 (vp
->v_parent
!= NULLVP
) &&
4584 !(vp
->v_parent
->v_mount
->mnt_kern_flag
& MNTK_NAMED_STREAMS
) &&
4585 (fp
->f_flags
& FP_WRITTEN
)) {
4586 (void) vnode_flushnamedstream(vp
->v_parent
, vp
, ctx
);
4590 (void)vnode_put(vp
);
4596 * Duplicate files. Source must be a file, target must be a file or
4599 * XXX Copyfile authorisation checking is woefully inadequate, and will not
4600 * perform inheritance correctly.
4604 copyfile(__unused proc_t p
, struct copyfile_args
*uap
, __unused register_t
*retval
)
4606 vnode_t tvp
, fvp
, tdvp
, sdvp
;
4607 struct nameidata fromnd
, tond
;
4609 vfs_context_t ctx
= vfs_context_current();
4611 /* Check that the flags are valid. */
4613 if (uap
->flags
& ~CPF_MASK
) {
4617 NDINIT(&fromnd
, LOOKUP
, SAVESTART
| AUDITVNPATH1
,
4618 UIO_USERSPACE
, uap
->from
, ctx
);
4619 if ((error
= namei(&fromnd
)))
4623 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
| AUDITVNPATH2
| CN_NBMOUNTLOOK
,
4624 UIO_USERSPACE
, uap
->to
, ctx
);
4625 if ((error
= namei(&tond
))) {
4632 if (!(uap
->flags
& CPF_OVERWRITE
)) {
4637 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
4642 if ((error
= vnode_authorize(tdvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
4648 * If source is the same as the destination (that is the
4649 * same inode number) then there is nothing to do.
4650 * (fixed to have POSIX semantics - CSM 3/2/98)
4655 error
= VNOP_COPYFILE(fvp
, tdvp
, tvp
, &tond
.ni_cnd
, uap
->mode
, uap
->flags
, ctx
);
4657 sdvp
= tond
.ni_startdir
;
4659 * nameidone has to happen before we vnode_put(tdvp)
4660 * since it may need to release the fs_nodelock on the tdvp
4671 if (fromnd
.ni_startdir
)
4672 vnode_put(fromnd
.ni_startdir
);
4682 * Rename files. Source and destination must either both be directories,
4683 * or both not be directories. If target is a directory, it must be empty.
4687 rename(__unused proc_t p
, struct rename_args
*uap
, __unused register_t
*retval
)
4691 struct nameidata fromnd
, tond
;
4692 vfs_context_t ctx
= vfs_context_current();
4697 char *from_name
= NULL
, *to_name
= NULL
;
4698 int from_len
, to_len
;
4699 int holding_mntlock
;
4700 mount_t locked_mp
= NULL
;
4702 fse_info from_finfo
, to_finfo
;
4704 holding_mntlock
= 0;
4710 NDINIT(&fromnd
, DELETE
, WANTPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->from
, ctx
);
4712 if ( (error
= namei(&fromnd
)) )
4714 fdvp
= fromnd
.ni_dvp
;
4718 error
= mac_vnode_check_rename_from(ctx
, fdvp
, fvp
, &fromnd
.ni_cnd
);
4723 NDINIT(&tond
, RENAME
, WANTPARENT
| AUDITVNPATH2
| CN_NBMOUNTLOOK
, UIO_USERSPACE
, uap
->to
, ctx
);
4724 if (fvp
->v_type
== VDIR
)
4725 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
4727 if ( (error
= namei(&tond
)) ) {
4729 * Translate error code for rename("dir1", "dir2/.").
4731 if (error
== EISDIR
&& fvp
->v_type
== VDIR
)
4739 error
= mac_vnode_check_rename_to(ctx
,
4740 tdvp
, tvp
, fdvp
== tdvp
, &tond
.ni_cnd
);
4746 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
4749 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
4759 * If the source and destination are the same (i.e. they're
4760 * links to the same vnode) and the target file system is
4761 * case sensitive, then there is nothing to do.
4767 * Note: if _PC_CASE_SENSITIVE selector isn't supported,
4768 * then assume that this file system is case sensitive.
4770 if (VNOP_PATHCONF(fvp
, _PC_CASE_SENSITIVE
, &pathconf_val
, ctx
) != 0 ||
4771 pathconf_val
!= 0) {
4779 * If tvp is a directory and not the same as fdvp, or tdvp is not
4780 * the same as fdvp, the node is moving between directories and we
4781 * need rights to remove from the old and add to the new.
4783 * If tvp already exists and is not a directory, we need to be
4784 * allowed to delete it.
4786 * Note that we do not inherit when renaming.
4788 * XXX This needs to be revisited to implement the deferred-inherit bit
4794 if ((tvp
!= NULL
) && vnode_isdir(tvp
)) {
4797 } else if (tdvp
!= fdvp
) {
4801 * must have delete rights to remove the old name even in
4802 * the simple case of fdvp == tdvp.
4804 * If fvp is a directory, and we are changing it's parent,
4805 * then we also need rights to rewrite its ".." entry as well.
4807 if (vnode_isdir(fvp
)) {
4808 if ((error
= vnode_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
| KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
)) != 0)
4811 if ((error
= vnode_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
, ctx
)) != 0)
4815 /* moving into tdvp or tvp, must have rights to add */
4816 if ((error
= vnode_authorize(((tvp
!= NULL
) && vnode_isdir(tvp
)) ? tvp
: tdvp
,
4818 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
4822 /* node staying in same directory, must be allowed to add new name */
4823 if ((error
= vnode_authorize(fdvp
, NULL
,
4824 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
4827 /* overwriting tvp */
4828 if ((tvp
!= NULL
) && !vnode_isdir(tvp
) &&
4829 ((error
= vnode_authorize(tvp
, tdvp
, KAUTH_VNODE_DELETE
, ctx
)) != 0))
4832 /* XXX more checks? */
4835 /* authorization denied */
4840 * Allow the renaming of mount points.
4841 * - target must not exist
4842 * - target must reside in the same directory as source
4843 * - union mounts cannot be renamed
4844 * - "/" cannot be renamed
4846 if ((fvp
->v_flag
& VROOT
) &&
4847 (fvp
->v_type
== VDIR
) &&
4849 (fvp
->v_mountedhere
== NULL
) &&
4851 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
4852 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
4855 /* switch fvp to the covered vnode */
4856 coveredvp
= fvp
->v_mount
->mnt_vnodecovered
;
4857 if ( (vnode_getwithref(coveredvp
)) ) {
4867 * Check for cross-device rename.
4869 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
4870 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
4875 * Avoid renaming "." and "..".
4877 if (fvp
->v_type
== VDIR
&&
4879 (fromnd
.ni_cnd
.cn_namelen
== 1 && fromnd
.ni_cnd
.cn_nameptr
[0] == '.') ||
4880 ((fromnd
.ni_cnd
.cn_flags
| tond
.ni_cnd
.cn_flags
) & ISDOTDOT
)) ) {
4885 * The following edge case is caught here:
4886 * (to cannot be a descendent of from)
4899 if (tdvp
->v_parent
== fvp
) {
4905 * If source is the same as the destination (that is the
4906 * same inode number) then there is nothing to do...
4907 * EXCEPT if the underlying file system supports case
4908 * insensitivity and is case preserving. In this case
4909 * the file system needs to handle the special case of
4910 * getting the same vnode as target (fvp) and source (tvp).
4912 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
4913 * and _PC_CASE_PRESERVING can have this exception, and they need to
4914 * handle the special case of getting the same vnode as target and
4915 * source. NOTE: Then the target is unlocked going into vnop_rename,
4916 * so not to cause locking problems. There is a single reference on tvp.
4918 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
4919 * that correct behaviour then is just to remove the source (link)
4921 if (fvp
== tvp
&& fdvp
== tdvp
) {
4922 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
4923 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
4924 fromnd
.ni_cnd
.cn_namelen
)) {
4929 if (holding_mntlock
&& fvp
->v_mount
!= locked_mp
) {
4931 * we're holding a reference and lock
4932 * on locked_mp, but it no longer matches
4933 * what we want to do... so drop our hold
4935 mount_unlock_renames(locked_mp
);
4936 mount_drop(locked_mp
, 0);
4937 holding_mntlock
= 0;
4939 if (tdvp
!= fdvp
&& fvp
->v_type
== VDIR
) {
4941 * serialize renames that re-shape
4942 * the tree... if holding_mntlock is
4943 * set, then we're ready to go...
4945 * first need to drop the iocounts
4946 * we picked up, second take the
4947 * lock to serialize the access,
4948 * then finally start the lookup
4949 * process over with the lock held
4951 if (!holding_mntlock
) {
4953 * need to grab a reference on
4954 * the mount point before we
4955 * drop all the iocounts... once
4956 * the iocounts are gone, the mount
4959 locked_mp
= fvp
->v_mount
;
4960 mount_ref(locked_mp
, 0);
4963 * nameidone has to happen before we vnode_put(tvp)
4964 * since it may need to release the fs_nodelock on the tvp
4973 * nameidone has to happen before we vnode_put(fdvp)
4974 * since it may need to release the fs_nodelock on the fvp
4981 mount_lock_renames(locked_mp
);
4982 holding_mntlock
= 1;
4988 * when we dropped the iocounts to take
4989 * the lock, we allowed the identity of
4990 * the various vnodes to change... if they did,
4991 * we may no longer be dealing with a rename
4992 * that reshapes the tree... once we're holding
4993 * the iocounts, the vnodes can't change type
4994 * so we're free to drop the lock at this point
4997 if (holding_mntlock
) {
4998 mount_unlock_renames(locked_mp
);
4999 mount_drop(locked_mp
, 0);
5000 holding_mntlock
= 0;
5003 // save these off so we can later verify that fvp is the same
5004 oname
= fvp
->v_name
;
5005 oparent
= fvp
->v_parent
;
5008 need_event
= need_fsevent(FSE_RENAME
, fvp
);
5010 get_fse_info(fvp
, &from_finfo
, ctx
);
5013 get_fse_info(tvp
, &to_finfo
, ctx
);
5018 #endif /* CONFIG_FSE */
5020 if (need_event
|| kauth_authorize_fileop_has_listeners()) {
5021 GET_PATH(from_name
);
5022 if (from_name
== NULL
) {
5026 from_len
= MAXPATHLEN
;
5027 vn_getpath(fdvp
, from_name
, &from_len
);
5028 if ((from_len
+ 1 + fromnd
.ni_cnd
.cn_namelen
+ 1) < MAXPATHLEN
) {
5030 from_name
[from_len
-1] = '/';
5034 strlcpy(&from_name
[from_len
], fromnd
.ni_cnd
.cn_nameptr
, MAXPATHLEN
-from_len
);
5035 from_len
+= fromnd
.ni_cnd
.cn_namelen
+ 1;
5036 from_name
[from_len
] = '\0';
5040 if (to_name
== NULL
) {
5045 to_len
= MAXPATHLEN
;
5046 vn_getpath(tdvp
, to_name
, &to_len
);
5047 // if the path is not just "/", then append a "/"
5048 if ((to_len
+ 1 + tond
.ni_cnd
.cn_namelen
+ 1) < MAXPATHLEN
) {
5050 to_name
[to_len
-1] = '/';
5054 strlcpy(&to_name
[to_len
], tond
.ni_cnd
.cn_nameptr
, MAXPATHLEN
-to_len
);
5055 to_len
+= tond
.ni_cnd
.cn_namelen
+ 1;
5056 to_name
[to_len
] = '\0';
5060 error
= VNOP_RENAME(fdvp
, fvp
, &fromnd
.ni_cnd
,
5061 tdvp
, tvp
, &tond
.ni_cnd
,
5064 if (holding_mntlock
) {
5066 * we can drop our serialization
5069 mount_unlock_renames(locked_mp
);
5070 mount_drop(locked_mp
, 0);
5071 holding_mntlock
= 0;
5078 /* call out to allow 3rd party notification of rename.
5079 * Ignore result of kauth_authorize_fileop call.
5081 kauth_authorize_fileop(vfs_context_ucred(ctx
),
5082 KAUTH_FILEOP_RENAME
,
5083 (uintptr_t)from_name
, (uintptr_t)to_name
);
5086 if (from_name
!= NULL
&& to_name
!= NULL
) {
5088 add_fsevent(FSE_RENAME
, ctx
,
5089 FSE_ARG_STRING
, from_len
, from_name
,
5090 FSE_ARG_FINFO
, &from_finfo
,
5091 FSE_ARG_STRING
, to_len
, to_name
,
5092 FSE_ARG_FINFO
, &to_finfo
,
5095 add_fsevent(FSE_RENAME
, ctx
,
5096 FSE_ARG_STRING
, from_len
, from_name
,
5097 FSE_ARG_FINFO
, &from_finfo
,
5098 FSE_ARG_STRING
, to_len
, to_name
,
5102 #endif /* CONFIG_FSE */
5105 * update filesystem's mount point data
5108 char *cp
, *pathend
, *mpname
;
5114 mp
= fvp
->v_mountedhere
;
5116 if (vfs_busy(mp
, LK_NOWAIT
)) {
5120 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
5122 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
5124 /* find current mount point prefix */
5125 pathend
= &mp
->mnt_vfsstat
.f_mntonname
[0];
5126 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
5130 /* find last component of target name */
5131 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
5135 /* append name to prefix */
5136 maxlen
= MAXPATHLEN
- (pathend
- mp
->mnt_vfsstat
.f_mntonname
);
5137 bzero(pathend
, maxlen
);
5138 strlcpy(pathend
, mpname
, maxlen
);
5140 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
5145 * fix up name & parent pointers. note that we first
5146 * check that fvp has the same name/parent pointers it
5147 * had before the rename call... this is a 'weak' check
5150 if (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
) {
5153 update_flags
= VNODE_UPDATE_NAME
;
5156 update_flags
|= VNODE_UPDATE_PARENT
;
5158 vnode_update_identity(fvp
, tdvp
, tond
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_namelen
, tond
.ni_cnd
.cn_hash
, update_flags
);
5161 if (to_name
!= NULL
)
5162 RELEASE_PATH(to_name
);
5163 if (from_name
!= NULL
)
5164 RELEASE_PATH(from_name
);
5166 if (holding_mntlock
) {
5167 mount_unlock_renames(locked_mp
);
5168 mount_drop(locked_mp
, 0);
5172 * nameidone has to happen before we vnode_put(tdvp)
5173 * since it may need to release the fs_nodelock on the tdvp
5183 * nameidone has to happen before we vnode_put(fdvp)
5184 * since it may need to release the fs_nodelock on the fdvp
5196 * Make a directory file.
5198 * Returns: 0 Success
5201 * vnode_authorize:???
5206 mkdir1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
5210 int update_flags
= 0;
5211 struct nameidata nd
;
5213 AUDIT_ARG(mode
, vap
->va_mode
);
5214 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
5215 UIO_USERSPACE
, path
, ctx
);
5216 nd
.ni_cnd
.cn_flags
|= WILLBEDIR
;
5228 VATTR_SET(vap
, va_type
, VDIR
);
5231 error
= mac_vnode_check_create(ctx
,
5232 nd
.ni_dvp
, &nd
.ni_cnd
, vap
);
5237 /* authorize addition of a directory to the parent */
5238 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
)) != 0)
5242 /* make the directory */
5243 if ((error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
)) != 0)
5246 // Make sure the name & parent pointers are hooked up
5247 if (vp
->v_name
== NULL
)
5248 update_flags
|= VNODE_UPDATE_NAME
;
5249 if (vp
->v_parent
== NULLVP
)
5250 update_flags
|= VNODE_UPDATE_PARENT
;
5253 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
5256 add_fsevent(FSE_CREATE_DIR
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
5261 * nameidone has to happen before we vnode_put(dvp)
5262 * since it may need to release the fs_nodelock on the dvp
5275 mkdir_extended(proc_t p
, struct mkdir_extended_args
*uap
, __unused register_t
*retval
)
5278 kauth_filesec_t xsecdst
;
5279 struct vnode_attr va
;
5282 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
5283 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
5287 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
5288 if (xsecdst
!= NULL
)
5289 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
5291 ciferror
= mkdir1(vfs_context_current(), uap
->path
, &va
);
5292 if (xsecdst
!= NULL
)
5293 kauth_filesec_free(xsecdst
);
5298 mkdir(proc_t p
, struct mkdir_args
*uap
, __unused register_t
*retval
)
5300 struct vnode_attr va
;
5303 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
5305 return(mkdir1(vfs_context_current(), uap
->path
, &va
));
5309 * Remove a directory file.
5313 rmdir(__unused proc_t p
, struct rmdir_args
*uap
, __unused register_t
*retval
)
5317 struct nameidata nd
;
5318 vfs_context_t ctx
= vfs_context_current();
5320 int restart_flag
, oldvp_id
= -1;
5323 * This loop exists to restart rmdir in the unlikely case that two
5324 * processes are simultaneously trying to remove the same directory
5325 * containing orphaned appleDouble files.
5330 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
5331 UIO_USERSPACE
, uap
->path
, ctx
);
5341 * If being restarted check if the new vp
5342 * still has the same v_id.
5344 if (oldvp_id
!= -1 && oldvp_id
!= vp
->v_id
) {
5349 if (vp
->v_type
!= VDIR
) {
5351 * rmdir only deals with directories
5354 } else if (dvp
== vp
) {
5356 * No rmdir "." please.
5359 } else if (vp
->v_flag
& VROOT
) {
5361 * The root of a mounted filesystem cannot be deleted.
5366 error
= mac_vnode_check_unlink(ctx
, dvp
,
5370 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, ctx
);
5376 int has_listeners
= 0;
5380 need_event
= need_fsevent(FSE_DELETE
, dvp
);
5382 get_fse_info(vp
, &finfo
, ctx
);
5385 has_listeners
= kauth_authorize_fileop_has_listeners();
5386 if (need_event
|| has_listeners
) {
5393 vn_getpath(vp
, path
, &len
);
5396 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, ctx
);
5399 * Special case to remove orphaned AppleDouble
5400 * files. I don't like putting this in the kernel,
5401 * but carbon does not like putting this in carbon either,
5404 if (error
== ENOTEMPTY
) {
5405 error
= rmdir_remove_orphaned_appleDouble(vp
, ctx
, &restart_flag
);
5406 if (error
== EBUSY
) {
5407 oldvp_id
= vp
->v_id
;
5413 * Assuming everything went well, we will try the RMDIR again
5416 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, ctx
);
5420 * Call out to allow 3rd party notification of delete.
5421 * Ignore result of kauth_authorize_fileop call.
5424 if (has_listeners
) {
5425 kauth_authorize_fileop(vfs_context_ucred(ctx
),
5426 KAUTH_FILEOP_DELETE
,
5431 if (vp
->v_flag
& VISHARDLINK
) {
5432 // see the comment in unlink1() about why we update
5433 // the parent of a hard link when it is removed
5434 vnode_update_identity(vp
, NULL
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
5439 add_fsevent(FSE_DELETE
, ctx
,
5440 FSE_ARG_STRING
, len
, path
,
5441 FSE_ARG_FINFO
, &finfo
,
5452 * nameidone has to happen before we vnode_put(dvp)
5453 * since it may need to release the fs_nodelock on the dvp
5460 if (restart_flag
== 0) {
5461 wakeup_one((caddr_t
)vp
);
5464 tsleep(vp
, PVFS
, "rm AD", 1);
5466 } while (restart_flag
!= 0);
5472 /* Get direntry length padded to 8 byte alignment */
5473 #define DIRENT64_LEN(namlen) \
5474 ((sizeof(struct direntry) + (namlen) - (MAXPATHLEN-1) + 7) & ~7)
5477 vnode_readdir64(struct vnode
*vp
, struct uio
*uio
, int flags
, int *eofflag
,
5478 int *numdirent
, vfs_context_t ctxp
)
5480 /* Check if fs natively supports VNODE_READDIR_EXTENDED */
5481 if (vp
->v_mount
->mnt_vtable
->vfc_vfsflags
& VFC_VFSREADDIR_EXTENDED
) {
5482 return VNOP_READDIR(vp
, uio
, flags
, eofflag
, numdirent
, ctxp
);
5487 struct direntry entry64
;
5493 * Our kernel buffer needs to be smaller since re-packing
5494 * will expand each dirent. The worse case (when the name
5495 * length is 3) corresponds to a struct direntry size of 32
5496 * bytes (8-byte aligned) and a struct dirent size of 12 bytes
5497 * (4-byte aligned). So having a buffer that is 3/8 the size
5498 * will prevent us from reading more than we can pack.
5500 * Since this buffer is wired memory, we will limit the
5501 * buffer size to a maximum of 32K. We would really like to
5502 * use 32K in the MIN(), but we use magic number 87371 to
5503 * prevent uio_resid() * 3 / 8 from overflowing.
5505 bufsize
= 3 * MIN(uio_resid(uio
), 87371) / 8;
5506 MALLOC(bufptr
, void *, bufsize
, M_TEMP
, M_WAITOK
);
5508 auio
= uio_create(1, 0, UIO_SYSSPACE32
, UIO_READ
);
5509 uio_addiov(auio
, (uintptr_t)bufptr
, bufsize
);
5510 auio
->uio_offset
= uio
->uio_offset
;
5512 error
= VNOP_READDIR(vp
, auio
, 0, eofflag
, numdirent
, ctxp
);
5514 dep
= (struct dirent
*)bufptr
;
5515 bytesread
= bufsize
- uio_resid(auio
);
5518 * Convert all the entries and copy them out to user's buffer.
5520 while (error
== 0 && (char *)dep
< ((char *)bufptr
+ bytesread
)) {
5521 /* Convert a dirent to a dirent64. */
5522 entry64
.d_ino
= dep
->d_ino
;
5523 entry64
.d_seekoff
= 0;
5524 entry64
.d_reclen
= DIRENT64_LEN(dep
->d_namlen
);
5525 entry64
.d_namlen
= dep
->d_namlen
;
5526 entry64
.d_type
= dep
->d_type
;
5527 bcopy(dep
->d_name
, entry64
.d_name
, dep
->d_namlen
+ 1);
5529 /* Move to next entry. */
5530 dep
= (struct dirent
*)((char *)dep
+ dep
->d_reclen
);
5532 /* Copy entry64 to user's buffer. */
5533 error
= uiomove((caddr_t
)&entry64
, entry64
.d_reclen
, uio
);
5536 /* Update the real offset using the offset we got from VNOP_READDIR. */
5538 uio
->uio_offset
= auio
->uio_offset
;
5541 FREE(bufptr
, M_TEMP
);
5547 * Read a block of directory entries in a file system independent format.
5550 getdirentries_common(int fd
, user_addr_t bufp
, user_size_t bufsize
, ssize_t
*bytesread
,
5551 off_t
*offset
, int flags
)
5554 struct vfs_context context
= *vfs_context_current(); /* local copy */
5555 struct fileproc
*fp
;
5557 int spacetype
= proc_is64bit(vfs_context_proc(&context
)) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5559 int error
, eofflag
, numdirent
;
5560 char uio_buf
[ UIO_SIZEOF(1) ];
5562 error
= fp_getfvp(vfs_context_proc(&context
), fd
, &fp
, &vp
);
5566 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
5567 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
5573 error
= mac_file_check_change_offset(vfs_context_ucred(&context
), fp
->f_fglob
);
5577 if ( (error
= vnode_getwithref(vp
)) ) {
5580 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
5583 if (vp
->v_type
!= VDIR
) {
5584 (void)vnode_put(vp
);
5590 error
= mac_vnode_check_readdir(&context
, vp
);
5592 (void)vnode_put(vp
);
5597 loff
= fp
->f_fglob
->fg_offset
;
5598 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
5599 uio_addiov(auio
, bufp
, bufsize
);
5601 if (flags
& VNODE_READDIR_EXTENDED
) {
5602 error
= vnode_readdir64(vp
, auio
, flags
, &eofflag
, &numdirent
, &context
);
5603 fp
->f_fglob
->fg_offset
= uio_offset(auio
);
5605 error
= VNOP_READDIR(vp
, auio
, 0, &eofflag
, &numdirent
, &context
);
5606 fp
->f_fglob
->fg_offset
= uio_offset(auio
);
5609 (void)vnode_put(vp
);
5613 if ((user_ssize_t
)bufsize
== uio_resid(auio
)){
5614 if (union_dircheckp
) {
5615 error
= union_dircheckp(&vp
, fp
, &context
);
5622 if ((vp
->v_flag
& VROOT
) && (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
5623 struct vnode
*tvp
= vp
;
5624 vp
= vp
->v_mount
->mnt_vnodecovered
;
5625 vnode_getwithref(vp
);
5627 fp
->f_fglob
->fg_data
= (caddr_t
) vp
;
5628 fp
->f_fglob
->fg_offset
= 0;
5639 // LP64todo - fix this
5640 *bytesread
= bufsize
- uio_resid(auio
);
5648 getdirentries(__unused
struct proc
*p
, struct getdirentries_args
*uap
, register_t
*retval
)
5655 AUDIT_ARG(fd
, uap
->fd
);
5656 error
= getdirentries_common(uap
->fd
, uap
->buf
, uap
->count
, &bytesread
, &offset
, 0);
5659 loff
= (long)offset
;
5660 error
= copyout((caddr_t
)&loff
, uap
->basep
, sizeof(long));
5661 *retval
= bytesread
;
5667 getdirentries64(__unused
struct proc
*p
, struct getdirentries64_args
*uap
, user_ssize_t
*retval
)
5673 AUDIT_ARG(fd
, uap
->fd
);
5674 error
= getdirentries_common(uap
->fd
, uap
->buf
, uap
->bufsize
, &bytesread
, &offset
, VNODE_READDIR_EXTENDED
);
5677 *retval
= bytesread
;
5678 error
= copyout((caddr_t
)&offset
, uap
->position
, sizeof(off_t
));
5685 * Set the mode mask for creation of filesystem nodes.
5687 #warning XXX implement xsecurity
5689 #define UMASK_NOXSECURITY (void *)1 /* leave existing xsecurity alone */
5691 umask1(proc_t p
, int newmask
, __unused kauth_filesec_t fsec
, register_t
*retval
)
5693 struct filedesc
*fdp
;
5695 AUDIT_ARG(mask
, newmask
);
5698 *retval
= fdp
->fd_cmask
;
5699 fdp
->fd_cmask
= newmask
& ALLPERMS
;
5706 umask_extended(proc_t p
, struct umask_extended_args
*uap
, register_t
*retval
)
5709 kauth_filesec_t xsecdst
;
5711 xsecdst
= KAUTH_FILESEC_NONE
;
5712 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
5713 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
5716 xsecdst
= KAUTH_FILESEC_NONE
;
5719 ciferror
= umask1(p
, uap
->newmask
, xsecdst
, retval
);
5721 if (xsecdst
!= KAUTH_FILESEC_NONE
)
5722 kauth_filesec_free(xsecdst
);
5727 umask(proc_t p
, struct umask_args
*uap
, register_t
*retval
)
5729 return(umask1(p
, uap
->newmask
, UMASK_NOXSECURITY
, retval
));
5733 * Void all references to file by ripping underlying filesystem
5738 revoke(proc_t p
, struct revoke_args
*uap
, __unused register_t
*retval
)
5741 struct vnode_attr va
;
5742 vfs_context_t ctx
= vfs_context_current();
5744 struct nameidata nd
;
5746 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
5747 UIO_USERSPACE
, uap
->path
, ctx
);
5756 error
= mac_vnode_check_revoke(ctx
, vp
);
5762 VATTR_WANTED(&va
, va_uid
);
5763 if ((error
= vnode_getattr(vp
, &va
, ctx
)))
5765 if (kauth_cred_getuid(vfs_context_ucred(ctx
)) != va
.va_uid
&&
5766 (error
= suser(vfs_context_ucred(ctx
), &p
->p_acflag
)))
5768 if (vp
->v_usecount
> 1 || (vp
->v_flag
& VALIASED
))
5769 VNOP_REVOKE(vp
, REVOKEALL
, ctx
);
5777 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
5778 * The following system calls are designed to support features
5779 * which are specific to the HFS & HFS Plus volume formats
5782 #ifdef __APPLE_API_OBSOLETE
5784 /************************************************/
5785 /* *** Following calls will be deleted soon *** */
5786 /************************************************/
5789 * Make a complex file. A complex file is one with multiple forks (data streams)
5793 mkcomplex(__unused proc_t p
, __unused
struct mkcomplex_args
*uap
, __unused register_t
*retval
)
5799 * Extended stat call which returns volumeid and vnodeid as well as other info
5803 statv(__unused proc_t p
,
5804 __unused
struct statv_args
*uap
,
5805 __unused register_t
*retval
)
5807 return (ENOTSUP
); /* We'll just return an error for now */
5809 } /* end of statv system call */
5812 * Extended lstat call which returns volumeid and vnodeid as well as other info
5816 lstatv(__unused proc_t p
,
5817 __unused
struct lstatv_args
*uap
,
5818 __unused register_t
*retval
)
5820 return (ENOTSUP
); /* We'll just return an error for now */
5821 } /* end of lstatv system call */
5824 * Extended fstat call which returns volumeid and vnodeid as well as other info
5828 fstatv(__unused proc_t p
,
5829 __unused
struct fstatv_args
*uap
,
5830 __unused register_t
*retval
)
5832 return (ENOTSUP
); /* We'll just return an error for now */
5833 } /* end of fstatv system call */
5836 /************************************************/
5837 /* *** Preceding calls will be deleted soon *** */
5838 /************************************************/
5840 #endif /* __APPLE_API_OBSOLETE */
5843 * Obtain attribute information on objects in a directory while enumerating
5844 * the directory. This call does not yet support union mounted directories.
5846 * 1.union mounted directories.
5851 getdirentriesattr (proc_t p
, struct getdirentriesattr_args
*uap
, register_t
*retval
)
5854 struct fileproc
*fp
;
5856 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5861 struct attrlist attributelist
;
5862 vfs_context_t ctx
= vfs_context_current();
5864 char uio_buf
[ UIO_SIZEOF(1) ];
5865 kauth_action_t action
;
5869 /* Get the attributes into kernel space */
5870 if ((error
= copyin(uap
->alist
, (caddr_t
)&attributelist
, sizeof(attributelist
)))) {
5873 if ((error
= copyin(uap
->count
, (caddr_t
)&count
, sizeof(count
)))) {
5876 if ( (error
= fp_getfvp(p
, fd
, &fp
, &vp
)) ) {
5879 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
5880 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
5887 error
= mac_file_check_change_offset(vfs_context_ucred(ctx
),
5894 if ( (error
= vnode_getwithref(vp
)) )
5897 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
5899 if (vp
->v_type
!= VDIR
) {
5900 (void)vnode_put(vp
);
5906 error
= mac_vnode_check_readdir(ctx
, vp
);
5908 (void)vnode_put(vp
);
5913 /* set up the uio structure which will contain the users return buffer */
5914 loff
= fp
->f_fglob
->fg_offset
;
5915 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
5916 &uio_buf
[0], sizeof(uio_buf
));
5917 uio_addiov(auio
, uap
->buffer
, uap
->buffersize
);
5920 * If the only item requested is file names, we can let that past with
5921 * just LIST_DIRECTORY. If they want any other attributes, that means
5922 * they need SEARCH as well.
5924 action
= KAUTH_VNODE_LIST_DIRECTORY
;
5925 if ((attributelist
.commonattr
& ~ATTR_CMN_NAME
) ||
5926 attributelist
.fileattr
|| attributelist
.dirattr
)
5927 action
|= KAUTH_VNODE_SEARCH
;
5929 if ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) == 0) {
5930 u_long ulcount
= count
;
5932 error
= VNOP_READDIRATTR(vp
, &attributelist
, auio
,
5934 uap
->options
, (unsigned long *)&newstate
, &eofflag
,
5939 (void)vnode_put(vp
);
5943 fp
->f_fglob
->fg_offset
= uio_offset(auio
); /* should be multiple of dirent, not variable */
5945 if ((error
= copyout((caddr_t
) &count
, uap
->count
, sizeof(count
))))
5947 if ((error
= copyout((caddr_t
) &newstate
, uap
->newstate
, sizeof(newstate
))))
5949 if ((error
= copyout((caddr_t
) &loff
, uap
->basep
, sizeof(loff
))))
5952 *retval
= eofflag
; /* similar to getdirentries */
5956 return (error
); /* return error earlier, an retval of 0 or 1 now */
5958 } /* end of getdirentryattr system call */
5961 * Exchange data between two files
5966 exchangedata (__unused proc_t p
, struct exchangedata_args
*uap
, __unused register_t
*retval
)
5969 struct nameidata fnd
, snd
;
5970 vfs_context_t ctx
= vfs_context_current();
5978 fse_info f_finfo
, s_finfo
;
5981 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
5983 NDINIT(&fnd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
5984 UIO_USERSPACE
, uap
->path1
, ctx
);
5986 error
= namei(&fnd
);
5993 NDINIT(&snd
, LOOKUP
| CN_NBMOUNTLOOK
, nameiflags
| AUDITVNPATH2
,
5994 UIO_USERSPACE
, uap
->path2
, ctx
);
5996 error
= namei(&snd
);
6005 * if the files are the same, return an inval error
6013 * if the files are on different volumes, return an error
6015 if (svp
->v_mount
!= fvp
->v_mount
) {
6021 error
= mac_vnode_check_exchangedata(ctx
,
6026 if (((error
= vnode_authorize(fvp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, ctx
)) != 0) ||
6027 ((error
= vnode_authorize(svp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, ctx
)) != 0))
6032 need_fsevent(FSE_EXCHANGE
, fvp
) ||
6034 kauth_authorize_fileop_has_listeners()) {
6037 if (fpath
== NULL
|| spath
== NULL
) {
6043 if (vn_getpath(fvp
, fpath
, &flen
) != 0 || fpath
[0] == '\0') {
6044 printf("exchange: vn_getpath(fvp=%p) failed <<%s>>\n",
6047 if (vn_getpath(svp
, spath
, &slen
) != 0 || spath
[0] == '\0') {
6048 printf("exchange: vn_getpath(svp=%p) failed <<%s>>\n",
6052 get_fse_info(fvp
, &f_finfo
, ctx
);
6053 get_fse_info(svp
, &s_finfo
, ctx
);
6056 /* Ok, make the call */
6057 error
= VNOP_EXCHANGE(fvp
, svp
, 0, ctx
);
6060 const char *tmpname
;
6062 if (fpath
!= NULL
&& spath
!= NULL
) {
6063 /* call out to allow 3rd party notification of exchangedata.
6064 * Ignore result of kauth_authorize_fileop call.
6066 kauth_authorize_fileop(vfs_context_ucred(ctx
), KAUTH_FILEOP_EXCHANGE
,
6067 (uintptr_t)fpath
, (uintptr_t)spath
);
6071 tmpname
= fvp
->v_name
;
6072 fvp
->v_name
= svp
->v_name
;
6073 svp
->v_name
= tmpname
;
6075 if (fvp
->v_parent
!= svp
->v_parent
) {
6078 tmp
= fvp
->v_parent
;
6079 fvp
->v_parent
= svp
->v_parent
;
6080 svp
->v_parent
= tmp
;
6082 name_cache_unlock();
6085 if (fpath
!= NULL
&& spath
!= NULL
) {
6086 add_fsevent(FSE_EXCHANGE
, ctx
,
6087 FSE_ARG_STRING
, flen
, fpath
,
6088 FSE_ARG_FINFO
, &f_finfo
,
6089 FSE_ARG_STRING
, slen
, spath
,
6090 FSE_ARG_FINFO
, &s_finfo
,
6098 RELEASE_PATH(fpath
);
6100 RELEASE_PATH(spath
);
6111 searchfs(proc_t p
, struct searchfs_args
*uap
, __unused register_t
*retval
)
6116 struct nameidata nd
;
6117 struct user_fssearchblock searchblock
;
6118 struct searchstate
*state
;
6119 struct attrlist
*returnattrs
;
6120 void *searchparams1
,*searchparams2
;
6122 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6126 vfs_context_t ctx
= vfs_context_current();
6127 char uio_buf
[ UIO_SIZEOF(1) ];
6129 /* Start by copying in fsearchblock paramater list */
6130 if (IS_64BIT_PROCESS(p
)) {
6131 error
= copyin(uap
->searchblock
, (caddr_t
) &searchblock
, sizeof(searchblock
));
6134 struct fssearchblock tmp_searchblock
;
6135 error
= copyin(uap
->searchblock
, (caddr_t
) &tmp_searchblock
, sizeof(tmp_searchblock
));
6136 // munge into 64-bit version
6137 searchblock
.returnattrs
= CAST_USER_ADDR_T(tmp_searchblock
.returnattrs
);
6138 searchblock
.returnbuffer
= CAST_USER_ADDR_T(tmp_searchblock
.returnbuffer
);
6139 searchblock
.returnbuffersize
= tmp_searchblock
.returnbuffersize
;
6140 searchblock
.maxmatches
= tmp_searchblock
.maxmatches
;
6141 searchblock
.timelimit
.tv_sec
= tmp_searchblock
.timelimit
.tv_sec
;
6142 searchblock
.timelimit
.tv_usec
= tmp_searchblock
.timelimit
.tv_usec
;
6143 searchblock
.searchparams1
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams1
);
6144 searchblock
.sizeofsearchparams1
= tmp_searchblock
.sizeofsearchparams1
;
6145 searchblock
.searchparams2
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams2
);
6146 searchblock
.sizeofsearchparams2
= tmp_searchblock
.sizeofsearchparams2
;
6147 searchblock
.searchattrs
= tmp_searchblock
.searchattrs
;
6152 /* Do a sanity check on sizeofsearchparams1 and sizeofsearchparams2.
6154 if (searchblock
.sizeofsearchparams1
> SEARCHFS_MAX_SEARCHPARMS
||
6155 searchblock
.sizeofsearchparams2
> SEARCHFS_MAX_SEARCHPARMS
)
6158 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
6159 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
6160 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
6163 mallocsize
= searchblock
.sizeofsearchparams1
+ searchblock
.sizeofsearchparams2
+
6164 sizeof(struct attrlist
) + sizeof(struct searchstate
);
6166 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
6168 /* Now set up the various pointers to the correct place in our newly allocated memory */
6170 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
6171 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
6172 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
6174 /* Now copy in the stuff given our local variables. */
6176 if ((error
= copyin(searchblock
.searchparams1
, searchparams1
, searchblock
.sizeofsearchparams1
)))
6179 if ((error
= copyin(searchblock
.searchparams2
, searchparams2
, searchblock
.sizeofsearchparams2
)))
6182 if ((error
= copyin(searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
))))
6185 if ((error
= copyin(uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
))))
6188 /* set up the uio structure which will contain the users return buffer */
6190 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
6191 &uio_buf
[0], sizeof(uio_buf
));
6192 uio_addiov(auio
, searchblock
.returnbuffer
, searchblock
.returnbuffersize
);
6195 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
6196 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
6197 UIO_USERSPACE
, uap
->path
, ctx
);
6208 * If searchblock.maxmatches == 0, then skip the search. This has happened
6209 * before and sometimes the underlyning code doesnt deal with it well.
6211 if (searchblock
.maxmatches
== 0) {
6217 Allright, we have everything we need, so lets make that call.
6219 We keep special track of the return value from the file system:
6220 EAGAIN is an acceptable error condition that shouldn't keep us
6221 from copying out any results...
6224 fserror
= VNOP_SEARCHFS(vp
,
6227 &searchblock
.searchattrs
,
6228 searchblock
.maxmatches
,
6229 &searchblock
.timelimit
,
6242 /* Now copy out the stuff that needs copying out. That means the number of matches, the
6243 search state. Everything was already put into he return buffer by the vop call. */
6245 if ((error
= copyout((caddr_t
) state
, uap
->state
, sizeof(struct searchstate
))) != 0)
6248 if ((error
= suulong(uap
->nummatches
, (uint64_t)nummatches
)) != 0)
6255 FREE(searchparams1
,M_TEMP
);
6260 } /* end of searchfs system call */
6264 * Make a filesystem-specific control call:
6268 fsctl (proc_t p
, struct fsctl_args
*uap
, __unused register_t
*retval
)
6272 struct nameidata nd
;
6274 u_long cmd
= uap
->cmd
;
6276 #define STK_PARAMS 128
6277 char stkbuf
[STK_PARAMS
];
6279 vfs_context_t ctx
= vfs_context_current();
6281 size
= IOCPARM_LEN(cmd
);
6282 if (size
> IOCPARM_MAX
) return (EINVAL
);
6284 is64bit
= proc_is64bit(p
);
6287 if (size
> sizeof (stkbuf
)) {
6288 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
6296 error
= copyin(uap
->data
, data
, size
);
6297 if (error
) goto FSCtl_Exit
;
6300 *(user_addr_t
*)data
= uap
->data
;
6303 *(uint32_t *)data
= (uint32_t)uap
->data
;
6306 } else if ((cmd
& IOC_OUT
) && size
) {
6308 * Zero the buffer so the user always
6309 * gets back something deterministic.
6312 } else if (cmd
& IOC_VOID
) {
6314 *(user_addr_t
*)data
= uap
->data
;
6317 *(uint32_t *)data
= (uint32_t)uap
->data
;
6321 /* Get the vnode for the file we are getting info on: */
6323 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
6324 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, uap
->path
, ctx
);
6325 if ((error
= namei(&nd
))) goto FSCtl_Exit
;
6328 error
= mac_mount_check_fsctl(ctx
, vnode_mount(nd
.ni_vp
), cmd
);
6330 vnode_put(nd
.ni_vp
);
6336 /* Invoke the filesystem-specific code */
6337 error
= VNOP_IOCTL(nd
.ni_vp
, IOCBASECMD(cmd
), data
, uap
->options
, ctx
);
6339 vnode_put(nd
.ni_vp
);
6343 * Copy any data to user, size was
6344 * already set and checked above.
6346 if (error
== 0 && (cmd
& IOC_OUT
) && size
)
6347 error
= copyout(data
, uap
->data
, size
);
6350 if (memp
) kfree(memp
, size
);
6354 /* end of fsctl system call */
6357 * An in-kernel sync for power management to call.
6359 __private_extern__
int
6364 struct sync_args data
;
6369 error
= sync(current_proc(), &data
, &retval
[0]);
6373 } /* end of sync_internal call */
6377 * Retrieve the data of an extended attribute.
6380 getxattr(proc_t p
, struct getxattr_args
*uap
, user_ssize_t
*retval
)
6383 struct nameidata nd
;
6384 char attrname
[XATTR_MAXNAMELEN
+1];
6385 vfs_context_t ctx
= vfs_context_current();
6387 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6388 size_t attrsize
= 0;
6392 char uio_buf
[ UIO_SIZEOF(1) ];
6394 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6397 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
6398 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, ctx
);
6399 if ((error
= namei(&nd
))) {
6405 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
6408 if (xattr_protected(attrname
)) {
6412 if (uap
->value
&& uap
->size
> 0) {
6413 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
6414 &uio_buf
[0], sizeof(uio_buf
));
6415 uio_addiov(auio
, uap
->value
, uap
->size
);
6418 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, ctx
);
6423 *retval
= uap
->size
- uio_resid(auio
);
6425 *retval
= (user_ssize_t
)attrsize
;
6432 * Retrieve the data of an extended attribute.
6435 fgetxattr(proc_t p
, struct fgetxattr_args
*uap
, user_ssize_t
*retval
)
6438 char attrname
[XATTR_MAXNAMELEN
+1];
6440 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6441 size_t attrsize
= 0;
6444 char uio_buf
[ UIO_SIZEOF(1) ];
6446 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6449 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
6452 if ( (error
= vnode_getwithref(vp
)) ) {
6456 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
6459 if (xattr_protected(attrname
)) {
6463 if (uap
->value
&& uap
->size
> 0) {
6464 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
6465 &uio_buf
[0], sizeof(uio_buf
));
6466 uio_addiov(auio
, uap
->value
, uap
->size
);
6469 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, vfs_context_current());
6471 (void)vnode_put(vp
);
6475 *retval
= uap
->size
- uio_resid(auio
);
6477 *retval
= (user_ssize_t
)attrsize
;
6483 * Set the data of an extended attribute.
6486 setxattr(proc_t p
, struct setxattr_args
*uap
, int *retval
)
6489 struct nameidata nd
;
6490 char attrname
[XATTR_MAXNAMELEN
+1];
6491 vfs_context_t ctx
= vfs_context_current();
6493 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6497 char uio_buf
[ UIO_SIZEOF(1) ];
6499 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6502 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
6505 if (xattr_protected(attrname
))
6507 if (uap
->size
!= 0 && uap
->value
== 0) {
6511 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
6512 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, ctx
);
6513 if ((error
= namei(&nd
))) {
6519 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
6520 &uio_buf
[0], sizeof(uio_buf
));
6521 uio_addiov(auio
, uap
->value
, uap
->size
);
6523 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, ctx
);
6526 add_fsevent(FSE_XATTR_MODIFIED
, ctx
,
6537 * Set the data of an extended attribute.
6540 fsetxattr(proc_t p
, struct fsetxattr_args
*uap
, int *retval
)
6543 char attrname
[XATTR_MAXNAMELEN
+1];
6545 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6548 char uio_buf
[ UIO_SIZEOF(1) ];
6549 vfs_context_t ctx
= vfs_context_current();
6551 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6554 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
6557 if (xattr_protected(attrname
))
6559 if (uap
->size
!= 0 && uap
->value
== 0) {
6562 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
6565 if ( (error
= vnode_getwithref(vp
)) ) {
6569 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
6570 &uio_buf
[0], sizeof(uio_buf
));
6571 uio_addiov(auio
, uap
->value
, uap
->size
);
6573 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, vfs_context_current());
6576 add_fsevent(FSE_XATTR_MODIFIED
, ctx
,
6588 * Remove an extended attribute.
6590 #warning "code duplication"
6592 removexattr(proc_t p
, struct removexattr_args
*uap
, int *retval
)
6595 struct nameidata nd
;
6596 char attrname
[XATTR_MAXNAMELEN
+1];
6597 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6598 vfs_context_t ctx
= vfs_context_current();
6603 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6606 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
6610 if (xattr_protected(attrname
))
6612 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
6613 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, ctx
);
6614 if ((error
= namei(&nd
))) {
6620 error
= vn_removexattr(vp
, attrname
, uap
->options
, ctx
);
6623 add_fsevent(FSE_XATTR_REMOVED
, ctx
,
6634 * Remove an extended attribute.
6636 #warning "code duplication"
6638 fremovexattr(__unused proc_t p
, struct fremovexattr_args
*uap
, int *retval
)
6641 char attrname
[XATTR_MAXNAMELEN
+1];
6644 vfs_context_t ctx
= vfs_context_current();
6646 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6649 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
6653 if (xattr_protected(attrname
))
6655 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
6658 if ( (error
= vnode_getwithref(vp
)) ) {
6663 error
= vn_removexattr(vp
, attrname
, uap
->options
, vfs_context_current());
6666 add_fsevent(FSE_XATTR_REMOVED
, ctx
,
6678 * Retrieve the list of extended attribute names.
6680 #warning "code duplication"
6682 listxattr(proc_t p
, struct listxattr_args
*uap
, user_ssize_t
*retval
)
6685 struct nameidata nd
;
6686 vfs_context_t ctx
= vfs_context_current();
6688 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6689 size_t attrsize
= 0;
6692 char uio_buf
[ UIO_SIZEOF(1) ];
6694 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6697 nameiflags
= ((uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
) | NOTRIGGER
;
6698 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, ctx
);
6699 if ((error
= namei(&nd
))) {
6704 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
6705 // LP64todo - fix this!
6706 auio
= uio_createwithbuffer(1, 0, spacetype
,
6707 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
6708 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
6711 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, ctx
);
6715 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
6717 *retval
= (user_ssize_t
)attrsize
;
6723 * Retrieve the list of extended attribute names.
6725 #warning "code duplication"
6727 flistxattr(proc_t p
, struct flistxattr_args
*uap
, user_ssize_t
*retval
)
6731 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6732 size_t attrsize
= 0;
6734 char uio_buf
[ UIO_SIZEOF(1) ];
6736 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6739 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
6742 if ( (error
= vnode_getwithref(vp
)) ) {
6746 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
6747 // LP64todo - fix this!
6748 auio
= uio_createwithbuffer(1, 0, spacetype
,
6749 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
6750 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
6753 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, vfs_context_current());
6758 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
6760 *retval
= (user_ssize_t
)attrsize
;
6766 * Common routine to handle various flavors of statfs data heading out
6769 * Returns: 0 Success
6773 munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
6774 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
6775 boolean_t partial_copy
)
6778 int my_size
, copy_size
;
6781 struct user_statfs sfs
;
6782 my_size
= copy_size
= sizeof(sfs
);
6783 bzero(&sfs
, my_size
);
6784 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
6785 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
6786 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
6787 sfs
.f_bsize
= (user_long_t
)sfsp
->f_bsize
;
6788 sfs
.f_iosize
= (user_long_t
)sfsp
->f_iosize
;
6789 sfs
.f_blocks
= (user_long_t
)sfsp
->f_blocks
;
6790 sfs
.f_bfree
= (user_long_t
)sfsp
->f_bfree
;
6791 sfs
.f_bavail
= (user_long_t
)sfsp
->f_bavail
;
6792 sfs
.f_files
= (user_long_t
)sfsp
->f_files
;
6793 sfs
.f_ffree
= (user_long_t
)sfsp
->f_ffree
;
6794 sfs
.f_fsid
= sfsp
->f_fsid
;
6795 sfs
.f_owner
= sfsp
->f_owner
;
6796 strlcpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
);
6797 strlcpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
);
6798 strlcpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
);
6801 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
6803 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
6807 my_size
= copy_size
= sizeof(sfs
);
6808 bzero(&sfs
, my_size
);
6810 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
6811 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
6812 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
6815 * It's possible for there to be more than 2^^31 blocks in the filesystem, so we
6816 * have to fudge the numbers here in that case. We inflate the blocksize in order
6817 * to reflect the filesystem size as best we can.
6819 if ((sfsp
->f_blocks
> LONG_MAX
)
6820 /* Hack for 4061702 . I think the real fix is for Carbon to
6821 * look for some volume capability and not depend on hidden
6822 * semantics agreed between a FS and carbon.
6823 * f_blocks, f_bfree, and f_bavail set to -1 is the trigger
6824 * for Carbon to set bNoVolumeSizes volume attribute.
6825 * Without this the webdavfs files cannot be copied onto
6826 * disk as they look huge. This change should not affect
6827 * XSAN as they should not setting these to -1..
6829 && (sfsp
->f_blocks
!= 0xffffffffffffffffULL
)
6830 && (sfsp
->f_bfree
!= 0xffffffffffffffffULL
)
6831 && (sfsp
->f_bavail
!= 0xffffffffffffffffULL
)) {
6835 * Work out how far we have to shift the block count down to make it fit.
6836 * Note that it's possible to have to shift so far that the resulting
6837 * blocksize would be unreportably large. At that point, we will clip
6838 * any values that don't fit.
6840 * For safety's sake, we also ensure that f_iosize is never reported as
6841 * being smaller than f_bsize.
6843 for (shift
= 0; shift
< 32; shift
++) {
6844 if ((sfsp
->f_blocks
>> shift
) <= LONG_MAX
)
6846 if ((sfsp
->f_bsize
<< (shift
+ 1)) > LONG_MAX
)
6849 #define __SHIFT_OR_CLIP(x, s) ((((x) >> (s)) > LONG_MAX) ? LONG_MAX : ((x) >> (s)))
6850 sfs
.f_blocks
= (long)__SHIFT_OR_CLIP(sfsp
->f_blocks
, shift
);
6851 sfs
.f_bfree
= (long)__SHIFT_OR_CLIP(sfsp
->f_bfree
, shift
);
6852 sfs
.f_bavail
= (long)__SHIFT_OR_CLIP(sfsp
->f_bavail
, shift
);
6853 #undef __SHIFT_OR_CLIP
6854 sfs
.f_bsize
= (long)(sfsp
->f_bsize
<< shift
);
6855 sfs
.f_iosize
= lmax(sfsp
->f_iosize
, sfsp
->f_bsize
);
6857 /* filesystem is small enough to be reported honestly */
6858 sfs
.f_bsize
= (long)sfsp
->f_bsize
;
6859 sfs
.f_iosize
= (long)sfsp
->f_iosize
;
6860 sfs
.f_blocks
= (long)sfsp
->f_blocks
;
6861 sfs
.f_bfree
= (long)sfsp
->f_bfree
;
6862 sfs
.f_bavail
= (long)sfsp
->f_bavail
;
6864 sfs
.f_files
= (long)sfsp
->f_files
;
6865 sfs
.f_ffree
= (long)sfsp
->f_ffree
;
6866 sfs
.f_fsid
= sfsp
->f_fsid
;
6867 sfs
.f_owner
= sfsp
->f_owner
;
6868 strlcpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
);
6869 strlcpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
);
6870 strlcpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
);
6873 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
6875 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
6878 if (sizep
!= NULL
) {
6885 * copy stat structure into user_stat structure.
6887 void munge_stat(struct stat
*sbp
, struct user_stat
*usbp
)
6889 bzero(usbp
, sizeof(struct user_stat
));
6891 usbp
->st_dev
= sbp
->st_dev
;
6892 usbp
->st_ino
= sbp
->st_ino
;
6893 usbp
->st_mode
= sbp
->st_mode
;
6894 usbp
->st_nlink
= sbp
->st_nlink
;
6895 usbp
->st_uid
= sbp
->st_uid
;
6896 usbp
->st_gid
= sbp
->st_gid
;
6897 usbp
->st_rdev
= sbp
->st_rdev
;
6898 #ifndef _POSIX_C_SOURCE
6899 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
6900 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
6901 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
6902 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
6903 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
6904 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
6906 usbp
->st_atime
= sbp
->st_atime
;
6907 usbp
->st_atimensec
= sbp
->st_atimensec
;
6908 usbp
->st_mtime
= sbp
->st_mtime
;
6909 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
6910 usbp
->st_ctime
= sbp
->st_ctime
;
6911 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
6913 usbp
->st_size
= sbp
->st_size
;
6914 usbp
->st_blocks
= sbp
->st_blocks
;
6915 usbp
->st_blksize
= sbp
->st_blksize
;
6916 usbp
->st_flags
= sbp
->st_flags
;
6917 usbp
->st_gen
= sbp
->st_gen
;
6918 usbp
->st_lspare
= sbp
->st_lspare
;
6919 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
6920 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];
6924 * copy stat64 structure into user_stat64 structure.
6926 void munge_stat64(struct stat64
*sbp
, struct user_stat64
*usbp
)
6928 bzero(usbp
, sizeof(struct user_stat
));
6930 usbp
->st_dev
= sbp
->st_dev
;
6931 usbp
->st_ino
= sbp
->st_ino
;
6932 usbp
->st_mode
= sbp
->st_mode
;
6933 usbp
->st_nlink
= sbp
->st_nlink
;
6934 usbp
->st_uid
= sbp
->st_uid
;
6935 usbp
->st_gid
= sbp
->st_gid
;
6936 usbp
->st_rdev
= sbp
->st_rdev
;
6937 #ifndef _POSIX_C_SOURCE
6938 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
6939 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
6940 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
6941 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
6942 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
6943 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
6944 usbp
->st_birthtimespec
.tv_sec
= sbp
->st_birthtimespec
.tv_sec
;
6945 usbp
->st_birthtimespec
.tv_nsec
= sbp
->st_birthtimespec
.tv_nsec
;
6947 usbp
->st_atime
= sbp
->st_atime
;
6948 usbp
->st_atimensec
= sbp
->st_atimensec
;
6949 usbp
->st_mtime
= sbp
->st_mtime
;
6950 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
6951 usbp
->st_ctime
= sbp
->st_ctime
;
6952 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
6953 usbp
->st_birthtime
= sbp
->st_birthtime
;
6954 usbp
->st_birthtimensec
= sbp
->st_birthtimensec
;
6956 usbp
->st_size
= sbp
->st_size
;
6957 usbp
->st_blocks
= sbp
->st_blocks
;
6958 usbp
->st_blksize
= sbp
->st_blksize
;
6959 usbp
->st_flags
= sbp
->st_flags
;
6960 usbp
->st_gen
= sbp
->st_gen
;
6961 usbp
->st_lspare
= sbp
->st_lspare
;
6962 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
6963 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];