2 * Copyright (c) 1995-2007 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 * Access is defined as checking against the process'
3498 * real identity, even if operations are checking the
3499 * effective identity. So we need to tweak the credential
3502 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
3503 context
.vc_thread
= current_thread();
3505 niopts
= FOLLOW
| AUDITVNPATH1
;
3506 /* need parent for vnode_authorize for deletion test */
3507 if (uap
->flags
& _DELETE_OK
)
3508 niopts
|= WANTPARENT
;
3509 NDINIT(&nd
, LOOKUP
, niopts
, UIO_USERSPACE
, uap
->path
, &context
);
3512 /* access(F_OK) calls are allowed for resource forks. */
3513 if (uap
->flags
== F_OK
)
3514 nd
.ni_cnd
.cn_flags
|= CN_ALLOWRSRCFORK
;
3520 error
= access1(nd
.ni_vp
, nd
.ni_dvp
, uap
->flags
, &context
);
3522 vnode_put(nd
.ni_vp
);
3523 if (uap
->flags
& _DELETE_OK
)
3524 vnode_put(nd
.ni_dvp
);
3528 kauth_cred_unref(&context
.vc_ucred
);
3534 * Returns: 0 Success
3541 stat2(vfs_context_t ctx
, struct nameidata
*ndp
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
, int isstat64
)
3545 struct user_stat user_sb
;
3546 struct user_stat64 user_sb64
;
3549 kauth_filesec_t fsec
;
3550 size_t xsecurity_bufsize
;
3554 /* stat calls are allowed for resource forks. */
3555 ndp
->ni_cnd
.cn_flags
|= CN_ALLOWRSRCFORK
;
3560 fsec
= KAUTH_FILESEC_NONE
;
3562 statptr
= (void *)&sb64
;
3564 statptr
= (void *)&sb
;
3565 error
= vn_stat(ndp
->ni_vp
, statptr
, (xsecurity
!= USER_ADDR_NULL
? &fsec
: NULL
), isstat64
, ctx
);
3568 /* Clean up resource fork shadow file if needed. */
3569 if ((ndp
->ni_vp
->v_flag
& VISNAMEDSTREAM
) &&
3570 (ndp
->ni_vp
->v_parent
!= NULLVP
) &&
3571 !(ndp
->ni_vp
->v_parent
->v_mount
->mnt_kern_flag
& MNTK_NAMED_STREAMS
)) {
3572 (void) vnode_relenamedstream(ndp
->ni_vp
->v_parent
, ndp
->ni_vp
, ctx
);
3575 vnode_put(ndp
->ni_vp
);
3580 /* Zap spare fields */
3581 if (isstat64
!= 0) {
3583 sb64
.st_qspare
[0] = 0LL;
3584 sb64
.st_qspare
[1] = 0LL;
3585 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
3586 munge_stat64(&sb64
, &user_sb64
);
3587 my_size
= sizeof(user_sb64
);
3588 sbp
= (caddr_t
)&user_sb64
;
3590 my_size
= sizeof(sb64
);
3591 sbp
= (caddr_t
)&sb64
;
3594 * Check if we raced (post lookup) against the last unlink of a file.
3596 if ((sb64
.st_nlink
== 0) && S_ISREG(sb64
.st_mode
)) {
3601 sb
.st_qspare
[0] = 0LL;
3602 sb
.st_qspare
[1] = 0LL;
3603 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
3604 munge_stat(&sb
, &user_sb
);
3605 my_size
= sizeof(user_sb
);
3606 sbp
= (caddr_t
)&user_sb
;
3608 my_size
= sizeof(sb
);
3613 * Check if we raced (post lookup) against the last unlink of a file.
3615 if ((sb
.st_nlink
== 0) && S_ISREG(sb
.st_mode
)) {
3619 if ((error
= copyout(sbp
, ub
, my_size
)) != 0)
3622 /* caller wants extended security information? */
3623 if (xsecurity
!= USER_ADDR_NULL
) {
3625 /* did we get any? */
3626 if (fsec
== KAUTH_FILESEC_NONE
) {
3627 if (susize(xsecurity_size
, 0) != 0) {
3632 /* find the user buffer size */
3633 xsecurity_bufsize
= fusize(xsecurity_size
);
3635 /* copy out the actual data size */
3636 if (susize(xsecurity_size
, KAUTH_FILESEC_COPYSIZE(fsec
)) != 0) {
3641 /* if the caller supplied enough room, copy out to it */
3642 if (xsecurity_bufsize
>= KAUTH_FILESEC_COPYSIZE(fsec
))
3643 error
= copyout(fsec
, xsecurity
, KAUTH_FILESEC_COPYSIZE(fsec
));
3647 if (fsec
!= KAUTH_FILESEC_NONE
)
3648 kauth_filesec_free(fsec
);
3653 * Get file status; this version follows links.
3655 * Returns: 0 Success
3656 * stat2:??? [see stat2() in this file]
3659 stat1(user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
, int isstat64
)
3661 struct nameidata nd
;
3662 vfs_context_t ctx
= vfs_context_current();
3664 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| FOLLOW
| AUDITVNPATH1
,
3665 UIO_USERSPACE
, path
, ctx
);
3666 return(stat2(ctx
, &nd
, ub
, xsecurity
, xsecurity_size
, isstat64
));
3670 stat_extended(__unused proc_t p
, struct stat_extended_args
*uap
, __unused register_t
*retval
)
3672 return (stat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 0));
3676 * Returns: 0 Success
3677 * stat1:??? [see stat1() in this file]
3680 stat(__unused proc_t p
, struct stat_args
*uap
, __unused register_t
*retval
)
3682 return(stat1(uap
->path
, uap
->ub
, 0, 0, 0));
3686 stat64(__unused proc_t p
, struct stat64_args
*uap
, __unused register_t
*retval
)
3688 return(stat1(uap
->path
, uap
->ub
, 0, 0, 1));
3692 stat64_extended(__unused proc_t p
, struct stat64_extended_args
*uap
, __unused register_t
*retval
)
3694 return (stat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 1));
3697 * Get file status; this version does not follow links.
3700 lstat1(user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
, int isstat64
)
3702 struct nameidata nd
;
3703 vfs_context_t ctx
= vfs_context_current();
3705 NDINIT(&nd
, LOOKUP
, NOTRIGGER
| NOFOLLOW
| AUDITVNPATH1
,
3706 UIO_USERSPACE
, path
, ctx
);
3708 return(stat2(ctx
, &nd
, ub
, xsecurity
, xsecurity_size
, isstat64
));
3712 lstat_extended(__unused proc_t p
, struct lstat_extended_args
*uap
, __unused register_t
*retval
)
3714 return (lstat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 0));
3718 lstat(__unused proc_t p
, struct lstat_args
*uap
, __unused register_t
*retval
)
3720 return(lstat1(uap
->path
, uap
->ub
, 0, 0, 0));
3723 lstat64(__unused proc_t p
, struct lstat64_args
*uap
, __unused register_t
*retval
)
3725 return(lstat1(uap
->path
, uap
->ub
, 0, 0, 1));
3729 lstat64_extended(__unused proc_t p
, struct lstat64_extended_args
*uap
, __unused register_t
*retval
)
3731 return (lstat1(uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
, 1));
3735 * Get configurable pathname variables.
3737 * Returns: 0 Success
3741 * Notes: Global implementation constants are intended to be
3742 * implemented in this function directly; all other constants
3743 * are per-FS implementation, and therefore must be handled in
3744 * each respective FS, instead.
3746 * XXX We implement some things globally right now that should actually be
3747 * XXX per-FS; we will need to deal with this at some point.
3751 pathconf(__unused proc_t p
, struct pathconf_args
*uap
, register_t
*retval
)
3754 struct nameidata nd
;
3755 vfs_context_t ctx
= vfs_context_current();
3757 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3758 UIO_USERSPACE
, uap
->path
, ctx
);
3763 error
= vn_pathconf(nd
.ni_vp
, uap
->name
, retval
, ctx
);
3765 vnode_put(nd
.ni_vp
);
3771 * Return target name of a symbolic link.
3775 readlink(proc_t p
, struct readlink_args
*uap
, register_t
*retval
)
3779 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
3781 struct nameidata nd
;
3782 vfs_context_t ctx
= vfs_context_current();
3783 char uio_buf
[ UIO_SIZEOF(1) ];
3785 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
3786 UIO_USERSPACE
, uap
->path
, ctx
);
3794 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
3795 &uio_buf
[0], sizeof(uio_buf
));
3796 uio_addiov(auio
, uap
->buf
, uap
->count
);
3797 if (vp
->v_type
!= VLNK
)
3801 error
= mac_vnode_check_readlink(ctx
,
3805 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, ctx
);
3807 error
= VNOP_READLINK(vp
, auio
, ctx
);
3810 // LP64todo - fix this
3811 *retval
= uap
->count
- (int)uio_resid(auio
);
3816 * Change file flags.
3819 chflags1(vnode_t vp
, int flags
, vfs_context_t ctx
)
3821 struct vnode_attr va
;
3822 kauth_action_t action
;
3826 VATTR_SET(&va
, va_flags
, flags
);
3829 error
= mac_vnode_check_setflags(ctx
, vp
, flags
);
3834 /* request authorisation, disregard immutability */
3835 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
3838 * Request that the auth layer disregard those file flags it's allowed to when
3839 * authorizing this operation; we need to do this in order to be able to
3840 * clear immutable flags.
3842 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
| KAUTH_VNODE_NOIMMUTABLE
, ctx
)) != 0))
3844 error
= vnode_setattr(vp
, &va
, ctx
);
3846 if ((error
== 0) && !VATTR_IS_SUPPORTED(&va
, va_flags
)) {
3855 * Change flags of a file given a path name.
3859 chflags(__unused proc_t p
, struct chflags_args
*uap
, __unused register_t
*retval
)
3862 vfs_context_t ctx
= vfs_context_current();
3864 struct nameidata nd
;
3866 AUDIT_ARG(fflags
, uap
->flags
);
3867 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3868 UIO_USERSPACE
, uap
->path
, ctx
);
3875 error
= chflags1(vp
, uap
->flags
, ctx
);
3881 * Change flags of a file given a file descriptor.
3885 fchflags(__unused proc_t p
, struct fchflags_args
*uap
, __unused register_t
*retval
)
3890 AUDIT_ARG(fd
, uap
->fd
);
3891 AUDIT_ARG(fflags
, uap
->flags
);
3892 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
3895 if ((error
= vnode_getwithref(vp
))) {
3900 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3902 error
= chflags1(vp
, uap
->flags
, vfs_context_current());
3909 * Change security information on a filesystem object.
3911 * Returns: 0 Success
3912 * EPERM Operation not permitted
3913 * vnode_authattr:??? [anything vnode_authattr can return]
3914 * vnode_authorize:??? [anything vnode_authorize can return]
3915 * vnode_setattr:??? [anything vnode_setattr can return]
3917 * Notes: If vnode_authattr or vnode_authorize return EACCES, it will be
3918 * translated to EPERM before being returned.
3921 chmod2(vfs_context_t ctx
, vnode_t vp
, struct vnode_attr
*vap
)
3923 kauth_action_t action
;
3926 AUDIT_ARG(mode
, (mode_t
)vap
->va_mode
);
3927 #warning XXX audit new args
3930 /* chmod calls are not allowed for resource forks. */
3931 if (vp
->v_flag
& VISNAMEDSTREAM
) {
3937 error
= mac_vnode_check_setmode(ctx
, vp
, (mode_t
)vap
->va_mode
);
3942 /* make sure that the caller is allowed to set this security information */
3943 if (((error
= vnode_authattr(vp
, vap
, &action
, ctx
)) != 0) ||
3944 ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
3945 if (error
== EACCES
)
3950 error
= vnode_setattr(vp
, vap
, ctx
);
3957 * Change mode of a file given path name.
3959 * Returns: 0 Success
3960 * namei:??? [anything namei can return]
3961 * chmod2:??? [anything chmod2 can return]
3964 chmod1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
3966 struct nameidata nd
;
3969 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3970 UIO_USERSPACE
, path
, ctx
);
3971 if ((error
= namei(&nd
)))
3973 error
= chmod2(ctx
, nd
.ni_vp
, vap
);
3974 vnode_put(nd
.ni_vp
);
3980 * A chmod system call using an extended argument list compared to the regular
3981 * system call 'mkfifo'.
3983 * Parameters: p Process requesting the open
3984 * uap User argument descriptor (see below)
3987 * Indirect: uap->path Path to object (same as 'chmod')
3988 * uap->uid UID to set
3989 * uap->gid GID to set
3990 * uap->mode File mode to set (same as 'chmod')
3991 * uap->xsecurity ACL to set (or delete)
3993 * Returns: 0 Success
3996 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
3998 * XXX: We should enummerate the possible errno values here, and where
3999 * in the code they originated.
4002 chmod_extended(__unused proc_t p
, struct chmod_extended_args
*uap
, __unused register_t
*retval
)
4005 struct vnode_attr va
;
4006 kauth_filesec_t xsecdst
;
4009 if (uap
->mode
!= -1)
4010 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
4011 if (uap
->uid
!= KAUTH_UID_NONE
)
4012 VATTR_SET(&va
, va_uid
, uap
->uid
);
4013 if (uap
->gid
!= KAUTH_GID_NONE
)
4014 VATTR_SET(&va
, va_gid
, uap
->gid
);
4017 switch(uap
->xsecurity
) {
4018 /* explicit remove request */
4019 case CAST_USER_ADDR_T((void *)1): /* _FILESEC_REMOVE_ACL */
4020 VATTR_SET(&va
, va_acl
, NULL
);
4023 case USER_ADDR_NULL
:
4026 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
4028 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
4029 KAUTH_DEBUG("CHMOD - setting ACL with %d entries", va
.va_acl
->acl_entrycount
);
4032 error
= chmod1(vfs_context_current(), uap
->path
, &va
);
4034 if (xsecdst
!= NULL
)
4035 kauth_filesec_free(xsecdst
);
4040 * Returns: 0 Success
4041 * chmod1:??? [anything chmod1 can return]
4044 chmod(__unused proc_t p
, struct chmod_args
*uap
, __unused register_t
*retval
)
4046 struct vnode_attr va
;
4049 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
4051 return(chmod1(vfs_context_current(), uap
->path
, &va
));
4055 * Change mode of a file given a file descriptor.
4058 fchmod1(__unused proc_t p
, int fd
, struct vnode_attr
*vap
)
4065 if ((error
= file_vnode(fd
, &vp
)) != 0)
4067 if ((error
= vnode_getwithref(vp
)) != 0) {
4071 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4073 error
= chmod2(vfs_context_current(), vp
, vap
);
4074 (void)vnode_put(vp
);
4081 fchmod_extended(proc_t p
, struct fchmod_extended_args
*uap
, __unused register_t
*retval
)
4084 struct vnode_attr va
;
4085 kauth_filesec_t xsecdst
;
4088 if (uap
->mode
!= -1)
4089 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
4090 if (uap
->uid
!= KAUTH_UID_NONE
)
4091 VATTR_SET(&va
, va_uid
, uap
->uid
);
4092 if (uap
->gid
!= KAUTH_GID_NONE
)
4093 VATTR_SET(&va
, va_gid
, uap
->gid
);
4096 switch(uap
->xsecurity
) {
4097 case USER_ADDR_NULL
:
4098 VATTR_SET(&va
, va_acl
, NULL
);
4100 case CAST_USER_ADDR_T(-1):
4103 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
4105 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
4108 error
= fchmod1(p
, uap
->fd
, &va
);
4111 switch(uap
->xsecurity
) {
4112 case USER_ADDR_NULL
:
4113 case CAST_USER_ADDR_T(-1):
4116 if (xsecdst
!= NULL
)
4117 kauth_filesec_free(xsecdst
);
4123 fchmod(proc_t p
, struct fchmod_args
*uap
, __unused register_t
*retval
)
4125 struct vnode_attr va
;
4128 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
4130 return(fchmod1(p
, uap
->fd
, &va
));
4135 * Set ownership given a path name.
4139 chown1(vfs_context_t ctx
, struct chown_args
*uap
, __unused register_t
*retval
, int follow
)
4142 struct vnode_attr va
;
4144 struct nameidata nd
;
4145 kauth_action_t action
;
4147 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
4149 NDINIT(&nd
, LOOKUP
, (follow
? FOLLOW
: 0) | NOTRIGGER
| AUDITVNPATH1
,
4150 UIO_USERSPACE
, uap
->path
, ctx
);
4159 if (uap
->uid
!= VNOVAL
)
4160 VATTR_SET(&va
, va_uid
, uap
->uid
);
4161 if (uap
->gid
!= VNOVAL
)
4162 VATTR_SET(&va
, va_gid
, uap
->gid
);
4165 error
= mac_vnode_check_setowner(ctx
, vp
, uap
->uid
, uap
->gid
);
4170 /* preflight and authorize attribute changes */
4171 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
4173 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
4175 error
= vnode_setattr(vp
, &va
, ctx
);
4179 * EACCES is only allowed from namei(); permissions failure should
4180 * return EPERM, so we need to translate the error code.
4182 if (error
== EACCES
)
4190 chown(__unused proc_t p
, struct chown_args
*uap
, register_t
*retval
)
4192 return chown1(vfs_context_current(), uap
, retval
, 1);
4196 lchown(__unused proc_t p
, struct lchown_args
*uap
, register_t
*retval
)
4198 /* Argument list identical, but machine generated; cast for chown1() */
4199 return chown1(vfs_context_current(), (struct chown_args
*)uap
, retval
, 0);
4203 * Set ownership given a file descriptor.
4207 fchown(__unused proc_t p
, struct fchown_args
*uap
, __unused register_t
*retval
)
4209 struct vnode_attr va
;
4210 vfs_context_t ctx
= vfs_context_current();
4213 kauth_action_t action
;
4215 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
4216 AUDIT_ARG(fd
, uap
->fd
);
4218 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
4221 if ( (error
= vnode_getwithref(vp
)) ) {
4225 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4228 if (uap
->uid
!= VNOVAL
)
4229 VATTR_SET(&va
, va_uid
, uap
->uid
);
4230 if (uap
->gid
!= VNOVAL
)
4231 VATTR_SET(&va
, va_gid
, uap
->gid
);
4234 /* chown calls are not allowed for resource forks. */
4235 if (vp
->v_flag
& VISNAMEDSTREAM
) {
4242 error
= mac_vnode_check_setowner(ctx
, vp
, uap
->uid
, uap
->gid
);
4247 /* preflight and authorize attribute changes */
4248 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
4250 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
4251 if (error
== EACCES
)
4255 error
= vnode_setattr(vp
, &va
, ctx
);
4258 (void)vnode_put(vp
);
4264 getutimes(user_addr_t usrtvp
, struct timespec
*tsp
)
4266 struct user_timeval tv
[2];
4269 if (usrtvp
== USER_ADDR_NULL
) {
4270 struct timeval old_tv
;
4271 /* XXX Y2038 bug because of microtime argument */
4273 TIMEVAL_TO_TIMESPEC(&old_tv
, &tsp
[0]);
4276 if (IS_64BIT_PROCESS(current_proc())) {
4277 error
= copyin(usrtvp
, (void *)tv
, sizeof(tv
));
4279 struct timeval old_tv
[2];
4280 error
= copyin(usrtvp
, (void *)old_tv
, sizeof(old_tv
));
4281 tv
[0].tv_sec
= old_tv
[0].tv_sec
;
4282 tv
[0].tv_usec
= old_tv
[0].tv_usec
;
4283 tv
[1].tv_sec
= old_tv
[1].tv_sec
;
4284 tv
[1].tv_usec
= old_tv
[1].tv_usec
;
4288 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
4289 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
4295 setutimes(vfs_context_t ctx
, vnode_t vp
, const struct timespec
*ts
,
4299 struct vnode_attr va
;
4300 kauth_action_t action
;
4302 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4305 VATTR_SET(&va
, va_access_time
, ts
[0]);
4306 VATTR_SET(&va
, va_modify_time
, ts
[1]);
4308 va
.va_vaflags
|= VA_UTIMES_NULL
;
4311 /* utimes calls are not allowed for resource forks. */
4312 if (vp
->v_flag
& VISNAMEDSTREAM
) {
4319 error
= mac_vnode_check_setutimes(ctx
, vp
, ts
[0], ts
[1]);
4323 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0) {
4324 if (!nullflag
&& error
== EACCES
)
4329 /* since we may not need to auth anything, check here */
4330 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
4331 if (!nullflag
&& error
== EACCES
)
4335 error
= vnode_setattr(vp
, &va
, ctx
);
4342 * Set the access and modification times of a file.
4346 utimes(__unused proc_t p
, struct utimes_args
*uap
, __unused register_t
*retval
)
4348 struct timespec ts
[2];
4351 struct nameidata nd
;
4352 vfs_context_t ctx
= vfs_context_current();
4355 * AUDIT: Needed to change the order of operations to do the
4356 * name lookup first because auditing wants the path.
4358 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4359 UIO_USERSPACE
, uap
->path
, ctx
);
4366 * Fetch the user-supplied time. If usrtvp is USER_ADDR_NULL, we fetch
4367 * the current time instead.
4370 if ((error
= getutimes(usrtvp
, ts
)) != 0)
4373 error
= setutimes(ctx
, nd
.ni_vp
, ts
, usrtvp
== USER_ADDR_NULL
);
4376 vnode_put(nd
.ni_vp
);
4381 * Set the access and modification times of a file.
4385 futimes(__unused proc_t p
, struct futimes_args
*uap
, __unused register_t
*retval
)
4387 struct timespec ts
[2];
4392 AUDIT_ARG(fd
, uap
->fd
);
4394 if ((error
= getutimes(usrtvp
, ts
)) != 0)
4396 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
4398 if((error
= vnode_getwithref(vp
))) {
4403 error
= setutimes(vfs_context_current(), vp
, ts
, usrtvp
== 0);
4410 * Truncate a file given its path name.
4414 truncate(__unused proc_t p
, struct truncate_args
*uap
, __unused register_t
*retval
)
4417 struct vnode_attr va
;
4418 vfs_context_t ctx
= vfs_context_current();
4420 struct nameidata nd
;
4421 kauth_action_t action
;
4423 if (uap
->length
< 0)
4425 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4426 UIO_USERSPACE
, uap
->path
, ctx
);
4427 if ((error
= namei(&nd
)))
4434 VATTR_SET(&va
, va_data_size
, uap
->length
);
4437 error
= mac_vnode_check_truncate(ctx
, NOCRED
, vp
);
4442 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
4444 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
4446 error
= vnode_setattr(vp
, &va
, ctx
);
4453 * Truncate a file given a file descriptor.
4457 ftruncate(proc_t p
, struct ftruncate_args
*uap
, register_t
*retval
)
4459 vfs_context_t ctx
= vfs_context_current();
4460 struct vnode_attr va
;
4462 struct fileproc
*fp
;
4466 AUDIT_ARG(fd
, uap
->fd
);
4467 if (uap
->length
< 0)
4470 if ( (error
= fp_lookup(p
,fd
,&fp
,0)) ) {
4474 if (fp
->f_fglob
->fg_type
== DTYPE_PSXSHM
) {
4475 error
= pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
);
4478 if (fp
->f_fglob
->fg_type
!= DTYPE_VNODE
) {
4483 vp
= (vnode_t
)fp
->f_fglob
->fg_data
;
4485 if ((fp
->f_fglob
->fg_flag
& FWRITE
) == 0) {
4486 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4491 if ((error
= vnode_getwithref(vp
)) != 0) {
4495 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4498 error
= mac_vnode_check_truncate(ctx
,
4499 fp
->f_fglob
->fg_cred
, vp
);
4501 (void)vnode_put(vp
);
4506 VATTR_SET(&va
, va_data_size
, uap
->length
);
4507 error
= vnode_setattr(vp
, &va
, ctx
);
4508 (void)vnode_put(vp
);
4516 * Sync an open file.
4520 fsync(proc_t p
, struct fsync_args
*uap
, register_t
*retval
)
4522 __pthread_testcancel(1);
4523 return(fsync_nocancel(p
, (struct fsync_nocancel_args
*)uap
, retval
));
4527 fsync_nocancel(proc_t p
, struct fsync_nocancel_args
*uap
, __unused register_t
*retval
)
4530 struct fileproc
*fp
;
4531 vfs_context_t ctx
= vfs_context_current();
4534 if ( (error
= fp_getfvp(p
, uap
->fd
, &fp
, &vp
)) )
4536 if ( (error
= vnode_getwithref(vp
)) ) {
4541 error
= VNOP_FSYNC(vp
, MNT_WAIT
, ctx
);
4544 /* Sync resource fork shadow file if necessary. */
4546 (vp
->v_flag
& VISNAMEDSTREAM
) &&
4547 (vp
->v_parent
!= NULLVP
) &&
4548 !(vp
->v_parent
->v_mount
->mnt_kern_flag
& MNTK_NAMED_STREAMS
) &&
4549 (fp
->f_flags
& FP_WRITTEN
)) {
4550 (void) vnode_flushnamedstream(vp
->v_parent
, vp
, ctx
);
4554 (void)vnode_put(vp
);
4560 * Duplicate files. Source must be a file, target must be a file or
4563 * XXX Copyfile authorisation checking is woefully inadequate, and will not
4564 * perform inheritance correctly.
4568 copyfile(__unused proc_t p
, struct copyfile_args
*uap
, __unused register_t
*retval
)
4570 vnode_t tvp
, fvp
, tdvp
, sdvp
;
4571 struct nameidata fromnd
, tond
;
4573 vfs_context_t ctx
= vfs_context_current();
4575 /* Check that the flags are valid. */
4577 if (uap
->flags
& ~CPF_MASK
) {
4581 NDINIT(&fromnd
, LOOKUP
, SAVESTART
| AUDITVNPATH1
,
4582 UIO_USERSPACE
, uap
->from
, ctx
);
4583 if ((error
= namei(&fromnd
)))
4587 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
| AUDITVNPATH2
| CN_NBMOUNTLOOK
,
4588 UIO_USERSPACE
, uap
->to
, ctx
);
4589 if ((error
= namei(&tond
))) {
4596 if (!(uap
->flags
& CPF_OVERWRITE
)) {
4601 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
4606 if ((error
= vnode_authorize(tdvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
4612 * If source is the same as the destination (that is the
4613 * same inode number) then there is nothing to do.
4614 * (fixed to have POSIX semantics - CSM 3/2/98)
4619 error
= VNOP_COPYFILE(fvp
, tdvp
, tvp
, &tond
.ni_cnd
, uap
->mode
, uap
->flags
, ctx
);
4621 sdvp
= tond
.ni_startdir
;
4623 * nameidone has to happen before we vnode_put(tdvp)
4624 * since it may need to release the fs_nodelock on the tdvp
4635 if (fromnd
.ni_startdir
)
4636 vnode_put(fromnd
.ni_startdir
);
4646 * Rename files. Source and destination must either both be directories,
4647 * or both not be directories. If target is a directory, it must be empty.
4651 rename(__unused proc_t p
, struct rename_args
*uap
, __unused register_t
*retval
)
4655 struct nameidata fromnd
, tond
;
4656 vfs_context_t ctx
= vfs_context_current();
4661 char *from_name
= NULL
, *to_name
= NULL
;
4662 int from_len
, to_len
;
4663 int holding_mntlock
;
4664 mount_t locked_mp
= NULL
;
4666 fse_info from_finfo
, to_finfo
;
4668 holding_mntlock
= 0;
4674 NDINIT(&fromnd
, DELETE
, WANTPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->from
, ctx
);
4676 if ( (error
= namei(&fromnd
)) )
4678 fdvp
= fromnd
.ni_dvp
;
4682 error
= mac_vnode_check_rename_from(ctx
, fdvp
, fvp
, &fromnd
.ni_cnd
);
4687 NDINIT(&tond
, RENAME
, WANTPARENT
| AUDITVNPATH2
| CN_NBMOUNTLOOK
, UIO_USERSPACE
, uap
->to
, ctx
);
4688 if (fvp
->v_type
== VDIR
)
4689 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
4691 if ( (error
= namei(&tond
)) ) {
4693 * Translate error code for rename("dir1", "dir2/.").
4695 if (error
== EISDIR
&& fvp
->v_type
== VDIR
)
4703 error
= mac_vnode_check_rename_to(ctx
,
4704 tdvp
, tvp
, fdvp
== tdvp
, &tond
.ni_cnd
);
4710 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
4713 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
4723 * If the source and destination are the same (i.e. they're
4724 * links to the same vnode) and the target file system is
4725 * case sensitive, then there is nothing to do.
4731 * Note: if _PC_CASE_SENSITIVE selector isn't supported,
4732 * then assume that this file system is case sensitive.
4734 if (VNOP_PATHCONF(fvp
, _PC_CASE_SENSITIVE
, &pathconf_val
, ctx
) != 0 ||
4735 pathconf_val
!= 0) {
4743 * If tvp is a directory and not the same as fdvp, or tdvp is not
4744 * the same as fdvp, the node is moving between directories and we
4745 * need rights to remove from the old and add to the new.
4747 * If tvp already exists and is not a directory, we need to be
4748 * allowed to delete it.
4750 * Note that we do not inherit when renaming.
4752 * XXX This needs to be revisited to implement the deferred-inherit bit
4758 if ((tvp
!= NULL
) && vnode_isdir(tvp
)) {
4761 } else if (tdvp
!= fdvp
) {
4765 * must have delete rights to remove the old name even in
4766 * the simple case of fdvp == tdvp.
4768 * If fvp is a directory, and we are changing it's parent,
4769 * then we also need rights to rewrite its ".." entry as well.
4771 if (vnode_isdir(fvp
)) {
4772 if ((error
= vnode_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
| KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
)) != 0)
4775 if ((error
= vnode_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
, ctx
)) != 0)
4779 /* moving into tdvp or tvp, must have rights to add */
4780 if ((error
= vnode_authorize(((tvp
!= NULL
) && vnode_isdir(tvp
)) ? tvp
: tdvp
,
4782 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
4786 /* node staying in same directory, must be allowed to add new name */
4787 if ((error
= vnode_authorize(fdvp
, NULL
,
4788 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
4791 /* overwriting tvp */
4792 if ((tvp
!= NULL
) && !vnode_isdir(tvp
) &&
4793 ((error
= vnode_authorize(tvp
, tdvp
, KAUTH_VNODE_DELETE
, ctx
)) != 0))
4796 /* XXX more checks? */
4799 /* authorization denied */
4804 * Allow the renaming of mount points.
4805 * - target must not exist
4806 * - target must reside in the same directory as source
4807 * - union mounts cannot be renamed
4808 * - "/" cannot be renamed
4810 if ((fvp
->v_flag
& VROOT
) &&
4811 (fvp
->v_type
== VDIR
) &&
4813 (fvp
->v_mountedhere
== NULL
) &&
4815 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
4816 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
4819 /* switch fvp to the covered vnode */
4820 coveredvp
= fvp
->v_mount
->mnt_vnodecovered
;
4821 if ( (vnode_getwithref(coveredvp
)) ) {
4831 * Check for cross-device rename.
4833 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
4834 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
4839 * Avoid renaming "." and "..".
4841 if (fvp
->v_type
== VDIR
&&
4843 (fromnd
.ni_cnd
.cn_namelen
== 1 && fromnd
.ni_cnd
.cn_nameptr
[0] == '.') ||
4844 ((fromnd
.ni_cnd
.cn_flags
| tond
.ni_cnd
.cn_flags
) & ISDOTDOT
)) ) {
4849 * The following edge case is caught here:
4850 * (to cannot be a descendent of from)
4863 if (tdvp
->v_parent
== fvp
) {
4869 * If source is the same as the destination (that is the
4870 * same inode number) then there is nothing to do...
4871 * EXCEPT if the underlying file system supports case
4872 * insensitivity and is case preserving. In this case
4873 * the file system needs to handle the special case of
4874 * getting the same vnode as target (fvp) and source (tvp).
4876 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
4877 * and _PC_CASE_PRESERVING can have this exception, and they need to
4878 * handle the special case of getting the same vnode as target and
4879 * source. NOTE: Then the target is unlocked going into vnop_rename,
4880 * so not to cause locking problems. There is a single reference on tvp.
4882 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
4883 * that correct behaviour then is just to remove the source (link)
4885 if (fvp
== tvp
&& fdvp
== tdvp
) {
4886 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
4887 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
4888 fromnd
.ni_cnd
.cn_namelen
)) {
4893 if (holding_mntlock
&& fvp
->v_mount
!= locked_mp
) {
4895 * we're holding a reference and lock
4896 * on locked_mp, but it no longer matches
4897 * what we want to do... so drop our hold
4899 mount_unlock_renames(locked_mp
);
4900 mount_drop(locked_mp
, 0);
4901 holding_mntlock
= 0;
4903 if (tdvp
!= fdvp
&& fvp
->v_type
== VDIR
) {
4905 * serialize renames that re-shape
4906 * the tree... if holding_mntlock is
4907 * set, then we're ready to go...
4909 * first need to drop the iocounts
4910 * we picked up, second take the
4911 * lock to serialize the access,
4912 * then finally start the lookup
4913 * process over with the lock held
4915 if (!holding_mntlock
) {
4917 * need to grab a reference on
4918 * the mount point before we
4919 * drop all the iocounts... once
4920 * the iocounts are gone, the mount
4923 locked_mp
= fvp
->v_mount
;
4924 mount_ref(locked_mp
, 0);
4927 * nameidone has to happen before we vnode_put(tvp)
4928 * since it may need to release the fs_nodelock on the tvp
4937 * nameidone has to happen before we vnode_put(fdvp)
4938 * since it may need to release the fs_nodelock on the fvp
4945 mount_lock_renames(locked_mp
);
4946 holding_mntlock
= 1;
4952 * when we dropped the iocounts to take
4953 * the lock, we allowed the identity of
4954 * the various vnodes to change... if they did,
4955 * we may no longer be dealing with a rename
4956 * that reshapes the tree... once we're holding
4957 * the iocounts, the vnodes can't change type
4958 * so we're free to drop the lock at this point
4961 if (holding_mntlock
) {
4962 mount_unlock_renames(locked_mp
);
4963 mount_drop(locked_mp
, 0);
4964 holding_mntlock
= 0;
4967 // save these off so we can later verify that fvp is the same
4968 oname
= fvp
->v_name
;
4969 oparent
= fvp
->v_parent
;
4972 need_event
= need_fsevent(FSE_RENAME
, fvp
);
4974 get_fse_info(fvp
, &from_finfo
, ctx
);
4977 get_fse_info(tvp
, &to_finfo
, ctx
);
4982 #endif /* CONFIG_FSE */
4984 if (need_event
|| kauth_authorize_fileop_has_listeners()) {
4985 GET_PATH(from_name
);
4986 if (from_name
== NULL
) {
4990 from_len
= MAXPATHLEN
;
4991 vn_getpath(fdvp
, from_name
, &from_len
);
4992 if ((from_len
+ 1 + fromnd
.ni_cnd
.cn_namelen
+ 1) < MAXPATHLEN
) {
4994 from_name
[from_len
-1] = '/';
4998 strlcpy(&from_name
[from_len
], fromnd
.ni_cnd
.cn_nameptr
, MAXPATHLEN
-from_len
);
4999 from_len
+= fromnd
.ni_cnd
.cn_namelen
+ 1;
5000 from_name
[from_len
] = '\0';
5004 if (to_name
== NULL
) {
5009 to_len
= MAXPATHLEN
;
5010 vn_getpath(tdvp
, to_name
, &to_len
);
5011 // if the path is not just "/", then append a "/"
5012 if ((to_len
+ 1 + tond
.ni_cnd
.cn_namelen
+ 1) < MAXPATHLEN
) {
5014 to_name
[to_len
-1] = '/';
5018 strlcpy(&to_name
[to_len
], tond
.ni_cnd
.cn_nameptr
, MAXPATHLEN
-to_len
);
5019 to_len
+= tond
.ni_cnd
.cn_namelen
+ 1;
5020 to_name
[to_len
] = '\0';
5024 error
= VNOP_RENAME(fdvp
, fvp
, &fromnd
.ni_cnd
,
5025 tdvp
, tvp
, &tond
.ni_cnd
,
5028 if (holding_mntlock
) {
5030 * we can drop our serialization
5033 mount_unlock_renames(locked_mp
);
5034 mount_drop(locked_mp
, 0);
5035 holding_mntlock
= 0;
5042 /* call out to allow 3rd party notification of rename.
5043 * Ignore result of kauth_authorize_fileop call.
5045 kauth_authorize_fileop(vfs_context_ucred(ctx
),
5046 KAUTH_FILEOP_RENAME
,
5047 (uintptr_t)from_name
, (uintptr_t)to_name
);
5050 if (from_name
!= NULL
&& to_name
!= NULL
) {
5052 add_fsevent(FSE_RENAME
, ctx
,
5053 FSE_ARG_STRING
, from_len
, from_name
,
5054 FSE_ARG_FINFO
, &from_finfo
,
5055 FSE_ARG_STRING
, to_len
, to_name
,
5056 FSE_ARG_FINFO
, &to_finfo
,
5059 add_fsevent(FSE_RENAME
, ctx
,
5060 FSE_ARG_STRING
, from_len
, from_name
,
5061 FSE_ARG_FINFO
, &from_finfo
,
5062 FSE_ARG_STRING
, to_len
, to_name
,
5066 #endif /* CONFIG_FSE */
5069 * update filesystem's mount point data
5072 char *cp
, *pathend
, *mpname
;
5078 mp
= fvp
->v_mountedhere
;
5080 if (vfs_busy(mp
, LK_NOWAIT
)) {
5084 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
5086 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
5088 /* find current mount point prefix */
5089 pathend
= &mp
->mnt_vfsstat
.f_mntonname
[0];
5090 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
5094 /* find last component of target name */
5095 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
5099 /* append name to prefix */
5100 maxlen
= MAXPATHLEN
- (pathend
- mp
->mnt_vfsstat
.f_mntonname
);
5101 bzero(pathend
, maxlen
);
5102 strlcpy(pathend
, mpname
, maxlen
);
5104 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
5109 * fix up name & parent pointers. note that we first
5110 * check that fvp has the same name/parent pointers it
5111 * had before the rename call... this is a 'weak' check
5114 if (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
) {
5117 update_flags
= VNODE_UPDATE_NAME
;
5120 update_flags
|= VNODE_UPDATE_PARENT
;
5122 vnode_update_identity(fvp
, tdvp
, tond
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_namelen
, tond
.ni_cnd
.cn_hash
, update_flags
);
5125 if (to_name
!= NULL
)
5126 RELEASE_PATH(to_name
);
5127 if (from_name
!= NULL
)
5128 RELEASE_PATH(from_name
);
5130 if (holding_mntlock
) {
5131 mount_unlock_renames(locked_mp
);
5132 mount_drop(locked_mp
, 0);
5136 * nameidone has to happen before we vnode_put(tdvp)
5137 * since it may need to release the fs_nodelock on the tdvp
5147 * nameidone has to happen before we vnode_put(fdvp)
5148 * since it may need to release the fs_nodelock on the fdvp
5160 * Make a directory file.
5162 * Returns: 0 Success
5165 * vnode_authorize:???
5170 mkdir1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
5174 int update_flags
= 0;
5175 struct nameidata nd
;
5177 AUDIT_ARG(mode
, vap
->va_mode
);
5178 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
5179 UIO_USERSPACE
, path
, ctx
);
5180 nd
.ni_cnd
.cn_flags
|= WILLBEDIR
;
5192 VATTR_SET(vap
, va_type
, VDIR
);
5195 error
= mac_vnode_check_create(ctx
,
5196 nd
.ni_dvp
, &nd
.ni_cnd
, vap
);
5201 /* authorize addition of a directory to the parent */
5202 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
)) != 0)
5206 /* make the directory */
5207 if ((error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
)) != 0)
5210 // Make sure the name & parent pointers are hooked up
5211 if (vp
->v_name
== NULL
)
5212 update_flags
|= VNODE_UPDATE_NAME
;
5213 if (vp
->v_parent
== NULLVP
)
5214 update_flags
|= VNODE_UPDATE_PARENT
;
5217 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
5220 add_fsevent(FSE_CREATE_DIR
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
5225 * nameidone has to happen before we vnode_put(dvp)
5226 * since it may need to release the fs_nodelock on the dvp
5239 mkdir_extended(proc_t p
, struct mkdir_extended_args
*uap
, __unused register_t
*retval
)
5242 kauth_filesec_t xsecdst
;
5243 struct vnode_attr va
;
5246 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
5247 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
5251 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
5252 if (xsecdst
!= NULL
)
5253 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
5255 ciferror
= mkdir1(vfs_context_current(), uap
->path
, &va
);
5256 if (xsecdst
!= NULL
)
5257 kauth_filesec_free(xsecdst
);
5262 mkdir(proc_t p
, struct mkdir_args
*uap
, __unused register_t
*retval
)
5264 struct vnode_attr va
;
5267 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
5269 return(mkdir1(vfs_context_current(), uap
->path
, &va
));
5273 * Remove a directory file.
5277 rmdir(__unused proc_t p
, struct rmdir_args
*uap
, __unused register_t
*retval
)
5281 struct nameidata nd
;
5282 vfs_context_t ctx
= vfs_context_current();
5284 int restart_flag
, oldvp_id
= -1;
5287 * This loop exists to restart rmdir in the unlikely case that two
5288 * processes are simultaneously trying to remove the same directory
5289 * containing orphaned appleDouble files.
5294 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
5295 UIO_USERSPACE
, uap
->path
, ctx
);
5305 * If being restarted check if the new vp
5306 * still has the same v_id.
5308 if (oldvp_id
!= -1 && oldvp_id
!= vp
->v_id
) {
5313 if (vp
->v_type
!= VDIR
) {
5315 * rmdir only deals with directories
5318 } else if (dvp
== vp
) {
5320 * No rmdir "." please.
5323 } else if (vp
->v_flag
& VROOT
) {
5325 * The root of a mounted filesystem cannot be deleted.
5330 error
= mac_vnode_check_unlink(ctx
, dvp
,
5334 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, ctx
);
5340 int has_listeners
= 0;
5344 need_event
= need_fsevent(FSE_DELETE
, dvp
);
5346 get_fse_info(vp
, &finfo
, ctx
);
5349 has_listeners
= kauth_authorize_fileop_has_listeners();
5350 if (need_event
|| has_listeners
) {
5357 vn_getpath(vp
, path
, &len
);
5360 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, ctx
);
5363 * Special case to remove orphaned AppleDouble
5364 * files. I don't like putting this in the kernel,
5365 * but carbon does not like putting this in carbon either,
5368 if (error
== ENOTEMPTY
) {
5369 error
= rmdir_remove_orphaned_appleDouble(vp
, ctx
, &restart_flag
);
5370 if (error
== EBUSY
) {
5371 oldvp_id
= vp
->v_id
;
5377 * Assuming everything went well, we will try the RMDIR again
5380 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, ctx
);
5384 * Call out to allow 3rd party notification of delete.
5385 * Ignore result of kauth_authorize_fileop call.
5388 if (has_listeners
) {
5389 kauth_authorize_fileop(vfs_context_ucred(ctx
),
5390 KAUTH_FILEOP_DELETE
,
5395 if (vp
->v_flag
& VISHARDLINK
) {
5396 // see the comment in unlink1() about why we update
5397 // the parent of a hard link when it is removed
5398 vnode_update_identity(vp
, NULL
, NULL
, 0, 0, VNODE_UPDATE_PARENT
);
5403 add_fsevent(FSE_DELETE
, ctx
,
5404 FSE_ARG_STRING
, len
, path
,
5405 FSE_ARG_FINFO
, &finfo
,
5416 * nameidone has to happen before we vnode_put(dvp)
5417 * since it may need to release the fs_nodelock on the dvp
5424 if (restart_flag
== 0) {
5425 wakeup_one((caddr_t
)vp
);
5428 tsleep(vp
, PVFS
, "rm AD", 1);
5430 } while (restart_flag
!= 0);
5436 /* Get direntry length padded to 8 byte alignment */
5437 #define DIRENT64_LEN(namlen) \
5438 ((sizeof(struct direntry) + (namlen) - (MAXPATHLEN-1) + 7) & ~7)
5441 vnode_readdir64(struct vnode
*vp
, struct uio
*uio
, int flags
, int *eofflag
,
5442 int *numdirent
, vfs_context_t ctxp
)
5444 /* Check if fs natively supports VNODE_READDIR_EXTENDED */
5445 if (vp
->v_mount
->mnt_vtable
->vfc_vfsflags
& VFC_VFSREADDIR_EXTENDED
) {
5446 return VNOP_READDIR(vp
, uio
, flags
, eofflag
, numdirent
, ctxp
);
5451 struct direntry entry64
;
5457 * Our kernel buffer needs to be smaller since re-packing
5458 * will expand each dirent. The worse case (when the name
5459 * length is 3) corresponds to a struct direntry size of 32
5460 * bytes (8-byte aligned) and a struct dirent size of 12 bytes
5461 * (4-byte aligned). So having a buffer that is 3/8 the size
5462 * will prevent us from reading more than we can pack.
5464 * Since this buffer is wired memory, we will limit the
5465 * buffer size to a maximum of 32K. We would really like to
5466 * use 32K in the MIN(), but we use magic number 87371 to
5467 * prevent uio_resid() * 3 / 8 from overflowing.
5469 bufsize
= 3 * MIN(uio_resid(uio
), 87371) / 8;
5470 MALLOC(bufptr
, void *, bufsize
, M_TEMP
, M_WAITOK
);
5472 auio
= uio_create(1, 0, UIO_SYSSPACE32
, UIO_READ
);
5473 uio_addiov(auio
, (uintptr_t)bufptr
, bufsize
);
5474 auio
->uio_offset
= uio
->uio_offset
;
5476 error
= VNOP_READDIR(vp
, auio
, 0, eofflag
, numdirent
, ctxp
);
5478 dep
= (struct dirent
*)bufptr
;
5479 bytesread
= bufsize
- uio_resid(auio
);
5482 * Convert all the entries and copy them out to user's buffer.
5484 while (error
== 0 && (char *)dep
< ((char *)bufptr
+ bytesread
)) {
5485 /* Convert a dirent to a dirent64. */
5486 entry64
.d_ino
= dep
->d_ino
;
5487 entry64
.d_seekoff
= 0;
5488 entry64
.d_reclen
= DIRENT64_LEN(dep
->d_namlen
);
5489 entry64
.d_namlen
= dep
->d_namlen
;
5490 entry64
.d_type
= dep
->d_type
;
5491 bcopy(dep
->d_name
, entry64
.d_name
, dep
->d_namlen
+ 1);
5493 /* Move to next entry. */
5494 dep
= (struct dirent
*)((char *)dep
+ dep
->d_reclen
);
5496 /* Copy entry64 to user's buffer. */
5497 error
= uiomove((caddr_t
)&entry64
, entry64
.d_reclen
, uio
);
5500 /* Update the real offset using the offset we got from VNOP_READDIR. */
5502 uio
->uio_offset
= auio
->uio_offset
;
5505 FREE(bufptr
, M_TEMP
);
5511 * Read a block of directory entries in a file system independent format.
5514 getdirentries_common(int fd
, user_addr_t bufp
, user_size_t bufsize
, ssize_t
*bytesread
,
5515 off_t
*offset
, int flags
)
5518 struct vfs_context context
= *vfs_context_current(); /* local copy */
5519 struct fileproc
*fp
;
5521 int spacetype
= proc_is64bit(vfs_context_proc(&context
)) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5523 int error
, eofflag
, numdirent
;
5524 char uio_buf
[ UIO_SIZEOF(1) ];
5526 error
= fp_getfvp(vfs_context_proc(&context
), fd
, &fp
, &vp
);
5530 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
5531 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
5537 error
= mac_file_check_change_offset(vfs_context_ucred(&context
), fp
->f_fglob
);
5541 if ( (error
= vnode_getwithref(vp
)) ) {
5544 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
5547 if (vp
->v_type
!= VDIR
) {
5548 (void)vnode_put(vp
);
5554 error
= mac_vnode_check_readdir(&context
, vp
);
5556 (void)vnode_put(vp
);
5561 loff
= fp
->f_fglob
->fg_offset
;
5562 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
5563 uio_addiov(auio
, bufp
, bufsize
);
5565 if (flags
& VNODE_READDIR_EXTENDED
) {
5566 error
= vnode_readdir64(vp
, auio
, flags
, &eofflag
, &numdirent
, &context
);
5567 fp
->f_fglob
->fg_offset
= uio_offset(auio
);
5569 error
= VNOP_READDIR(vp
, auio
, 0, &eofflag
, &numdirent
, &context
);
5570 fp
->f_fglob
->fg_offset
= uio_offset(auio
);
5573 (void)vnode_put(vp
);
5577 if ((user_ssize_t
)bufsize
== uio_resid(auio
)){
5578 if (union_dircheckp
) {
5579 error
= union_dircheckp(&vp
, fp
, &context
);
5586 if ((vp
->v_flag
& VROOT
) && (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
5587 struct vnode
*tvp
= vp
;
5588 vp
= vp
->v_mount
->mnt_vnodecovered
;
5589 vnode_getwithref(vp
);
5591 fp
->f_fglob
->fg_data
= (caddr_t
) vp
;
5592 fp
->f_fglob
->fg_offset
= 0;
5603 // LP64todo - fix this
5604 *bytesread
= bufsize
- uio_resid(auio
);
5612 getdirentries(__unused
struct proc
*p
, struct getdirentries_args
*uap
, register_t
*retval
)
5619 AUDIT_ARG(fd
, uap
->fd
);
5620 error
= getdirentries_common(uap
->fd
, uap
->buf
, uap
->count
, &bytesread
, &offset
, 0);
5623 loff
= (long)offset
;
5624 error
= copyout((caddr_t
)&loff
, uap
->basep
, sizeof(long));
5625 *retval
= bytesread
;
5631 getdirentries64(__unused
struct proc
*p
, struct getdirentries64_args
*uap
, user_ssize_t
*retval
)
5637 AUDIT_ARG(fd
, uap
->fd
);
5638 error
= getdirentries_common(uap
->fd
, uap
->buf
, uap
->bufsize
, &bytesread
, &offset
, VNODE_READDIR_EXTENDED
);
5641 *retval
= bytesread
;
5642 error
= copyout((caddr_t
)&offset
, uap
->position
, sizeof(off_t
));
5649 * Set the mode mask for creation of filesystem nodes.
5651 #warning XXX implement xsecurity
5653 #define UMASK_NOXSECURITY (void *)1 /* leave existing xsecurity alone */
5655 umask1(proc_t p
, int newmask
, __unused kauth_filesec_t fsec
, register_t
*retval
)
5657 struct filedesc
*fdp
;
5659 AUDIT_ARG(mask
, newmask
);
5662 *retval
= fdp
->fd_cmask
;
5663 fdp
->fd_cmask
= newmask
& ALLPERMS
;
5670 umask_extended(proc_t p
, struct umask_extended_args
*uap
, register_t
*retval
)
5673 kauth_filesec_t xsecdst
;
5675 xsecdst
= KAUTH_FILESEC_NONE
;
5676 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
5677 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
5680 xsecdst
= KAUTH_FILESEC_NONE
;
5683 ciferror
= umask1(p
, uap
->newmask
, xsecdst
, retval
);
5685 if (xsecdst
!= KAUTH_FILESEC_NONE
)
5686 kauth_filesec_free(xsecdst
);
5691 umask(proc_t p
, struct umask_args
*uap
, register_t
*retval
)
5693 return(umask1(p
, uap
->newmask
, UMASK_NOXSECURITY
, retval
));
5697 * Void all references to file by ripping underlying filesystem
5702 revoke(proc_t p
, struct revoke_args
*uap
, __unused register_t
*retval
)
5705 struct vnode_attr va
;
5706 vfs_context_t ctx
= vfs_context_current();
5708 struct nameidata nd
;
5710 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
5711 UIO_USERSPACE
, uap
->path
, ctx
);
5720 error
= mac_vnode_check_revoke(ctx
, vp
);
5726 VATTR_WANTED(&va
, va_uid
);
5727 if ((error
= vnode_getattr(vp
, &va
, ctx
)))
5729 if (kauth_cred_getuid(vfs_context_ucred(ctx
)) != va
.va_uid
&&
5730 (error
= suser(vfs_context_ucred(ctx
), &p
->p_acflag
)))
5732 if (vp
->v_usecount
> 1 || (vp
->v_flag
& VALIASED
))
5733 VNOP_REVOKE(vp
, REVOKEALL
, ctx
);
5741 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
5742 * The following system calls are designed to support features
5743 * which are specific to the HFS & HFS Plus volume formats
5746 #ifdef __APPLE_API_OBSOLETE
5748 /************************************************/
5749 /* *** Following calls will be deleted soon *** */
5750 /************************************************/
5753 * Make a complex file. A complex file is one with multiple forks (data streams)
5757 mkcomplex(__unused proc_t p
, __unused
struct mkcomplex_args
*uap
, __unused register_t
*retval
)
5763 * Extended stat call which returns volumeid and vnodeid as well as other info
5767 statv(__unused proc_t p
,
5768 __unused
struct statv_args
*uap
,
5769 __unused register_t
*retval
)
5771 return (ENOTSUP
); /* We'll just return an error for now */
5773 } /* end of statv system call */
5776 * Extended lstat call which returns volumeid and vnodeid as well as other info
5780 lstatv(__unused proc_t p
,
5781 __unused
struct lstatv_args
*uap
,
5782 __unused register_t
*retval
)
5784 return (ENOTSUP
); /* We'll just return an error for now */
5785 } /* end of lstatv system call */
5788 * Extended fstat call which returns volumeid and vnodeid as well as other info
5792 fstatv(__unused proc_t p
,
5793 __unused
struct fstatv_args
*uap
,
5794 __unused register_t
*retval
)
5796 return (ENOTSUP
); /* We'll just return an error for now */
5797 } /* end of fstatv system call */
5800 /************************************************/
5801 /* *** Preceding calls will be deleted soon *** */
5802 /************************************************/
5804 #endif /* __APPLE_API_OBSOLETE */
5807 * Obtain attribute information on objects in a directory while enumerating
5808 * the directory. This call does not yet support union mounted directories.
5810 * 1.union mounted directories.
5815 getdirentriesattr (proc_t p
, struct getdirentriesattr_args
*uap
, register_t
*retval
)
5818 struct fileproc
*fp
;
5820 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5825 struct attrlist attributelist
;
5826 vfs_context_t ctx
= vfs_context_current();
5828 char uio_buf
[ UIO_SIZEOF(1) ];
5829 kauth_action_t action
;
5833 /* Get the attributes into kernel space */
5834 if ((error
= copyin(uap
->alist
, (caddr_t
)&attributelist
, sizeof(attributelist
)))) {
5837 if ((error
= copyin(uap
->count
, (caddr_t
)&count
, sizeof(count
)))) {
5840 if ( (error
= fp_getfvp(p
, fd
, &fp
, &vp
)) ) {
5843 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
5844 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
5851 error
= mac_file_check_change_offset(vfs_context_ucred(ctx
),
5858 if ( (error
= vnode_getwithref(vp
)) )
5861 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
5863 if (vp
->v_type
!= VDIR
) {
5864 (void)vnode_put(vp
);
5870 error
= mac_vnode_check_readdir(ctx
, vp
);
5872 (void)vnode_put(vp
);
5877 /* set up the uio structure which will contain the users return buffer */
5878 loff
= fp
->f_fglob
->fg_offset
;
5879 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
5880 &uio_buf
[0], sizeof(uio_buf
));
5881 uio_addiov(auio
, uap
->buffer
, uap
->buffersize
);
5884 * If the only item requested is file names, we can let that past with
5885 * just LIST_DIRECTORY. If they want any other attributes, that means
5886 * they need SEARCH as well.
5888 action
= KAUTH_VNODE_LIST_DIRECTORY
;
5889 if ((attributelist
.commonattr
& ~ATTR_CMN_NAME
) ||
5890 attributelist
.fileattr
|| attributelist
.dirattr
)
5891 action
|= KAUTH_VNODE_SEARCH
;
5893 if ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) == 0) {
5894 u_long ulcount
= count
;
5896 error
= VNOP_READDIRATTR(vp
, &attributelist
, auio
,
5898 uap
->options
, (unsigned long *)&newstate
, &eofflag
,
5903 (void)vnode_put(vp
);
5907 fp
->f_fglob
->fg_offset
= uio_offset(auio
); /* should be multiple of dirent, not variable */
5909 if ((error
= copyout((caddr_t
) &count
, uap
->count
, sizeof(count
))))
5911 if ((error
= copyout((caddr_t
) &newstate
, uap
->newstate
, sizeof(newstate
))))
5913 if ((error
= copyout((caddr_t
) &loff
, uap
->basep
, sizeof(loff
))))
5916 *retval
= eofflag
; /* similar to getdirentries */
5920 return (error
); /* return error earlier, an retval of 0 or 1 now */
5922 } /* end of getdirentryattr system call */
5925 * Exchange data between two files
5930 exchangedata (__unused proc_t p
, struct exchangedata_args
*uap
, __unused register_t
*retval
)
5933 struct nameidata fnd
, snd
;
5934 vfs_context_t ctx
= vfs_context_current();
5942 fse_info f_finfo
, s_finfo
;
5945 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
5947 NDINIT(&fnd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
5948 UIO_USERSPACE
, uap
->path1
, ctx
);
5950 error
= namei(&fnd
);
5957 NDINIT(&snd
, LOOKUP
| CN_NBMOUNTLOOK
, nameiflags
| AUDITVNPATH2
,
5958 UIO_USERSPACE
, uap
->path2
, ctx
);
5960 error
= namei(&snd
);
5969 * if the files are the same, return an inval error
5977 * if the files are on different volumes, return an error
5979 if (svp
->v_mount
!= fvp
->v_mount
) {
5985 error
= mac_vnode_check_exchangedata(ctx
,
5990 if (((error
= vnode_authorize(fvp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, ctx
)) != 0) ||
5991 ((error
= vnode_authorize(svp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, ctx
)) != 0))
5996 need_fsevent(FSE_EXCHANGE
, fvp
) ||
5998 kauth_authorize_fileop_has_listeners()) {
6001 if (fpath
== NULL
|| spath
== NULL
) {
6007 if (vn_getpath(fvp
, fpath
, &flen
) != 0 || fpath
[0] == '\0') {
6008 printf("exchange: vn_getpath(fvp=%p) failed <<%s>>\n",
6011 if (vn_getpath(svp
, spath
, &slen
) != 0 || spath
[0] == '\0') {
6012 printf("exchange: vn_getpath(svp=%p) failed <<%s>>\n",
6016 get_fse_info(fvp
, &f_finfo
, ctx
);
6017 get_fse_info(svp
, &s_finfo
, ctx
);
6020 /* Ok, make the call */
6021 error
= VNOP_EXCHANGE(fvp
, svp
, 0, ctx
);
6024 const char *tmpname
;
6026 if (fpath
!= NULL
&& spath
!= NULL
) {
6027 /* call out to allow 3rd party notification of exchangedata.
6028 * Ignore result of kauth_authorize_fileop call.
6030 kauth_authorize_fileop(vfs_context_ucred(ctx
), KAUTH_FILEOP_EXCHANGE
,
6031 (uintptr_t)fpath
, (uintptr_t)spath
);
6035 tmpname
= fvp
->v_name
;
6036 fvp
->v_name
= svp
->v_name
;
6037 svp
->v_name
= tmpname
;
6039 if (fvp
->v_parent
!= svp
->v_parent
) {
6042 tmp
= fvp
->v_parent
;
6043 fvp
->v_parent
= svp
->v_parent
;
6044 svp
->v_parent
= tmp
;
6046 name_cache_unlock();
6049 if (fpath
!= NULL
&& spath
!= NULL
) {
6050 add_fsevent(FSE_EXCHANGE
, ctx
,
6051 FSE_ARG_STRING
, flen
, fpath
,
6052 FSE_ARG_FINFO
, &f_finfo
,
6053 FSE_ARG_STRING
, slen
, spath
,
6054 FSE_ARG_FINFO
, &s_finfo
,
6062 RELEASE_PATH(fpath
);
6064 RELEASE_PATH(spath
);
6075 searchfs(proc_t p
, struct searchfs_args
*uap
, __unused register_t
*retval
)
6080 struct nameidata nd
;
6081 struct user_fssearchblock searchblock
;
6082 struct searchstate
*state
;
6083 struct attrlist
*returnattrs
;
6084 void *searchparams1
,*searchparams2
;
6086 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6090 vfs_context_t ctx
= vfs_context_current();
6091 char uio_buf
[ UIO_SIZEOF(1) ];
6093 /* Start by copying in fsearchblock paramater list */
6094 if (IS_64BIT_PROCESS(p
)) {
6095 error
= copyin(uap
->searchblock
, (caddr_t
) &searchblock
, sizeof(searchblock
));
6098 struct fssearchblock tmp_searchblock
;
6099 error
= copyin(uap
->searchblock
, (caddr_t
) &tmp_searchblock
, sizeof(tmp_searchblock
));
6100 // munge into 64-bit version
6101 searchblock
.returnattrs
= CAST_USER_ADDR_T(tmp_searchblock
.returnattrs
);
6102 searchblock
.returnbuffer
= CAST_USER_ADDR_T(tmp_searchblock
.returnbuffer
);
6103 searchblock
.returnbuffersize
= tmp_searchblock
.returnbuffersize
;
6104 searchblock
.maxmatches
= tmp_searchblock
.maxmatches
;
6105 searchblock
.timelimit
.tv_sec
= tmp_searchblock
.timelimit
.tv_sec
;
6106 searchblock
.timelimit
.tv_usec
= tmp_searchblock
.timelimit
.tv_usec
;
6107 searchblock
.searchparams1
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams1
);
6108 searchblock
.sizeofsearchparams1
= tmp_searchblock
.sizeofsearchparams1
;
6109 searchblock
.searchparams2
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams2
);
6110 searchblock
.sizeofsearchparams2
= tmp_searchblock
.sizeofsearchparams2
;
6111 searchblock
.searchattrs
= tmp_searchblock
.searchattrs
;
6116 /* Do a sanity check on sizeofsearchparams1 and sizeofsearchparams2.
6118 if (searchblock
.sizeofsearchparams1
> SEARCHFS_MAX_SEARCHPARMS
||
6119 searchblock
.sizeofsearchparams2
> SEARCHFS_MAX_SEARCHPARMS
)
6122 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
6123 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
6124 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
6127 mallocsize
= searchblock
.sizeofsearchparams1
+ searchblock
.sizeofsearchparams2
+
6128 sizeof(struct attrlist
) + sizeof(struct searchstate
);
6130 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
6132 /* Now set up the various pointers to the correct place in our newly allocated memory */
6134 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
6135 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
6136 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
6138 /* Now copy in the stuff given our local variables. */
6140 if ((error
= copyin(searchblock
.searchparams1
, searchparams1
, searchblock
.sizeofsearchparams1
)))
6143 if ((error
= copyin(searchblock
.searchparams2
, searchparams2
, searchblock
.sizeofsearchparams2
)))
6146 if ((error
= copyin(searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
))))
6149 if ((error
= copyin(uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
))))
6152 /* set up the uio structure which will contain the users return buffer */
6154 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
6155 &uio_buf
[0], sizeof(uio_buf
));
6156 uio_addiov(auio
, searchblock
.returnbuffer
, searchblock
.returnbuffersize
);
6159 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
6160 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
6161 UIO_USERSPACE
, uap
->path
, ctx
);
6172 * If searchblock.maxmatches == 0, then skip the search. This has happened
6173 * before and sometimes the underlyning code doesnt deal with it well.
6175 if (searchblock
.maxmatches
== 0) {
6181 Allright, we have everything we need, so lets make that call.
6183 We keep special track of the return value from the file system:
6184 EAGAIN is an acceptable error condition that shouldn't keep us
6185 from copying out any results...
6188 fserror
= VNOP_SEARCHFS(vp
,
6191 &searchblock
.searchattrs
,
6192 searchblock
.maxmatches
,
6193 &searchblock
.timelimit
,
6206 /* Now copy out the stuff that needs copying out. That means the number of matches, the
6207 search state. Everything was already put into he return buffer by the vop call. */
6209 if ((error
= copyout((caddr_t
) state
, uap
->state
, sizeof(struct searchstate
))) != 0)
6212 if ((error
= suulong(uap
->nummatches
, (uint64_t)nummatches
)) != 0)
6219 FREE(searchparams1
,M_TEMP
);
6224 } /* end of searchfs system call */
6228 * Make a filesystem-specific control call:
6232 fsctl (proc_t p
, struct fsctl_args
*uap
, __unused register_t
*retval
)
6236 struct nameidata nd
;
6238 u_long cmd
= uap
->cmd
;
6240 #define STK_PARAMS 128
6241 char stkbuf
[STK_PARAMS
];
6243 vfs_context_t ctx
= vfs_context_current();
6245 size
= IOCPARM_LEN(cmd
);
6246 if (size
> IOCPARM_MAX
) return (EINVAL
);
6248 is64bit
= proc_is64bit(p
);
6251 if (size
> sizeof (stkbuf
)) {
6252 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
6260 error
= copyin(uap
->data
, data
, size
);
6261 if (error
) goto FSCtl_Exit
;
6264 *(user_addr_t
*)data
= uap
->data
;
6267 *(uint32_t *)data
= (uint32_t)uap
->data
;
6270 } else if ((cmd
& IOC_OUT
) && size
) {
6272 * Zero the buffer so the user always
6273 * gets back something deterministic.
6276 } else if (cmd
& IOC_VOID
) {
6278 *(user_addr_t
*)data
= uap
->data
;
6281 *(uint32_t *)data
= (uint32_t)uap
->data
;
6285 /* Get the vnode for the file we are getting info on: */
6287 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
6288 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, uap
->path
, ctx
);
6289 if ((error
= namei(&nd
))) goto FSCtl_Exit
;
6292 error
= mac_mount_check_fsctl(ctx
, vnode_mount(nd
.ni_vp
), cmd
);
6294 vnode_put(nd
.ni_vp
);
6300 /* Invoke the filesystem-specific code */
6301 error
= VNOP_IOCTL(nd
.ni_vp
, IOCBASECMD(cmd
), data
, uap
->options
, ctx
);
6303 vnode_put(nd
.ni_vp
);
6307 * Copy any data to user, size was
6308 * already set and checked above.
6310 if (error
== 0 && (cmd
& IOC_OUT
) && size
)
6311 error
= copyout(data
, uap
->data
, size
);
6314 if (memp
) kfree(memp
, size
);
6318 /* end of fsctl system call */
6321 * An in-kernel sync for power management to call.
6323 __private_extern__
int
6328 struct sync_args data
;
6333 error
= sync(current_proc(), &data
, &retval
[0]);
6337 } /* end of sync_internal call */
6341 * Retrieve the data of an extended attribute.
6344 getxattr(proc_t p
, struct getxattr_args
*uap
, user_ssize_t
*retval
)
6347 struct nameidata nd
;
6348 char attrname
[XATTR_MAXNAMELEN
+1];
6349 vfs_context_t ctx
= vfs_context_current();
6351 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6352 size_t attrsize
= 0;
6356 char uio_buf
[ UIO_SIZEOF(1) ];
6358 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6361 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
6362 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, ctx
);
6363 if ((error
= namei(&nd
))) {
6369 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
6372 if (xattr_protected(attrname
)) {
6376 if (uap
->value
&& uap
->size
> 0) {
6377 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
6378 &uio_buf
[0], sizeof(uio_buf
));
6379 uio_addiov(auio
, uap
->value
, uap
->size
);
6382 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, ctx
);
6387 *retval
= uap
->size
- uio_resid(auio
);
6389 *retval
= (user_ssize_t
)attrsize
;
6396 * Retrieve the data of an extended attribute.
6399 fgetxattr(proc_t p
, struct fgetxattr_args
*uap
, user_ssize_t
*retval
)
6402 char attrname
[XATTR_MAXNAMELEN
+1];
6404 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6405 size_t attrsize
= 0;
6408 char uio_buf
[ UIO_SIZEOF(1) ];
6410 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6413 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
6416 if ( (error
= vnode_getwithref(vp
)) ) {
6420 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
6423 if (xattr_protected(attrname
)) {
6427 if (uap
->value
&& uap
->size
> 0) {
6428 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
6429 &uio_buf
[0], sizeof(uio_buf
));
6430 uio_addiov(auio
, uap
->value
, uap
->size
);
6433 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, vfs_context_current());
6435 (void)vnode_put(vp
);
6439 *retval
= uap
->size
- uio_resid(auio
);
6441 *retval
= (user_ssize_t
)attrsize
;
6447 * Set the data of an extended attribute.
6450 setxattr(proc_t p
, struct setxattr_args
*uap
, int *retval
)
6453 struct nameidata nd
;
6454 char attrname
[XATTR_MAXNAMELEN
+1];
6455 vfs_context_t ctx
= vfs_context_current();
6457 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6461 char uio_buf
[ UIO_SIZEOF(1) ];
6463 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6466 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
6469 if (xattr_protected(attrname
))
6471 if (uap
->size
!= 0 && uap
->value
== 0) {
6475 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
6476 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, ctx
);
6477 if ((error
= namei(&nd
))) {
6483 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
6484 &uio_buf
[0], sizeof(uio_buf
));
6485 uio_addiov(auio
, uap
->value
, uap
->size
);
6487 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, ctx
);
6490 add_fsevent(FSE_XATTR_MODIFIED
, ctx
,
6501 * Set the data of an extended attribute.
6504 fsetxattr(proc_t p
, struct fsetxattr_args
*uap
, int *retval
)
6507 char attrname
[XATTR_MAXNAMELEN
+1];
6509 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6512 char uio_buf
[ UIO_SIZEOF(1) ];
6513 vfs_context_t ctx
= vfs_context_current();
6515 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6518 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
6521 if (xattr_protected(attrname
))
6523 if (uap
->size
!= 0 && uap
->value
== 0) {
6526 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
6529 if ( (error
= vnode_getwithref(vp
)) ) {
6533 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
6534 &uio_buf
[0], sizeof(uio_buf
));
6535 uio_addiov(auio
, uap
->value
, uap
->size
);
6537 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, vfs_context_current());
6540 add_fsevent(FSE_XATTR_MODIFIED
, ctx
,
6552 * Remove an extended attribute.
6554 #warning "code duplication"
6556 removexattr(proc_t p
, struct removexattr_args
*uap
, int *retval
)
6559 struct nameidata nd
;
6560 char attrname
[XATTR_MAXNAMELEN
+1];
6561 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6562 vfs_context_t ctx
= vfs_context_current();
6567 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6570 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
6574 if (xattr_protected(attrname
))
6576 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
6577 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, ctx
);
6578 if ((error
= namei(&nd
))) {
6584 error
= vn_removexattr(vp
, attrname
, uap
->options
, ctx
);
6587 add_fsevent(FSE_XATTR_REMOVED
, ctx
,
6598 * Remove an extended attribute.
6600 #warning "code duplication"
6602 fremovexattr(__unused proc_t p
, struct fremovexattr_args
*uap
, int *retval
)
6605 char attrname
[XATTR_MAXNAMELEN
+1];
6608 vfs_context_t ctx
= vfs_context_current();
6610 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6613 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
6617 if (xattr_protected(attrname
))
6619 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
6622 if ( (error
= vnode_getwithref(vp
)) ) {
6627 error
= vn_removexattr(vp
, attrname
, uap
->options
, vfs_context_current());
6630 add_fsevent(FSE_XATTR_REMOVED
, ctx
,
6642 * Retrieve the list of extended attribute names.
6644 #warning "code duplication"
6646 listxattr(proc_t p
, struct listxattr_args
*uap
, user_ssize_t
*retval
)
6649 struct nameidata nd
;
6650 vfs_context_t ctx
= vfs_context_current();
6652 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6653 size_t attrsize
= 0;
6656 char uio_buf
[ UIO_SIZEOF(1) ];
6658 if (uap
->options
& (XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6661 nameiflags
= ((uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
) | NOTRIGGER
;
6662 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, ctx
);
6663 if ((error
= namei(&nd
))) {
6668 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
6669 // LP64todo - fix this!
6670 auio
= uio_createwithbuffer(1, 0, spacetype
,
6671 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
6672 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
6675 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, ctx
);
6679 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
6681 *retval
= (user_ssize_t
)attrsize
;
6687 * Retrieve the list of extended attribute names.
6689 #warning "code duplication"
6691 flistxattr(proc_t p
, struct flistxattr_args
*uap
, user_ssize_t
*retval
)
6695 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
6696 size_t attrsize
= 0;
6698 char uio_buf
[ UIO_SIZEOF(1) ];
6700 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
| XATTR_NODEFAULT
))
6703 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
6706 if ( (error
= vnode_getwithref(vp
)) ) {
6710 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
6711 // LP64todo - fix this!
6712 auio
= uio_createwithbuffer(1, 0, spacetype
,
6713 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
6714 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
6717 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, vfs_context_current());
6722 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
6724 *retval
= (user_ssize_t
)attrsize
;
6730 * Common routine to handle various flavors of statfs data heading out
6733 * Returns: 0 Success
6737 munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
6738 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
6739 boolean_t partial_copy
)
6742 int my_size
, copy_size
;
6745 struct user_statfs sfs
;
6746 my_size
= copy_size
= sizeof(sfs
);
6747 bzero(&sfs
, my_size
);
6748 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
6749 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
6750 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
6751 sfs
.f_bsize
= (user_long_t
)sfsp
->f_bsize
;
6752 sfs
.f_iosize
= (user_long_t
)sfsp
->f_iosize
;
6753 sfs
.f_blocks
= (user_long_t
)sfsp
->f_blocks
;
6754 sfs
.f_bfree
= (user_long_t
)sfsp
->f_bfree
;
6755 sfs
.f_bavail
= (user_long_t
)sfsp
->f_bavail
;
6756 sfs
.f_files
= (user_long_t
)sfsp
->f_files
;
6757 sfs
.f_ffree
= (user_long_t
)sfsp
->f_ffree
;
6758 sfs
.f_fsid
= sfsp
->f_fsid
;
6759 sfs
.f_owner
= sfsp
->f_owner
;
6760 strlcpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
);
6761 strlcpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
);
6762 strlcpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
);
6765 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
6767 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
6771 my_size
= copy_size
= sizeof(sfs
);
6772 bzero(&sfs
, my_size
);
6774 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
6775 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
6776 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
6779 * It's possible for there to be more than 2^^31 blocks in the filesystem, so we
6780 * have to fudge the numbers here in that case. We inflate the blocksize in order
6781 * to reflect the filesystem size as best we can.
6783 if ((sfsp
->f_blocks
> LONG_MAX
)
6784 /* Hack for 4061702 . I think the real fix is for Carbon to
6785 * look for some volume capability and not depend on hidden
6786 * semantics agreed between a FS and carbon.
6787 * f_blocks, f_bfree, and f_bavail set to -1 is the trigger
6788 * for Carbon to set bNoVolumeSizes volume attribute.
6789 * Without this the webdavfs files cannot be copied onto
6790 * disk as they look huge. This change should not affect
6791 * XSAN as they should not setting these to -1..
6793 && (sfsp
->f_blocks
!= 0xffffffffffffffffULL
)
6794 && (sfsp
->f_bfree
!= 0xffffffffffffffffULL
)
6795 && (sfsp
->f_bavail
!= 0xffffffffffffffffULL
)) {
6799 * Work out how far we have to shift the block count down to make it fit.
6800 * Note that it's possible to have to shift so far that the resulting
6801 * blocksize would be unreportably large. At that point, we will clip
6802 * any values that don't fit.
6804 * For safety's sake, we also ensure that f_iosize is never reported as
6805 * being smaller than f_bsize.
6807 for (shift
= 0; shift
< 32; shift
++) {
6808 if ((sfsp
->f_blocks
>> shift
) <= LONG_MAX
)
6810 if ((sfsp
->f_bsize
<< (shift
+ 1)) > LONG_MAX
)
6813 #define __SHIFT_OR_CLIP(x, s) ((((x) >> (s)) > LONG_MAX) ? LONG_MAX : ((x) >> (s)))
6814 sfs
.f_blocks
= (long)__SHIFT_OR_CLIP(sfsp
->f_blocks
, shift
);
6815 sfs
.f_bfree
= (long)__SHIFT_OR_CLIP(sfsp
->f_bfree
, shift
);
6816 sfs
.f_bavail
= (long)__SHIFT_OR_CLIP(sfsp
->f_bavail
, shift
);
6817 #undef __SHIFT_OR_CLIP
6818 sfs
.f_bsize
= (long)(sfsp
->f_bsize
<< shift
);
6819 sfs
.f_iosize
= lmax(sfsp
->f_iosize
, sfsp
->f_bsize
);
6821 /* filesystem is small enough to be reported honestly */
6822 sfs
.f_bsize
= (long)sfsp
->f_bsize
;
6823 sfs
.f_iosize
= (long)sfsp
->f_iosize
;
6824 sfs
.f_blocks
= (long)sfsp
->f_blocks
;
6825 sfs
.f_bfree
= (long)sfsp
->f_bfree
;
6826 sfs
.f_bavail
= (long)sfsp
->f_bavail
;
6828 sfs
.f_files
= (long)sfsp
->f_files
;
6829 sfs
.f_ffree
= (long)sfsp
->f_ffree
;
6830 sfs
.f_fsid
= sfsp
->f_fsid
;
6831 sfs
.f_owner
= sfsp
->f_owner
;
6832 strlcpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
);
6833 strlcpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
);
6834 strlcpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
);
6837 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
6839 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
6842 if (sizep
!= NULL
) {
6849 * copy stat structure into user_stat structure.
6851 void munge_stat(struct stat
*sbp
, struct user_stat
*usbp
)
6853 bzero(usbp
, sizeof(struct user_stat
));
6855 usbp
->st_dev
= sbp
->st_dev
;
6856 usbp
->st_ino
= sbp
->st_ino
;
6857 usbp
->st_mode
= sbp
->st_mode
;
6858 usbp
->st_nlink
= sbp
->st_nlink
;
6859 usbp
->st_uid
= sbp
->st_uid
;
6860 usbp
->st_gid
= sbp
->st_gid
;
6861 usbp
->st_rdev
= sbp
->st_rdev
;
6862 #ifndef _POSIX_C_SOURCE
6863 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
6864 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
6865 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
6866 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
6867 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
6868 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
6870 usbp
->st_atime
= sbp
->st_atime
;
6871 usbp
->st_atimensec
= sbp
->st_atimensec
;
6872 usbp
->st_mtime
= sbp
->st_mtime
;
6873 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
6874 usbp
->st_ctime
= sbp
->st_ctime
;
6875 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
6877 usbp
->st_size
= sbp
->st_size
;
6878 usbp
->st_blocks
= sbp
->st_blocks
;
6879 usbp
->st_blksize
= sbp
->st_blksize
;
6880 usbp
->st_flags
= sbp
->st_flags
;
6881 usbp
->st_gen
= sbp
->st_gen
;
6882 usbp
->st_lspare
= sbp
->st_lspare
;
6883 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
6884 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];
6888 * copy stat64 structure into user_stat64 structure.
6890 void munge_stat64(struct stat64
*sbp
, struct user_stat64
*usbp
)
6892 bzero(usbp
, sizeof(struct user_stat
));
6894 usbp
->st_dev
= sbp
->st_dev
;
6895 usbp
->st_ino
= sbp
->st_ino
;
6896 usbp
->st_mode
= sbp
->st_mode
;
6897 usbp
->st_nlink
= sbp
->st_nlink
;
6898 usbp
->st_uid
= sbp
->st_uid
;
6899 usbp
->st_gid
= sbp
->st_gid
;
6900 usbp
->st_rdev
= sbp
->st_rdev
;
6901 #ifndef _POSIX_C_SOURCE
6902 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
6903 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
6904 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
6905 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
6906 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
6907 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
6908 usbp
->st_birthtimespec
.tv_sec
= sbp
->st_birthtimespec
.tv_sec
;
6909 usbp
->st_birthtimespec
.tv_nsec
= sbp
->st_birthtimespec
.tv_nsec
;
6911 usbp
->st_atime
= sbp
->st_atime
;
6912 usbp
->st_atimensec
= sbp
->st_atimensec
;
6913 usbp
->st_mtime
= sbp
->st_mtime
;
6914 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
6915 usbp
->st_ctime
= sbp
->st_ctime
;
6916 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
6917 usbp
->st_birthtime
= sbp
->st_birthtime
;
6918 usbp
->st_birthtimensec
= sbp
->st_birthtimensec
;
6920 usbp
->st_size
= sbp
->st_size
;
6921 usbp
->st_blocks
= sbp
->st_blocks
;
6922 usbp
->st_blksize
= sbp
->st_blksize
;
6923 usbp
->st_flags
= sbp
->st_flags
;
6924 usbp
->st_gen
= sbp
->st_gen
;
6925 usbp
->st_lspare
= sbp
->st_lspare
;
6926 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
6927 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];