2 * Copyright (c) 1995-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1989, 1993
24 * The Regents of the University of California. All rights reserved.
25 * (c) UNIX System Laboratories, Inc.
26 * All or some portions of this file are derived from material licensed
27 * to the University of California by American Telephone and Telegraph
28 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
29 * the permission of UNIX System Laboratories, Inc.
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed by the University of
42 * California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * @(#)vfs_syscalls.c 8.41 (Berkeley) 6/15/95
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/namei.h>
65 #include <sys/filedesc.h>
66 #include <sys/kernel.h>
67 #include <sys/file_internal.h>
69 #include <sys/vnode_internal.h>
70 #include <sys/mount_internal.h>
71 #include <sys/proc_internal.h>
72 #include <sys/kauth.h>
73 #include <sys/uio_internal.h>
74 #include <sys/malloc.h>
76 #include <sys/dirent.h>
78 #include <sys/sysctl.h>
80 #include <sys/quota.h>
81 #include <sys/kdebug.h>
82 #include <sys/fsevents.h>
83 #include <sys/sysproto.h>
84 #include <sys/xattr.h>
85 #include <sys/ubc_internal.h>
86 #include <machine/cons.h>
87 #include <machine/limits.h>
88 #include <miscfs/specfs/specdev.h>
90 #include <bsm/audit_kernel.h>
91 #include <bsm/audit_kevents.h>
93 #include <mach/mach_types.h>
94 #include <kern/kern_types.h>
95 #include <kern/kalloc.h>
97 #include <vm/vm_pageout.h>
99 #include <libkern/OSAtomic.h>
103 * The currently logged-in user, for ownership of files/directories whose on-disk
104 * permissions are ignored:
108 static int change_dir(struct nameidata
*ndp
, vfs_context_t ctx
);
109 static int checkdirs(vnode_t olddp
, vfs_context_t ctx
);
110 void enablequotas(struct mount
*mp
, vfs_context_t ctx
);
111 static int getfsstat_callback(mount_t mp
, void * arg
);
112 static int getutimes(user_addr_t usrtvp
, struct timespec
*tsp
);
113 static int setutimes(vfs_context_t ctx
, struct vnode
*vp
, const struct timespec
*ts
, int nullflag
);
114 static int sync_callback(mount_t
, void *);
115 static int munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
116 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
117 boolean_t partial_copy
);
119 __private_extern__
int sync_internal(void);
121 #ifdef __APPLE_API_OBSOLETE
123 int fd
; /* file descriptor of the target file */
124 struct vstat
*vsb
; /* vstat structure for returned info */
127 const char *path
; /* pathname of the target file */
128 struct vstat
*vsb
; /* vstat structure for returned info */
130 struct mkcomplex_args
{
131 const char *path
; /* pathname of the file to be created */
132 mode_t mode
; /* access mode for the newly created file */
133 u_long type
; /* format of the complex file */
136 const char *path
; /* pathname of the target file */
137 struct vstat
*vsb
; /* vstat structure for returned info */
140 int fstatv(struct proc
*p
, struct fstatv_args
*uap
, register_t
*retval
);
141 int lstatv(struct proc
*p
, struct lstatv_args
*uap
, register_t
*retval
);
142 int mkcomplex(struct proc
*p
, struct mkcomplex_args
*uap
, register_t
*retval
);
143 int statv(struct proc
*p
, struct statv_args
*uap
, register_t
*retval
);
145 #endif /* __APPLE_API_OBSOLETE */
148 extern int (**union_vnodeop_p
)(void *);
149 extern struct vnode
*union_dircache(struct vnode
*, struct proc
*);
152 /* counts number of mount and unmount operations */
153 unsigned int vfs_nummntops
=0;
155 extern struct fileops vnops
;
157 extern void mount_list_add(mount_t mp
);
158 extern void mount_list_remove(mount_t mp
);
159 extern int mount_refdrain(mount_t mp
);
160 extern int vcount(struct vnode
*vp
);
164 * Virtual File System System Calls
168 * Mount a file system.
172 mount(struct proc
*p
, register struct mount_args
*uap
, __unused register_t
*retval
)
175 struct vnode
*devvp
= NULLVP
;
176 struct vnode
*device_vnode
= NULLVP
;
178 struct vfstable
*vfsp
= (struct vfstable
*)0;
180 struct vnode_attr va
;
181 struct vfs_context context
;
183 struct nameidata nd1
;
184 char fstypename
[MFSNAMELEN
];
186 user_addr_t devpath
= USER_ADDR_NULL
;
187 user_addr_t fsmountargs
= uap
->data
;
192 boolean_t is_rwlock_locked
= FALSE
;
194 AUDIT_ARG(fflags
, uap
->flags
);
197 context
.vc_ucred
= kauth_cred_get();
198 is_64bit
= proc_is64bit(p
);
201 * Get vnode to be covered
203 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
204 UIO_USERSPACE
, uap
->path
, &context
);
210 if ((vp
->v_flag
& VROOT
) &&
211 (vp
->v_mount
->mnt_flag
& MNT_ROOTFS
))
212 uap
->flags
|= MNT_UPDATE
;
214 if (uap
->flags
& MNT_UPDATE
) {
215 if ((vp
->v_flag
& VROOT
) == 0) {
221 /* unmount in progress return error */
223 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
229 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
230 is_rwlock_locked
= TRUE
;
232 * We only allow the filesystem to be reloaded if it
233 * is currently mounted read-only.
235 if ((uap
->flags
& MNT_RELOAD
) &&
236 ((mp
->mnt_flag
& MNT_RDONLY
) == 0)) {
241 * Only root, or the user that did the original mount is
242 * permitted to update it.
244 if (mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(context
.vc_ucred
) &&
245 (error
= suser(context
.vc_ucred
, &p
->p_acflag
))) {
249 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV,
250 * and MNT_NOEXEC if mount point is already MNT_NOEXEC.
252 if (suser(context
.vc_ucred
, NULL
)) {
253 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
254 if (mp
->mnt_flag
& MNT_NOEXEC
)
255 uap
->flags
|= MNT_NOEXEC
;
260 uap
->flags
& (MNT_RELOAD
| MNT_FORCE
| MNT_UPDATE
);
262 vfsp
= mp
->mnt_vtable
;
266 * If the user is not root, ensure that they own the directory
267 * onto which we are attempting to mount.
270 VATTR_WANTED(&va
, va_uid
);
271 if ((error
= vnode_getattr(vp
, &va
, &context
)) ||
272 (va
.va_uid
!= kauth_cred_getuid(context
.vc_ucred
) &&
273 (error
= suser(context
.vc_ucred
, &p
->p_acflag
)))) {
277 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV, and
278 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
280 if (suser(context
.vc_ucred
, NULL
)) {
281 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
282 if (vp
->v_mount
->mnt_flag
& MNT_NOEXEC
)
283 uap
->flags
|= MNT_NOEXEC
;
285 if ( (error
= VNOP_FSYNC(vp
, MNT_WAIT
, &context
)) )
288 if ( (error
= buf_invalidateblks(vp
, BUF_WRITE_DATA
, 0, 0)) )
291 if (vp
->v_type
!= VDIR
) {
295 if ( (error
= copyinstr(uap
->type
, fstypename
, MFSNAMELEN
, &dummy
)) )
298 /* XXXAUDIT: Should we capture the type on the error path as well? */
299 AUDIT_ARG(text
, fstypename
);
301 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
302 if (!strcmp(vfsp
->vfc_name
, fstypename
))
309 if (ISSET(vp
->v_flag
, VMOUNT
) && (vp
->v_mountedhere
!= NULL
)) {
314 SET(vp
->v_flag
, VMOUNT
);
318 * Allocate and initialize the filesystem.
320 MALLOC_ZONE(mp
, struct mount
*, (u_long
)sizeof(struct mount
),
322 bzero((char *)mp
, (u_long
)sizeof(struct mount
));
325 /* Initialize the default IO constraints */
326 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
327 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
328 mp
->mnt_maxsegreadsize
= mp
->mnt_maxreadcnt
;
329 mp
->mnt_maxsegwritesize
= mp
->mnt_maxwritecnt
;
330 mp
->mnt_devblocksize
= DEV_BSIZE
;
332 TAILQ_INIT(&mp
->mnt_vnodelist
);
333 TAILQ_INIT(&mp
->mnt_workerqueue
);
334 TAILQ_INIT(&mp
->mnt_newvnodes
);
336 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
337 is_rwlock_locked
= TRUE
;
338 mp
->mnt_op
= vfsp
->vfc_vfsops
;
339 mp
->mnt_vtable
= vfsp
;
341 vfsp
->vfc_refcount
++;
343 //mp->mnt_stat.f_type = vfsp->vfc_typenum;
344 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
345 strncpy(mp
->mnt_vfsstat
.f_fstypename
, vfsp
->vfc_name
, MFSTYPENAMELEN
);
346 strncpy(mp
->mnt_vfsstat
.f_mntonname
, nd
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
347 mp
->mnt_vnodecovered
= vp
;
348 mp
->mnt_vfsstat
.f_owner
= kauth_cred_getuid(context
.vc_ucred
);
350 /* XXX 3762912 hack to support HFS filesystem 'owner' - filesystem may update later */
351 vfs_setowner(mp
, KAUTH_UID_NONE
, KAUTH_GID_NONE
);
355 * Set the mount level flags.
357 if (uap
->flags
& MNT_RDONLY
)
358 mp
->mnt_flag
|= MNT_RDONLY
;
359 else if (mp
->mnt_flag
& MNT_RDONLY
)
360 mp
->mnt_kern_flag
|= MNTK_WANTRDWR
;
361 mp
->mnt_flag
&= ~(MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
362 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
363 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
);
364 mp
->mnt_flag
|= uap
->flags
& (MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
365 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
366 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
|
369 if (vfsp
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
371 if ( (error
= copyin(fsmountargs
, (caddr_t
)&devpath
, sizeof(devpath
))) )
373 fsmountargs
+= sizeof(devpath
);
376 if ( (error
= copyin(fsmountargs
, (caddr_t
)&tmp
, sizeof(tmp
))) )
378 /* munge into LP64 addr */
379 devpath
= CAST_USER_ADDR_T(tmp
);
380 fsmountargs
+= sizeof(tmp
);
383 /* if it is not update and device name needs to be parsed */
385 NDINIT(&nd1
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, devpath
, &context
);
386 if ( (error
= namei(&nd1
)) )
389 strncpy(mp
->mnt_vfsstat
.f_mntfromname
, nd1
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
394 if (devvp
->v_type
!= VBLK
) {
398 if (major(devvp
->v_rdev
) >= nblkdev
) {
403 * If mount by non-root, then verify that user has necessary
404 * permissions on the device.
406 if (suser(context
.vc_ucred
, NULL
) != 0) {
407 accessmode
= KAUTH_VNODE_READ_DATA
;
408 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
409 accessmode
|= KAUTH_VNODE_WRITE_DATA
;
410 if ((error
= vnode_authorize(devvp
, NULL
, accessmode
, &context
)) != 0)
414 if (devpath
&& ((uap
->flags
& MNT_UPDATE
) == 0)) {
415 if ( (error
= vnode_ref(devvp
)) )
418 * Disallow multiple mounts of the same device.
419 * Disallow mounting of a device that is currently in use
420 * (except for root, which might share swap device for miniroot).
421 * Flush out any old buffers remaining from a previous use.
423 if ( (error
= vfs_mountedon(devvp
)) )
426 if (vcount(devvp
) > 1 && !(vfs_flags(mp
) & MNT_ROOTFS
)) {
430 if ( (error
= VNOP_FSYNC(devvp
, MNT_WAIT
, &context
)) ) {
434 if ( (error
= buf_invalidateblks(devvp
, BUF_WRITE_DATA
, 0, 0)) )
437 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
438 if ( (error
= VNOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, &context
)) )
441 mp
->mnt_devvp
= devvp
;
442 device_vnode
= devvp
;
444 if ((mp
->mnt_flag
& MNT_RDONLY
) && (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)) {
446 * If upgrade to read-write by non-root, then verify
447 * that user has necessary permissions on the device.
449 device_vnode
= mp
->mnt_devvp
;
450 if (device_vnode
&& suser(context
.vc_ucred
, NULL
)) {
451 if ((error
= vnode_authorize(device_vnode
, NULL
,
452 KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0)
456 device_vnode
= NULLVP
;
462 * Mount the filesystem.
464 error
= VFS_MOUNT(mp
, device_vnode
, fsmountargs
, &context
);
466 if (uap
->flags
& MNT_UPDATE
) {
467 if (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)
468 mp
->mnt_flag
&= ~MNT_RDONLY
;
470 (MNT_UPDATE
| MNT_RELOAD
| MNT_FORCE
);
471 mp
->mnt_kern_flag
&=~ MNTK_WANTRDWR
;
474 vfs_event_signal(NULL
, VQ_UPDATE
, (intptr_t)NULL
);
475 lck_rw_done(&mp
->mnt_rwlock
);
476 is_rwlock_locked
= FALSE
;
478 enablequotas(mp
,&context
);
482 * Put the new filesystem on the mount list after root.
486 CLR(vp
->v_flag
, VMOUNT
);
488 vp
->v_mountedhere
= mp
;
493 error
= checkdirs(vp
, &context
);
495 /* Unmount the filesystem as cdir/rdirs cannot be updated */
499 * there is no cleanup code here so I have made it void
500 * we need to revisit this
502 (void)VFS_START(mp
, 0, &context
);
505 lck_rw_done(&mp
->mnt_rwlock
);
506 is_rwlock_locked
= FALSE
;
508 /* increment the operations count */
509 OSAddAtomic(1, (SInt32
*)&vfs_nummntops
);
510 enablequotas(mp
,&context
);
513 device_vnode
->v_specflags
|= SI_MOUNTEDON
;
516 * cache the IO attributes for the underlying physical media...
517 * an error return indicates the underlying driver doesn't
518 * support all the queries necessary... however, reasonable
519 * defaults will have been set, so no reason to bail or care
521 vfs_init_io_attributes(device_vnode
, mp
);
524 /* Now that mount is setup, notify the listeners */
525 vfs_event_signal(NULL
, VQ_MOUNT
, (intptr_t)NULL
);
528 CLR(vp
->v_flag
, VMOUNT
);
531 mp
->mnt_vtable
->vfc_refcount
--;
535 VNOP_CLOSE(device_vnode
, ronly
? FREAD
: FREAD
|FWRITE
, &context
);
536 vnode_rele(device_vnode
);
538 lck_rw_done(&mp
->mnt_rwlock
);
539 is_rwlock_locked
= FALSE
;
540 mount_lock_destroy(mp
);
541 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
546 * drop I/O count on covered 'vp' and
547 * on the device vp if there was one
549 if (devpath
&& devvp
)
556 (void)VFS_UNMOUNT(mp
, MNT_FORCE
, &context
);
557 if (device_vnode
!= NULLVP
) {
558 VNOP_CLOSE(device_vnode
, mp
->mnt_flag
& MNT_RDONLY
? FREAD
: FREAD
|FWRITE
, &context
);
561 vp
->v_mountedhere
= (mount_t
) 0;
567 if (devpath
&& devvp
)
570 /* Release mnt_rwlock only when it was taken */
571 if (is_rwlock_locked
== TRUE
) {
572 lck_rw_done(&mp
->mnt_rwlock
);
576 vfsp
->vfc_refcount
--;
578 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
588 enablequotas(struct mount
*mp
, vfs_context_t context
)
590 struct nameidata qnd
;
592 char qfpath
[MAXPATHLEN
];
593 const char *qfname
= QUOTAFILENAME
;
594 const char *qfopsname
= QUOTAOPSNAME
;
595 const char *qfextension
[] = INITQFNAMES
;
597 if ((strcmp(mp
->mnt_vfsstat
.f_fstypename
, "hfs") != 0 )
598 && (strcmp( mp
->mnt_vfsstat
.f_fstypename
, "ufs") != 0))
602 * Enable filesystem disk quotas if necessary.
603 * We ignore errors as this should not interfere with final mount
605 for (type
=0; type
< MAXQUOTAS
; type
++) {
606 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfopsname
, qfextension
[type
]);
607 NDINIT(&qnd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE32
, CAST_USER_ADDR_T(qfpath
), context
);
608 if (namei(&qnd
) != 0)
609 continue; /* option file to trigger quotas is not present */
610 vnode_put(qnd
.ni_vp
);
612 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfname
, qfextension
[type
]);
614 (void) VFS_QUOTACTL(mp
, QCMD(Q_QUOTAON
, type
), 0, qfpath
, context
);
620 * Scan all active processes to see if any of them have a current
621 * or root directory onto which the new filesystem has just been
622 * mounted. If so, replace them with the new mount point.
625 checkdirs(olddp
, context
)
627 vfs_context_t context
;
629 struct filedesc
*fdp
;
633 struct vnode
*fdp_cvp
;
634 struct vnode
*fdp_rvp
;
635 int cdir_changed
= 0;
636 int rdir_changed
= 0;
637 boolean_t funnel_state
;
640 if (olddp
->v_usecount
== 1)
642 err
= VFS_ROOT(olddp
->v_mountedhere
, &newdp
, context
);
645 panic("mount: lost mount");
649 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
651 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
654 if (fdp
== (struct filedesc
*)0) {
658 fdp_cvp
= fdp
->fd_cdir
;
659 fdp_rvp
= fdp
->fd_rdir
;
662 if (fdp_cvp
== olddp
) {
669 if (fdp_rvp
== olddp
) {
676 if (cdir_changed
|| rdir_changed
) {
678 fdp
->fd_cdir
= fdp_cvp
;
679 fdp
->fd_rdir
= fdp_rvp
;
683 if (rootvnode
== olddp
) {
689 thread_funnel_set(kernel_flock
, funnel_state
);
696 * Unmount a file system.
698 * Note: unmount takes a path to the vnode mounted on as argument,
699 * not special file (as before).
703 unmount(struct proc
*p
, register struct unmount_args
*uap
, __unused register_t
*retval
)
705 register struct vnode
*vp
;
709 struct vfs_context context
;
712 context
.vc_ucred
= kauth_cred_get();
714 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
715 UIO_USERSPACE
, uap
->path
, &context
);
724 * Must be the root of the filesystem
726 if ((vp
->v_flag
& VROOT
) == 0) {
732 /* safedounmount consumes the mount ref */
733 return (safedounmount(mp
, uap
->flags
, p
));
737 * The mount struct comes with a mount ref which will be consumed.
738 * Do the actual file system unmount, prevent some common foot shooting.
740 * XXX Should take a "vfs_context_t" instead of a "struct proc *"
743 safedounmount(mp
, flags
, p
)
751 * Only root, or the user that did the original mount is
752 * permitted to unmount this filesystem.
754 if ((mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(kauth_cred_get())) &&
755 (error
= suser(kauth_cred_get(), &p
->p_acflag
))) {
760 * Don't allow unmounting the root file system.
762 if (mp
->mnt_flag
& MNT_ROOTFS
) {
767 return (dounmount(mp
, flags
, NULL
, 1, p
));
774 * Do the actual file system unmount.
777 dounmount(mp
, flags
, skiplistrmp
, withref
, p
)
778 register struct mount
*mp
;
784 struct vnode
*coveredvp
= (vnode_t
)0;
787 struct vfs_context context
;
788 int forcedunmount
= 0;
792 context
.vc_ucred
= kauth_cred_get();
794 if (flags
& MNT_FORCE
)
797 /* XXX post jaguar fix LK_DRAIN - then clean this up */
798 if ((flags
& MNT_FORCE
)) {
799 mp
->mnt_kern_flag
|= MNTK_FRCUNMOUNT
;
800 mp
->mnt_lflag
|= MNT_LFORCE
;
802 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
803 mp
->mnt_lflag
|= MNT_LWAIT
;
806 msleep((caddr_t
)mp
, &mp
->mnt_mlock
, (PVFS
| PDROP
), "dounmount", 0 );
808 * The prior unmount attempt has probably succeeded.
809 * Do not dereference mp here - returning EBUSY is safest.
811 if (skiplistrmp
!= NULL
)
815 mp
->mnt_kern_flag
|= MNTK_UNMOUNT
;
816 mp
->mnt_lflag
|= MNT_LUNMOUNT
;
817 mp
->mnt_flag
&=~ MNT_ASYNC
;
819 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
822 fsevent_unmount(mp
); /* has to come first! */
824 if (forcedunmount
== 0) {
825 ubc_umount(mp
); /* release cached vnodes */
826 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
827 error
= VFS_SYNC(mp
, MNT_WAIT
, &context
);
830 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
831 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
832 mp
->mnt_lflag
&= ~MNT_LFORCE
;
839 lflags
|= FORCECLOSE
;
840 error
= vflush(mp
, NULLVP
, SKIPSWAP
| SKIPSYSTEM
| SKIPROOT
| lflags
);
841 if ((forcedunmount
== 0) && error
) {
843 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
844 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
845 mp
->mnt_lflag
&= ~MNT_LFORCE
;
849 /* make sure there are no one in the mount iterations or lookup */
852 error
= VFS_UNMOUNT(mp
, flags
, &context
);
856 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
857 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
858 mp
->mnt_lflag
&= ~MNT_LFORCE
;
862 /* increment the operations count */
864 OSAddAtomic(1, (SInt32
*)&vfs_nummntops
);
866 if ( mp
->mnt_devvp
&& mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
867 mp
->mnt_devvp
->v_specflags
&= ~SI_MOUNTEDON
;
868 VNOP_CLOSE(mp
->mnt_devvp
, mp
->mnt_flag
& MNT_RDONLY
? FREAD
: FREAD
|FWRITE
,
870 vnode_rele(mp
->mnt_devvp
);
872 lck_rw_done(&mp
->mnt_rwlock
);
873 mount_list_remove(mp
);
874 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
876 /* mark the mount point hook in the vp but not drop the ref yet */
877 if ((coveredvp
= mp
->mnt_vnodecovered
) != NULLVP
) {
878 vnode_getwithref(coveredvp
);
879 vnode_lock(coveredvp
);
880 coveredvp
->v_mountedhere
= (struct mount
*)0;
881 vnode_unlock(coveredvp
);
882 vnode_put(coveredvp
);
886 mp
->mnt_vtable
->vfc_refcount
--;
889 cache_purgevfs(mp
); /* remove cache entries for this file sys */
890 vfs_event_signal(NULL
, VQ_UNMOUNT
, (intptr_t)NULL
);
892 mp
->mnt_lflag
|= MNT_LDEAD
;
894 if (mp
->mnt_lflag
& MNT_LWAIT
) {
897 * in case we block in mount_refdrain
898 * which will drop the mount lock
899 * and allow anyone blocked in vfs_busy
900 * to wakeup and see the LDEAD state
902 mp
->mnt_lflag
&= ~MNT_LWAIT
;
907 if (mp
->mnt_lflag
& MNT_LWAIT
) {
908 mp
->mnt_lflag
&= ~MNT_LWAIT
;
912 lck_rw_done(&mp
->mnt_rwlock
);
917 if ((coveredvp
!= NULLVP
)) {
918 vnode_getwithref(coveredvp
);
919 vnode_rele(coveredvp
);
920 vnode_lock(coveredvp
);
921 if(mp
->mnt_crossref
== 0) {
922 vnode_unlock(coveredvp
);
923 mount_lock_destroy(mp
);
924 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
926 coveredvp
->v_lflag
|= VL_MOUNTDEAD
;
927 vnode_unlock(coveredvp
);
929 vnode_put(coveredvp
);
930 } else if (mp
->mnt_flag
& MNT_ROOTFS
) {
931 mount_lock_destroy(mp
);
932 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
934 panic("dounmount: no coveredvp");
940 mount_dropcrossref(mount_t mp
, vnode_t dp
, int need_put
)
944 if (mp
->mnt_crossref
< 0)
945 panic("mount cross refs -ve");
946 if (((dp
->v_lflag
& VL_MOUNTDEAD
) == VL_MOUNTDEAD
) && (mp
->mnt_crossref
== 0)) {
947 dp
->v_lflag
&= ~VL_MOUNTDEAD
;
949 vnode_put_locked(dp
);
951 mount_lock_destroy(mp
);
952 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
956 vnode_put_locked(dp
);
962 * Sync each mounted filesystem.
966 struct ctldebug debug0
= { "syncprt", &syncprt
};
969 int print_vmpage_stat
=0;
972 sync_callback(mount_t mp
, __unused
void * arg
)
974 struct proc
* p
= current_proc();
976 struct vfs_context context
;
979 context
.vc_ucred
= kauth_cred_get();
981 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
982 asyncflag
= mp
->mnt_flag
& MNT_ASYNC
;
983 mp
->mnt_flag
&= ~MNT_ASYNC
;
984 VFS_SYNC(mp
, MNT_NOWAIT
, &context
);
986 mp
->mnt_flag
|= MNT_ASYNC
;
988 return(VFS_RETURNED
);
992 extern unsigned int vp_pagein
, vp_pgodirty
, vp_pgoclean
;
993 extern unsigned int dp_pgins
, dp_pgouts
;
997 sync(__unused
struct proc
*p
, __unused
struct sync_args
*uap
, __unused register_t
*retval
)
1000 vfs_iterate(LK_NOWAIT
, sync_callback
, (void *)0);
1002 if(print_vmpage_stat
) {
1003 vm_countdirtypages();
1004 printf("VP: %d: %d: %d: %d: %d\n", vp_pgodirty
, vp_pgoclean
, vp_pagein
,
1005 dp_pgins
, dp_pgouts
);
1011 #endif /* DIAGNOSTIC */
1016 * Change filesystem quotas.
1020 quotactl(struct proc
*p
, register struct quotactl_args
*uap
, __unused register_t
*retval
)
1022 register struct mount
*mp
;
1023 int error
, quota_cmd
, quota_status
;
1026 struct nameidata nd
;
1027 struct vfs_context context
;
1028 struct dqblk my_dqblk
;
1030 context
.vc_proc
= p
;
1031 context
.vc_ucred
= kauth_cred_get();
1033 AUDIT_ARG(uid
, uap
->uid
, 0, 0, 0);
1034 AUDIT_ARG(cmd
, uap
->cmd
);
1035 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1036 UIO_USERSPACE
, uap
->path
, &context
);
1040 mp
= nd
.ni_vp
->v_mount
;
1041 vnode_put(nd
.ni_vp
);
1044 /* copyin any data we will need for downstream code */
1045 quota_cmd
= uap
->cmd
>> SUBCMDSHIFT
;
1047 switch (quota_cmd
) {
1049 /* uap->arg specifies a file from which to take the quotas */
1050 fnamelen
= MAXPATHLEN
;
1051 datap
= kalloc(MAXPATHLEN
);
1052 error
= copyinstr(uap
->arg
, datap
, MAXPATHLEN
, &fnamelen
);
1055 /* uap->arg is a pointer to a dqblk structure. */
1056 datap
= (caddr_t
) &my_dqblk
;
1060 /* uap->arg is a pointer to a dqblk structure. */
1061 datap
= (caddr_t
) &my_dqblk
;
1062 if (proc_is64bit(p
)) {
1063 struct user_dqblk my_dqblk64
;
1064 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk64
, sizeof (my_dqblk64
));
1066 munge_dqblk(&my_dqblk
, &my_dqblk64
, FALSE
);
1070 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk
, sizeof (my_dqblk
));
1074 /* uap->arg is a pointer to an integer */
1075 datap
= (caddr_t
) "a_status
;
1083 error
= VFS_QUOTACTL(mp
, uap
->cmd
, uap
->uid
, datap
, &context
);
1086 switch (quota_cmd
) {
1089 kfree(datap
, MAXPATHLEN
);
1092 /* uap->arg is a pointer to a dqblk structure we need to copy out to */
1094 if (proc_is64bit(p
)) {
1095 struct user_dqblk my_dqblk64
;
1096 munge_dqblk(&my_dqblk
, &my_dqblk64
, TRUE
);
1097 error
= copyout((caddr_t
)&my_dqblk64
, uap
->arg
, sizeof (my_dqblk64
));
1100 error
= copyout(datap
, uap
->arg
, sizeof (struct dqblk
));
1105 /* uap->arg is a pointer to an integer */
1107 error
= copyout(datap
, uap
->arg
, sizeof(quota_status
));
1118 * Get filesystem statistics.
1122 statfs(struct proc
*p
, register struct statfs_args
*uap
, __unused register_t
*retval
)
1125 struct vfsstatfs
*sp
;
1127 struct nameidata nd
;
1128 struct vfs_context context
;
1131 context
.vc_proc
= p
;
1132 context
.vc_ucred
= kauth_cred_get();
1134 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1135 UIO_USERSPACE
, uap
->path
, &context
);
1141 sp
= &mp
->mnt_vfsstat
;
1144 error
= vfs_update_vfsstat(mp
, &context
);
1149 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1154 * Get filesystem statistics.
1158 fstatfs(struct proc
*p
, register struct fstatfs_args
*uap
, __unused register_t
*retval
)
1162 struct vfsstatfs
*sp
;
1164 struct vfs_context context
;
1166 context
.vc_proc
= p
;
1167 context
.vc_ucred
= kauth_cred_get();
1169 AUDIT_ARG(fd
, uap
->fd
);
1171 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1174 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
1181 sp
= &mp
->mnt_vfsstat
;
1182 if ((error
= vfs_update_vfsstat(mp
, &context
)) != 0) {
1188 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1194 struct getfsstat_struct
{
1204 getfsstat_callback(mount_t mp
, void * arg
)
1207 struct getfsstat_struct
*fstp
= (struct getfsstat_struct
*)arg
;
1208 struct vfsstatfs
*sp
;
1209 struct proc
* p
= current_proc();
1211 struct vfs_context context
;
1213 context
.vc_proc
= p
;
1214 context
.vc_ucred
= kauth_cred_get();
1216 if (fstp
->sfsp
&& fstp
->count
< fstp
->maxcount
) {
1217 sp
= &mp
->mnt_vfsstat
;
1219 * If MNT_NOWAIT is specified, do not refresh the
1220 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
1222 if (((fstp
->flags
& MNT_NOWAIT
) == 0 || (fstp
->flags
& MNT_WAIT
)) &&
1223 (error
= vfs_update_vfsstat(mp
, &context
))) {
1224 KAUTH_DEBUG("vfs_update_vfsstat returned %d", error
);
1225 return(VFS_RETURNED
);
1229 * Need to handle LP64 version of struct statfs
1231 error
= munge_statfs(mp
, sp
, fstp
->sfsp
, &my_size
, IS_64BIT_PROCESS(p
), FALSE
);
1233 fstp
->error
= error
;
1234 return(VFS_RETURNED_DONE
);
1236 fstp
->sfsp
+= my_size
;
1239 return(VFS_RETURNED
);
1243 * Get statistics on all filesystems.
1246 getfsstat(__unused proc_t p
, struct getfsstat_args
*uap
, int *retval
)
1249 int count
, maxcount
;
1250 struct getfsstat_struct fst
;
1252 if (IS_64BIT_PROCESS(p
)) {
1253 maxcount
= uap
->bufsize
/ sizeof(struct user_statfs
);
1256 maxcount
= uap
->bufsize
/ sizeof(struct statfs
);
1262 fst
.flags
= uap
->flags
;
1265 fst
.maxcount
= maxcount
;
1268 vfs_iterate(0, getfsstat_callback
, &fst
);
1271 KAUTH_DEBUG("ERROR - %s gets %d", p
->p_comm
, fst
.error
);
1275 if (fst
.sfsp
&& fst
.count
> fst
.maxcount
)
1276 *retval
= fst
.maxcount
;
1278 *retval
= fst
.count
;
1282 #if COMPAT_GETFSSTAT
1283 ogetfsstat(p
, uap
, retval
)
1285 register struct getfsstat_args
*uap
;
1293 * Change current working directory to a given file descriptor.
1297 fchdir(struct proc
*p
, struct fchdir_args
*uap
, __unused register_t
*retval
)
1299 register struct filedesc
*fdp
= p
->p_fd
;
1300 struct vnode
*vp
, *tdp
, *tvp
;
1303 struct vfs_context context
;
1305 context
.vc_proc
= p
;
1306 context
.vc_ucred
= kauth_cred_get();
1308 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1310 if ( (error
= vnode_getwithref(vp
)) ) {
1315 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
1317 if (vp
->v_type
!= VDIR
)
1320 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, &context
);
1321 while (!error
&& (mp
= vp
->v_mountedhere
) != NULL
) {
1322 if (vfs_busy(mp
, LK_NOWAIT
)) {
1326 error
= VFS_ROOT(mp
, &tdp
, &context
);
1335 if ( (error
= vnode_ref(vp
)) )
1357 * Change current working directory (``.'').
1361 chdir(struct proc
*p
, struct chdir_args
*uap
, __unused register_t
*retval
)
1363 register struct filedesc
*fdp
= p
->p_fd
;
1365 struct nameidata nd
;
1367 struct vfs_context context
;
1369 context
.vc_proc
= p
;
1370 context
.vc_ucred
= kauth_cred_get();
1372 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1373 UIO_USERSPACE
, uap
->path
, &context
);
1374 error
= change_dir(&nd
, &context
);
1377 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
1378 vnode_put(nd
.ni_vp
);
1382 * drop the iocount we picked up in change_dir
1384 vnode_put(nd
.ni_vp
);
1388 fdp
->fd_cdir
= nd
.ni_vp
;
1398 * Change notion of root (``/'') directory.
1402 chroot(struct proc
*p
, struct chroot_args
*uap
, __unused register_t
*retval
)
1404 register struct filedesc
*fdp
= p
->p_fd
;
1406 struct nameidata nd
;
1407 boolean_t shared_regions_active
;
1409 struct vfs_context context
;
1411 context
.vc_proc
= p
;
1412 context
.vc_ucred
= kauth_cred_get();
1414 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
1417 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1418 UIO_USERSPACE
, uap
->path
, &context
);
1419 error
= change_dir(&nd
, &context
);
1423 if(p
->p_flag
& P_NOSHLIB
) {
1424 shared_regions_active
= FALSE
;
1426 shared_regions_active
= TRUE
;
1428 if ((error
= clone_system_shared_regions(shared_regions_active
,
1429 TRUE
, /* chain_regions */
1431 vnode_put(nd
.ni_vp
);
1434 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
1435 vnode_put(nd
.ni_vp
);
1438 vnode_put(nd
.ni_vp
);
1442 fdp
->fd_rdir
= nd
.ni_vp
;
1443 fdp
->fd_flags
|= FD_CHROOT
;
1453 * Common routine for chroot and chdir.
1456 change_dir(struct nameidata
*ndp
, vfs_context_t ctx
)
1461 if ((error
= namei(ndp
)))
1465 if (vp
->v_type
!= VDIR
)
1468 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, ctx
);
1476 * Check permissions, allocate an open file structure,
1477 * and call the device open routine if any.
1480 #warning XXX implement uid, gid
1482 open1(vfs_context_t ctx
, user_addr_t upath
, int uflags
, struct vnode_attr
*vap
, register_t
*retval
)
1484 struct proc
*p
= vfs_context_proc(ctx
);
1485 register struct filedesc
*fdp
= p
->p_fd
;
1486 register struct fileproc
*fp
;
1487 register struct vnode
*vp
;
1489 struct fileproc
*nfp
;
1490 int type
, indx
, error
;
1492 struct nameidata nd
;
1496 if ((oflags
& O_ACCMODE
) == O_ACCMODE
)
1498 flags
= FFLAGS(uflags
);
1500 AUDIT_ARG(fflags
, oflags
);
1501 AUDIT_ARG(mode
, vap
->va_mode
);
1503 if ( (error
= falloc(p
, &nfp
, &indx
)) ) {
1507 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1508 UIO_USERSPACE
, upath
, ctx
);
1509 p
->p_dupfd
= -indx
- 1; /* XXX check for fdopen */
1511 if ((error
= vn_open_auth(&nd
, &flags
, vap
))) {
1512 if ((error
== ENODEV
|| error
== ENXIO
) && (p
->p_dupfd
>= 0)) { /* XXX from fdopen */
1513 if ((error
= dupfdopen(fdp
, indx
, p
->p_dupfd
, flags
, error
)) == 0) {
1514 fp_drop(p
, indx
, 0, 0);
1519 if (error
== ERESTART
)
1521 fp_free(p
, indx
, fp
);
1528 fp
->f_fglob
->fg_flag
= flags
& (FMASK
| O_EVTONLY
);
1529 fp
->f_fglob
->fg_type
= DTYPE_VNODE
;
1530 fp
->f_fglob
->fg_ops
= &vnops
;
1531 fp
->f_fglob
->fg_data
= (caddr_t
)vp
;
1533 if (flags
& (O_EXLOCK
| O_SHLOCK
)) {
1534 lf
.l_whence
= SEEK_SET
;
1537 if (flags
& O_EXLOCK
)
1538 lf
.l_type
= F_WRLCK
;
1540 lf
.l_type
= F_RDLCK
;
1542 if ((flags
& FNONBLOCK
) == 0)
1544 if ((error
= VNOP_ADVLOCK(vp
, (caddr_t
)fp
->f_fglob
, F_SETLK
, &lf
, type
, ctx
)))
1546 fp
->f_fglob
->fg_flag
|= FHASLOCK
;
1549 /* try to truncate by setting the size attribute */
1550 if ((flags
& O_TRUNC
) && ((error
= vnode_setsize(vp
, (off_t
)0, 0, ctx
)) != 0))
1556 procfdtbl_releasefd(p
, indx
, NULL
);
1557 fp_drop(p
, indx
, fp
, 1);
1564 vn_close(vp
, fp
->f_fglob
->fg_flag
, fp
->f_fglob
->fg_cred
, p
);
1566 fp_free(p
, indx
, fp
);
1573 * An open system call using an extended argument list compared to the regular
1574 * system call 'open'.
1576 * Parameters: p Process requesting the open
1577 * uap User argument descriptor (see below)
1578 * retval Pointer to an area to receive the
1579 * return calue from the system call
1581 * Indirect: uap->path Path to open (same as 'open')
1582 * uap->flags Flags to open (same as 'open'
1583 * uap->uid UID to set, if creating
1584 * uap->gid GID to set, if creating
1585 * uap->mode File mode, if creating (same as 'open')
1586 * uap->xsecurity ACL to set, if creating
1588 * Returns: 0 Success
1591 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
1593 * XXX: We should enummerate the possible errno values here, and where
1594 * in the code they originated.
1597 open_extended(struct proc
*p
, struct open_extended_args
*uap
, register_t
*retval
)
1599 struct vfs_context context
;
1600 register struct filedesc
*fdp
= p
->p_fd
;
1602 kauth_filesec_t xsecdst
;
1603 struct vnode_attr va
;
1607 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
1608 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
1611 context
.vc_proc
= p
;
1612 context
.vc_ucred
= kauth_cred_get();
1615 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
1616 VATTR_SET(&va
, va_mode
, cmode
);
1617 if (uap
->uid
!= KAUTH_UID_NONE
)
1618 VATTR_SET(&va
, va_uid
, uap
->uid
);
1619 if (uap
->gid
!= KAUTH_GID_NONE
)
1620 VATTR_SET(&va
, va_gid
, uap
->gid
);
1621 if (xsecdst
!= NULL
)
1622 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
1624 ciferror
= open1(&context
, uap
->path
, uap
->flags
, &va
, retval
);
1625 if (xsecdst
!= NULL
)
1626 kauth_filesec_free(xsecdst
);
1632 open(struct proc
*p
, struct open_args
*uap
, register_t
*retval
)
1634 struct vfs_context context
;
1635 register struct filedesc
*fdp
= p
->p_fd
;
1636 struct vnode_attr va
;
1639 context
.vc_proc
= p
;
1640 context
.vc_ucred
= kauth_cred_get();
1643 /* Mask off all but regular access permissions */
1644 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
1645 VATTR_SET(&va
, va_mode
, cmode
& ACCESSPERMS
);
1647 return(open1(&context
, uap
->path
, uap
->flags
, &va
, retval
));
1652 * Create a special file.
1654 static int mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
);
1657 mknod(struct proc
*p
, register struct mknod_args
*uap
, __unused register_t
*retval
)
1659 struct vnode_attr va
;
1660 struct vfs_context context
;
1663 struct nameidata nd
;
1666 context
.vc_proc
= p
;
1667 context
.vc_ucred
= kauth_cred_get();
1670 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1671 VATTR_SET(&va
, va_rdev
, uap
->dev
);
1673 /* If it's a mknod() of a FIFO, call mkfifo1() instead */
1674 if ((uap
->mode
& S_IFMT
) == S_IFIFO
)
1675 return(mkfifo1(&context
, uap
->path
, &va
));
1677 AUDIT_ARG(mode
, uap
->mode
);
1678 AUDIT_ARG(dev
, uap
->dev
);
1680 if ((error
= suser(context
.vc_ucred
, &p
->p_acflag
)))
1682 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1683 UIO_USERSPACE
, uap
->path
, &context
);
1695 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
1698 switch (uap
->mode
& S_IFMT
) {
1699 case S_IFMT
: /* used by badsect to flag bad sectors */
1700 VATTR_SET(&va
, va_type
, VBAD
);
1703 VATTR_SET(&va
, va_type
, VCHR
);
1706 VATTR_SET(&va
, va_type
, VBLK
);
1716 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, CREATE
, &context
);
1718 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, &va
, 0, &context
);
1724 int update_flags
= 0;
1726 // Make sure the name & parent pointers are hooked up
1727 if (vp
->v_name
== NULL
)
1728 update_flags
|= VNODE_UPDATE_NAME
;
1729 if (vp
->v_parent
== NULLVP
)
1730 update_flags
|= VNODE_UPDATE_PARENT
;
1733 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
1735 add_fsevent(FSE_CREATE_FILE
, &context
,
1742 * nameidone has to happen before we vnode_put(dvp)
1743 * since it may need to release the fs_nodelock on the dvp
1755 * Create a named pipe.
1758 mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
)
1762 struct nameidata nd
;
1764 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1765 UIO_USERSPACE
, upath
, ctx
);
1772 /* check that this is a new file and authorize addition */
1777 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
1780 VATTR_SET(vap
, va_type
, VFIFO
);
1782 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
);
1785 * nameidone has to happen before we vnode_put(dvp)
1786 * since it may need to release the fs_nodelock on the dvp
1799 * A mkfifo system call using an extended argument list compared to the regular
1800 * system call 'mkfifo'.
1802 * Parameters: p Process requesting the open
1803 * uap User argument descriptor (see below)
1806 * Indirect: uap->path Path to fifo (same as 'mkfifo')
1807 * uap->uid UID to set
1808 * uap->gid GID to set
1809 * uap->mode File mode to set (same as 'mkfifo')
1810 * uap->xsecurity ACL to set, if creating
1812 * Returns: 0 Success
1815 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
1817 * XXX: We should enummerate the possible errno values here, and where
1818 * in the code they originated.
1821 mkfifo_extended(struct proc
*p
, struct mkfifo_extended_args
*uap
, __unused register_t
*retval
)
1824 kauth_filesec_t xsecdst
;
1825 struct vfs_context context
;
1826 struct vnode_attr va
;
1828 xsecdst
= KAUTH_FILESEC_NONE
;
1829 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
1830 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
1834 context
.vc_proc
= p
;
1835 context
.vc_ucred
= kauth_cred_get();
1838 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1839 if (uap
->uid
!= KAUTH_UID_NONE
)
1840 VATTR_SET(&va
, va_uid
, uap
->uid
);
1841 if (uap
->gid
!= KAUTH_GID_NONE
)
1842 VATTR_SET(&va
, va_gid
, uap
->gid
);
1843 if (xsecdst
!= KAUTH_FILESEC_NONE
)
1844 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
1846 ciferror
= mkfifo1(&context
, uap
->path
, &va
);
1848 if (xsecdst
!= KAUTH_FILESEC_NONE
)
1849 kauth_filesec_free(xsecdst
);
1855 mkfifo(struct proc
*p
, register struct mkfifo_args
*uap
, __unused register_t
*retval
)
1857 struct vfs_context context
;
1858 struct vnode_attr va
;
1860 context
.vc_proc
= p
;
1861 context
.vc_ucred
= kauth_cred_get();
1864 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1866 return(mkfifo1(&context
, uap
->path
, &va
));
1870 * Make a hard file link.
1874 link(struct proc
*p
, register struct link_args
*uap
, __unused register_t
*retval
)
1876 vnode_t vp
, dvp
, lvp
;
1877 struct nameidata nd
;
1878 struct vfs_context context
;
1881 int need_event
, has_listeners
;
1883 context
.vc_proc
= p
;
1884 context
.vc_ucred
= kauth_cred_get();
1885 vp
= dvp
= lvp
= NULLVP
;
1887 /* look up the object we are linking to */
1888 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1889 UIO_USERSPACE
, uap
->path
, &context
);
1897 /* we're not allowed to link to directories */
1898 if (vp
->v_type
== VDIR
) {
1899 error
= EPERM
; /* POSIX */
1903 /* or to anything that kauth doesn't want us to (eg. immutable items) */
1904 if ((error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_LINKTARGET
, &context
)) != 0)
1907 /* lookup the target node */
1908 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1909 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| AUDITVNPATH2
;
1910 nd
.ni_dirp
= uap
->link
;
1916 /* target node must not exist */
1917 if (lvp
!= NULLVP
) {
1921 /* cannot link across mountpoints */
1922 if (vnode_mount(vp
) != vnode_mount(dvp
)) {
1927 /* authorize creation of the target note */
1928 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
1931 /* and finally make the link */
1932 error
= VNOP_LINK(vp
, dvp
, &nd
.ni_cnd
, &context
);
1936 need_event
= need_fsevent(FSE_CREATE_FILE
, dvp
);
1937 has_listeners
= kauth_authorize_fileop_has_listeners();
1939 if (need_event
|| has_listeners
) {
1940 char *target_path
= NULL
;
1941 char *link_to_path
= NULL
;
1942 int len
, link_name_len
;
1944 /* build the path to the new link file */
1945 target_path
= get_pathbuff();
1947 vn_getpath(dvp
, target_path
, &len
);
1948 target_path
[len
-1] = '/';
1949 strcpy(&target_path
[len
], nd
.ni_cnd
.cn_nameptr
);
1950 len
+= nd
.ni_cnd
.cn_namelen
;
1952 if (has_listeners
) {
1953 /* build the path to file we are linking to */
1954 link_to_path
= get_pathbuff();
1955 link_name_len
= MAXPATHLEN
;
1956 vn_getpath(vp
, link_to_path
, &link_name_len
);
1958 /* call out to allow 3rd party notification of rename.
1959 * Ignore result of kauth_authorize_fileop call.
1961 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_LINK
,
1962 (uintptr_t)link_to_path
, (uintptr_t)target_path
);
1963 if (link_to_path
!= NULL
)
1964 release_pathbuff(link_to_path
);
1967 /* construct fsevent */
1968 if (get_fse_info(vp
, &finfo
, &context
) == 0) {
1969 // build the path to the destination of the link
1970 add_fsevent(FSE_CREATE_FILE
, &context
,
1971 FSE_ARG_STRING
, len
, target_path
,
1972 FSE_ARG_FINFO
, &finfo
,
1976 release_pathbuff(target_path
);
1980 * nameidone has to happen before we vnode_put(dvp)
1981 * since it may need to release the fs_nodelock on the dvp
1994 * Make a symbolic link.
1996 * We could add support for ACLs here too...
2000 symlink(struct proc
*p
, register struct symlink_args
*uap
, __unused register_t
*retval
)
2002 struct vnode_attr va
;
2005 struct nameidata nd
;
2006 struct vfs_context context
;
2010 context
.vc_proc
= p
;
2011 context
.vc_ucred
= kauth_cred_get();
2013 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2014 error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
);
2017 AUDIT_ARG(text
, path
); /* This is the link string */
2019 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
2020 UIO_USERSPACE
, uap
->link
, &context
);
2029 VATTR_SET(&va
, va_type
, VLNK
);
2030 VATTR_SET(&va
, va_mode
, ACCESSPERMS
& ~p
->p_fd
->fd_cmask
);
2033 error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
);
2034 /* get default ownership, etc. */
2036 error
= vnode_authattr_new(dvp
, &va
, 0, &context
);
2038 error
= VNOP_SYMLINK(dvp
, &vp
, &nd
.ni_cnd
, &va
, path
, &context
);
2040 /* do fallback attribute handling */
2042 error
= vnode_setattr_fallback(vp
, &va
, &context
);
2045 int update_flags
= 0;
2048 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
2049 nd
.ni_cnd
.cn_flags
= 0;
2057 #if 0 /* XXX - kauth_todo - is KAUTH_FILEOP_SYMLINK needed? */
2058 /* call out to allow 3rd party notification of rename.
2059 * Ignore result of kauth_authorize_fileop call.
2061 if (kauth_authorize_fileop_has_listeners() &&
2063 char *new_link_path
= NULL
;
2066 /* build the path to the new link file */
2067 new_link_path
= get_pathbuff();
2069 vn_getpath(dvp
, new_link_path
, &len
);
2070 new_link_path
[len
- 1] = '/';
2071 strcpy(&new_link_path
[len
], nd
.ni_cnd
.cn_nameptr
);
2073 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_SYMLINK
,
2074 (uintptr_t)path
, (uintptr_t)new_link_path
);
2075 if (new_link_path
!= NULL
)
2076 release_pathbuff(new_link_path
);
2079 // Make sure the name & parent pointers are hooked up
2080 if (vp
->v_name
== NULL
)
2081 update_flags
|= VNODE_UPDATE_NAME
;
2082 if (vp
->v_parent
== NULLVP
)
2083 update_flags
|= VNODE_UPDATE_PARENT
;
2086 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
2088 add_fsevent(FSE_CREATE_FILE
, &context
,
2097 * nameidone has to happen before we vnode_put(dvp)
2098 * since it may need to release the fs_nodelock on the dvp
2106 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
2112 * Delete a whiteout from the filesystem.
2115 #warning XXX authorization not implmented for whiteouts
2117 undelete(struct proc
*p
, register struct undelete_args
*uap
, __unused register_t
*retval
)
2120 struct nameidata nd
;
2121 struct vfs_context context
;
2124 context
.vc_proc
= p
;
2125 context
.vc_ucred
= kauth_cred_get();
2127 NDINIT(&nd
, DELETE
, LOCKPARENT
|DOWHITEOUT
|AUDITVNPATH1
,
2128 UIO_USERSPACE
, uap
->path
, &context
);
2135 if (vp
== NULLVP
&& (nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
2136 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, DELETE
, &context
);
2141 * nameidone has to happen before we vnode_put(dvp)
2142 * since it may need to release the fs_nodelock on the dvp
2154 * Delete a name from the filesystem.
2158 _unlink(struct proc
*p
, struct unlink_args
*uap
, __unused register_t
*retval
, int nodelbusy
)
2162 struct nameidata nd
;
2163 struct vfs_context context
;
2164 struct componentname
*cnp
;
2167 context
.vc_proc
= p
;
2168 context
.vc_ucred
= kauth_cred_get();
2170 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
2171 UIO_USERSPACE
, uap
->path
, &context
);
2174 /* With Carbon delete semantics, busy files cannot be deleted */
2176 flags
|= VNODE_REMOVE_NODELETEBUSY
;
2184 if (vp
->v_type
== VDIR
) {
2185 error
= EPERM
; /* POSIX */
2188 * The root of a mounted filesystem cannot be deleted.
2190 if (vp
->v_flag
& VROOT
) {
2194 /* authorize the delete operation */
2196 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, &context
);
2203 if (need_fsevent(FSE_DELETE
, dvp
)) {
2204 path
= get_pathbuff();
2206 vn_getpath(vp
, path
, &len
);
2207 get_fse_info(vp
, &finfo
, &context
);
2209 error
= VNOP_REMOVE(dvp
, vp
, &nd
.ni_cnd
, flags
, &context
);
2211 if ( !error
&& path
!= NULL
) {
2212 add_fsevent(FSE_DELETE
, &context
,
2213 FSE_ARG_STRING
, len
, path
,
2214 FSE_ARG_FINFO
, &finfo
,
2218 release_pathbuff(path
);
2221 * nameidone has to happen before we vnode_put(dvp)
2222 * since it may need to release the fs_nodelock on the dvp
2231 * Delete a name from the filesystem using POSIX semantics.
2234 unlink(p
, uap
, retval
)
2236 struct unlink_args
*uap
;
2239 return _unlink(p
, uap
, retval
, 0);
2243 * Delete a name from the filesystem using Carbon semantics.
2246 delete(p
, uap
, retval
)
2248 struct delete_args
*uap
;
2251 return _unlink(p
, (struct unlink_args
*)uap
, retval
, 1);
2255 * Reposition read/write file offset.
2258 lseek(p
, uap
, retval
)
2260 register struct lseek_args
*uap
;
2263 struct fileproc
*fp
;
2265 struct vfs_context context
;
2266 off_t offset
= uap
->offset
, file_size
;
2269 if ( (error
= fp_getfvp(p
,uap
->fd
, &fp
, &vp
)) ) {
2270 if (error
== ENOTSUP
)
2274 if (vnode_isfifo(vp
)) {
2278 if ( (error
= vnode_getwithref(vp
)) ) {
2283 switch (uap
->whence
) {
2285 offset
+= fp
->f_fglob
->fg_offset
;
2288 context
.vc_proc
= p
;
2289 context
.vc_ucred
= kauth_cred_get();
2290 if ((error
= vnode_size(vp
, &file_size
, &context
)) != 0)
2292 offset
+= file_size
;
2300 if (uap
->offset
> 0 && offset
< 0) {
2301 /* Incremented/relative move past max size */
2305 * Allow negative offsets on character devices, per
2306 * POSIX 1003.1-2001. Most likely for writing disk
2309 if (offset
< 0 && vp
->v_type
!= VCHR
) {
2310 /* Decremented/relative move before start */
2314 fp
->f_fglob
->fg_offset
= offset
;
2315 *retval
= fp
->f_fglob
->fg_offset
;
2319 (void)vnode_put(vp
);
2326 * Check access permissions.
2329 access1(vnode_t vp
, vnode_t dvp
, int uflags
, vfs_context_t ctx
)
2331 kauth_action_t action
;
2335 * If just the regular access bits, convert them to something
2336 * that vnode_authorize will understand.
2338 if (!(uflags
& _ACCESS_EXTENDED_MASK
)) {
2341 action
|= KAUTH_VNODE_READ_DATA
; /* aka KAUTH_VNODE_LIST_DIRECTORY */
2342 if (uflags
& W_OK
) {
2343 if (vnode_isdir(vp
)) {
2344 action
|= KAUTH_VNODE_ADD_FILE
|
2345 KAUTH_VNODE_ADD_SUBDIRECTORY
;
2346 /* might want delete rights here too */
2348 action
|= KAUTH_VNODE_WRITE_DATA
;
2351 if (uflags
& X_OK
) {
2352 if (vnode_isdir(vp
)) {
2353 action
|= KAUTH_VNODE_SEARCH
;
2355 action
|= KAUTH_VNODE_EXECUTE
;
2359 /* take advantage of definition of uflags */
2360 action
= uflags
>> 8;
2363 /* action == 0 means only check for existence */
2365 error
= vnode_authorize(vp
, dvp
, action
| KAUTH_VNODE_ACCESS
, ctx
);
2375 /* XXX need to support the check-as uid argument */
2377 access_extended(__unused
struct proc
*p
, struct access_extended_args
*uap
, __unused register_t
*retval
)
2379 struct accessx_descriptor
*input
;
2381 int error
, limit
, nent
, i
, j
, wantdelete
;
2382 struct vfs_context context
;
2383 struct nameidata nd
;
2392 context
.vc_ucred
= NULL
;
2394 /* check input size and fetch descriptor array into allocated storage */
2395 if (uap
->size
> ACCESSX_MAX_TABLESIZE
)
2397 if (uap
->size
< sizeof(struct accessx_descriptor
))
2399 MALLOC(input
, struct accessx_descriptor
*, uap
->size
, M_TEMP
, M_WAITOK
);
2400 if (input
== NULL
) {
2404 error
= copyin(uap
->entries
, input
, uap
->size
);
2409 * Access is defined as checking against the process'
2410 * real identity, even if operations are checking the
2411 * effective identity. So we need to tweak the credential
2414 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
2415 context
.vc_proc
= current_proc();
2418 * Find out how many entries we have, so we can allocate the result array.
2420 limit
= uap
->size
/ sizeof(struct accessx_descriptor
);
2423 for (i
= 0; i
< nent
; i
++) {
2425 * Take the offset to the name string for this entry and convert to an
2426 * input array index, which would be one off the end of the array if this
2427 * was the lowest-addressed name string.
2429 j
= input
[i
].ad_name_offset
/ sizeof(struct accessx_descriptor
);
2435 /* implicit reference to previous name, not a real offset */
2437 /* first entry must have a name string */
2447 if (nent
> ACCESSX_MAX_DESCRIPTORS
) {
2451 MALLOC(result
, errno_t
*, nent
* sizeof(errno_t
), M_TEMP
, M_WAITOK
);
2452 if (result
== NULL
) {
2461 for (i
= 0; i
< nent
; i
++) {
2463 * Looking up a new name?
2465 if (input
[i
].ad_name_offset
!= 0) {
2466 /* discard old vnodes */
2476 /* scan forwards to see if we need the parent this time */
2477 wantdelete
= input
[i
].ad_flags
& _DELETE_OK
;
2478 for (j
= i
+ 1; (j
< nent
) && (input
[j
].ad_name_offset
== 0); j
++)
2479 if (input
[j
].ad_flags
& _DELETE_OK
)
2482 niopts
= FOLLOW
| AUDITVNPATH1
;
2483 /* need parent for vnode_authorize for deletion test */
2485 niopts
|= WANTPARENT
;
2488 NDINIT(&nd
, LOOKUP
, niopts
, UIO_SYSSPACE
, CAST_USER_ADDR_T((const char *)input
+ input
[i
].ad_name_offset
), &context
);
2499 * Handle lookup errors.
2509 /* run this access check */
2510 result
[i
] = access1(vp
, dvp
, input
[i
].ad_flags
, &context
);
2513 /* fatal lookup error */
2519 /* copy out results */
2520 error
= copyout(result
, uap
->results
, nent
* sizeof(errno_t
));
2524 FREE(input
, M_TEMP
);
2526 FREE(result
, M_TEMP
);
2531 if (IS_VALID_CRED(context
.vc_ucred
))
2532 kauth_cred_unref(&context
.vc_ucred
);
2537 access(__unused
struct proc
*p
, register struct access_args
*uap
, __unused register_t
*retval
)
2540 struct nameidata nd
;
2542 struct vfs_context context
;
2545 * Access is defined as checking against the process'
2546 * real identity, even if operations are checking the
2547 * effective identity. So we need to tweak the credential
2550 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
2551 context
.vc_proc
= current_proc();
2553 niopts
= FOLLOW
| AUDITVNPATH1
;
2554 /* need parent for vnode_authorize for deletion test */
2555 if (uap
->flags
& _DELETE_OK
)
2556 niopts
|= WANTPARENT
;
2557 NDINIT(&nd
, LOOKUP
, niopts
, UIO_USERSPACE
, uap
->path
, &context
);
2562 error
= access1(nd
.ni_vp
, nd
.ni_dvp
, uap
->flags
, &context
);
2564 vnode_put(nd
.ni_vp
);
2565 if (uap
->flags
& _DELETE_OK
)
2566 vnode_put(nd
.ni_dvp
);
2570 kauth_cred_unref(&context
.vc_ucred
);
2576 stat2(vfs_context_t ctx
, struct nameidata
*ndp
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2579 struct user_stat user_sb
;
2582 kauth_filesec_t fsec
;
2583 size_t xsecurity_bufsize
;
2588 fsec
= KAUTH_FILESEC_NONE
;
2589 error
= vn_stat(ndp
->ni_vp
, &sb
, (xsecurity
!= USER_ADDR_NULL
? &fsec
: NULL
), ctx
);
2590 vnode_put(ndp
->ni_vp
);
2595 /* Zap spare fields */
2597 sb
.st_qspare
[0] = 0LL;
2598 sb
.st_qspare
[1] = 0LL;
2599 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
2600 munge_stat(&sb
, &user_sb
);
2601 my_size
= sizeof(user_sb
);
2602 sbp
= (caddr_t
)&user_sb
;
2605 my_size
= sizeof(sb
);
2608 if ((error
= copyout(sbp
, ub
, my_size
)) != 0)
2611 /* caller wants extended security information? */
2612 if (xsecurity
!= USER_ADDR_NULL
) {
2614 /* did we get any? */
2615 if (fsec
== KAUTH_FILESEC_NONE
) {
2616 if (susize(xsecurity_size
, 0) != 0) {
2621 /* find the user buffer size */
2622 xsecurity_bufsize
= fusize(xsecurity_size
);
2624 /* copy out the actual data size */
2625 if (susize(xsecurity_size
, KAUTH_FILESEC_COPYSIZE(fsec
)) != 0) {
2630 /* if the caller supplied enough room, copy out to it */
2631 if (xsecurity_bufsize
>= KAUTH_FILESEC_COPYSIZE(fsec
))
2632 error
= copyout(fsec
, xsecurity
, KAUTH_FILESEC_COPYSIZE(fsec
));
2636 if (fsec
!= KAUTH_FILESEC_NONE
)
2637 kauth_filesec_free(fsec
);
2642 * Get file status; this version follows links.
2645 stat1(struct proc
*p
, user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2647 struct nameidata nd
;
2648 struct vfs_context context
;
2650 context
.vc_proc
= p
;
2651 context
.vc_ucred
= kauth_cred_get();
2653 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2654 UIO_USERSPACE
, path
, &context
);
2655 return(stat2(&context
, &nd
, ub
, xsecurity
, xsecurity_size
));
2659 stat_extended(struct proc
*p
, struct stat_extended_args
*uap
, __unused register_t
*retval
)
2661 return (stat1(p
, uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
));
2665 stat(struct proc
*p
, struct stat_args
*uap
, __unused register_t
*retval
)
2667 return(stat1(p
, uap
->path
, uap
->ub
, 0, 0));
2671 * Get file status; this version does not follow links.
2674 lstat1(struct proc
*p
, user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2676 struct nameidata nd
;
2677 struct vfs_context context
;
2679 context
.vc_proc
= p
;
2680 context
.vc_ucred
= kauth_cred_get();
2682 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
2683 UIO_USERSPACE
, path
, &context
);
2685 return(stat2(&context
, &nd
, ub
, xsecurity
, xsecurity_size
));
2689 lstat_extended(struct proc
*p
, struct lstat_extended_args
*uap
, __unused register_t
*retval
)
2691 return (lstat1(p
, uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
));
2695 lstat(struct proc
*p
, struct lstat_args
*uap
, __unused register_t
*retval
)
2697 return(lstat1(p
, uap
->path
, uap
->ub
, 0, 0));
2701 * Get configurable pathname variables.
2705 pathconf(p
, uap
, retval
)
2707 register struct pathconf_args
*uap
;
2711 struct nameidata nd
;
2712 struct vfs_context context
;
2714 context
.vc_proc
= p
;
2715 context
.vc_ucred
= kauth_cred_get();
2717 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2718 UIO_USERSPACE
, uap
->path
, &context
);
2723 error
= vn_pathconf(nd
.ni_vp
, uap
->name
, retval
, &context
);
2725 vnode_put(nd
.ni_vp
);
2731 * Return target name of a symbolic link.
2735 readlink(p
, uap
, retval
)
2737 register struct readlink_args
*uap
;
2740 register struct vnode
*vp
;
2742 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
2744 struct nameidata nd
;
2745 struct vfs_context context
;
2746 char uio_buf
[ UIO_SIZEOF(1) ];
2748 context
.vc_proc
= p
;
2749 context
.vc_ucred
= kauth_cred_get();
2751 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
2752 UIO_USERSPACE
, uap
->path
, &context
);
2760 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
2761 &uio_buf
[0], sizeof(uio_buf
));
2762 uio_addiov(auio
, uap
->buf
, uap
->count
);
2763 if (vp
->v_type
!= VLNK
)
2766 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, &context
);
2768 error
= VNOP_READLINK(vp
, auio
, &context
);
2771 // LP64todo - fix this
2772 *retval
= uap
->count
- (int)uio_resid(auio
);
2777 * Change file flags.
2780 chflags1(vnode_t vp
, int flags
, vfs_context_t ctx
)
2782 struct vnode_attr va
;
2783 kauth_action_t action
;
2787 VATTR_SET(&va
, va_flags
, flags
);
2789 /* request authorisation, disregard immutability */
2790 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
2793 * Request that the auth layer disregard those file flags it's allowed to when
2794 * authorizing this operation; we need to do this in order to be able to
2795 * clear immutable flags.
2797 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
| KAUTH_VNODE_NOIMMUTABLE
, ctx
)) != 0))
2799 error
= vnode_setattr(vp
, &va
, ctx
);
2807 * Change flags of a file given a path name.
2811 chflags(struct proc
*p
, register struct chflags_args
*uap
, __unused register_t
*retval
)
2813 register struct vnode
*vp
;
2814 struct vfs_context context
;
2816 struct nameidata nd
;
2818 context
.vc_proc
= p
;
2819 context
.vc_ucred
= kauth_cred_get();
2821 AUDIT_ARG(fflags
, uap
->flags
);
2822 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2823 UIO_USERSPACE
, uap
->path
, &context
);
2830 error
= chflags1(vp
, uap
->flags
, &context
);
2836 * Change flags of a file given a file descriptor.
2840 fchflags(struct proc
*p
, register struct fchflags_args
*uap
, __unused register_t
*retval
)
2842 struct vfs_context context
;
2846 AUDIT_ARG(fd
, uap
->fd
);
2847 AUDIT_ARG(fflags
, uap
->flags
);
2848 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
2851 if ((error
= vnode_getwithref(vp
))) {
2856 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2858 context
.vc_proc
= p
;
2859 context
.vc_ucred
= kauth_cred_get();
2861 error
= chflags1(vp
, uap
->flags
, &context
);
2868 * Change security information on a filesystem object.
2871 chmod2(vfs_context_t ctx
, struct vnode
*vp
, struct vnode_attr
*vap
)
2873 kauth_action_t action
;
2876 AUDIT_ARG(mode
, (mode_t
)vap
->va_mode
);
2877 #warning XXX audit new args
2879 /* make sure that the caller is allowed to set this security information */
2880 if (((error
= vnode_authattr(vp
, vap
, &action
, ctx
)) != 0) ||
2881 ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
2882 if (error
== EACCES
)
2887 error
= vnode_setattr(vp
, vap
, ctx
);
2894 * Change mode of a file given path name.
2897 chmod1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
2899 struct nameidata nd
;
2902 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2903 UIO_USERSPACE
, path
, ctx
);
2904 if ((error
= namei(&nd
)))
2906 error
= chmod2(ctx
, nd
.ni_vp
, vap
);
2907 vnode_put(nd
.ni_vp
);
2913 * A chmod system call using an extended argument list compared to the regular
2914 * system call 'mkfifo'.
2916 * Parameters: p Process requesting the open
2917 * uap User argument descriptor (see below)
2920 * Indirect: uap->path Path to object (same as 'chmod')
2921 * uap->uid UID to set
2922 * uap->gid GID to set
2923 * uap->mode File mode to set (same as 'chmod')
2924 * uap->xsecurity ACL to set (or delete)
2926 * Returns: 0 Success
2929 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
2931 * XXX: We should enummerate the possible errno values here, and where
2932 * in the code they originated.
2935 chmod_extended(struct proc
*p
, struct chmod_extended_args
*uap
, __unused register_t
*retval
)
2937 struct vfs_context context
;
2939 struct vnode_attr va
;
2940 kauth_filesec_t xsecdst
;
2943 if (uap
->mode
!= -1)
2944 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2945 if (uap
->uid
!= KAUTH_UID_NONE
)
2946 VATTR_SET(&va
, va_uid
, uap
->uid
);
2947 if (uap
->gid
!= KAUTH_GID_NONE
)
2948 VATTR_SET(&va
, va_gid
, uap
->gid
);
2951 switch(uap
->xsecurity
) {
2952 /* explicit remove request */
2953 case CAST_USER_ADDR_T((void *)1): /* _FILESEC_REMOVE_ACL */
2954 VATTR_SET(&va
, va_acl
, NULL
);
2957 case USER_ADDR_NULL
:
2960 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
2962 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2963 KAUTH_DEBUG("CHMOD - setting ACL with %d entries", va
.va_acl
->acl_entrycount
);
2965 context
.vc_proc
= p
;
2966 context
.vc_ucred
= kauth_cred_get();
2968 error
= chmod1(&context
, uap
->path
, &va
);
2970 if (xsecdst
!= NULL
)
2971 kauth_filesec_free(xsecdst
);
2976 chmod(struct proc
*p
, register struct chmod_args
*uap
, __unused register_t
*retval
)
2978 struct vfs_context context
;
2979 struct vnode_attr va
;
2982 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2984 context
.vc_proc
= p
;
2985 context
.vc_ucred
= kauth_cred_get();
2987 return(chmod1(&context
, uap
->path
, &va
));
2991 * Change mode of a file given a file descriptor.
2994 fchmod1(struct proc
*p
, int fd
, struct vnode_attr
*vap
)
2998 struct vfs_context context
;
3000 context
.vc_proc
= p
;
3001 context
.vc_ucred
= kauth_cred_get();
3005 if ((error
= file_vnode(fd
, &vp
)) != 0)
3007 if ((error
= vnode_getwithref(vp
)) != 0) {
3011 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3013 error
= chmod2(&context
, vp
, vap
);
3014 (void)vnode_put(vp
);
3021 fchmod_extended(struct proc
*p
, struct fchmod_extended_args
*uap
, __unused register_t
*retval
)
3024 struct vnode_attr va
;
3025 kauth_filesec_t xsecdst
;
3028 if (uap
->mode
!= -1)
3029 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
3030 if (uap
->uid
!= KAUTH_UID_NONE
)
3031 VATTR_SET(&va
, va_uid
, uap
->uid
);
3032 if (uap
->gid
!= KAUTH_GID_NONE
)
3033 VATTR_SET(&va
, va_gid
, uap
->gid
);
3036 switch(uap
->xsecurity
) {
3037 case USER_ADDR_NULL
:
3038 VATTR_SET(&va
, va_acl
, NULL
);
3040 case CAST_USER_ADDR_T(-1):
3043 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
3045 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
3048 error
= fchmod1(p
, uap
->fd
, &va
);
3051 switch(uap
->xsecurity
) {
3052 case USER_ADDR_NULL
:
3053 case CAST_USER_ADDR_T(-1):
3056 if (xsecdst
!= NULL
)
3057 kauth_filesec_free(xsecdst
);
3063 fchmod(struct proc
*p
, register struct fchmod_args
*uap
, __unused register_t
*retval
)
3065 struct vnode_attr va
;
3068 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
3070 return(fchmod1(p
, uap
->fd
, &va
));
3075 * Set ownership given a path name.
3079 chown1(vfs_context_t ctx
, register struct chown_args
*uap
, __unused register_t
*retval
, int follow
)
3081 register struct vnode
*vp
;
3082 struct vnode_attr va
;
3084 struct nameidata nd
;
3085 kauth_action_t action
;
3087 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
3089 NDINIT(&nd
, LOOKUP
, (follow
? FOLLOW
: 0) | AUDITVNPATH1
,
3090 UIO_USERSPACE
, uap
->path
, ctx
);
3099 * XXX A TEMPORARY HACK FOR NOW: Try to track console_user
3100 * by looking for chown() calls on /dev/console from a console process.
3102 if ((vp
) && (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
) && (vp
->v_specinfo
) &&
3103 (major(vp
->v_specinfo
->si_rdev
) == CONSMAJOR
) &&
3104 (minor(vp
->v_specinfo
->si_rdev
) == 0)) {
3105 console_user
= uap
->uid
;
3108 if (uap
->uid
!= VNOVAL
)
3109 VATTR_SET(&va
, va_uid
, uap
->uid
);
3110 if (uap
->gid
!= VNOVAL
)
3111 VATTR_SET(&va
, va_gid
, uap
->gid
);
3113 /* preflight and authorize attribute changes */
3114 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
3116 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
3118 error
= vnode_setattr(vp
, &va
, ctx
);
3122 * EACCES is only allowed from namei(); permissions failure should
3123 * return EPERM, so we need to translate the error code.
3125 if (error
== EACCES
)
3133 chown(struct proc
*p
, register struct chown_args
*uap
, register_t
*retval
)
3135 struct vfs_context context
;
3137 context
.vc_proc
= p
;
3138 context
.vc_ucred
= kauth_cred_get();
3140 return chown1(&context
, uap
, retval
, 1);
3144 lchown(struct proc
*p
, register struct lchown_args
*uap
, register_t
*retval
)
3146 struct vfs_context context
;
3148 context
.vc_proc
= p
;
3149 context
.vc_ucred
= kauth_cred_get();
3151 /* Argument list identical, but machine generated; cast for chown1() */
3152 return chown1(&context
, (struct chown_args
*)uap
, retval
, 0);
3156 * Set ownership given a file descriptor.
3160 fchown(struct proc
*p
, register struct fchown_args
*uap
, __unused register_t
*retval
)
3162 struct vnode_attr va
;
3163 struct vfs_context context
;
3166 kauth_action_t action
;
3168 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
3169 AUDIT_ARG(fd
, uap
->fd
);
3171 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
3174 if ( (error
= vnode_getwithref(vp
)) ) {
3178 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3181 if (uap
->uid
!= VNOVAL
)
3182 VATTR_SET(&va
, va_uid
, uap
->uid
);
3183 if (uap
->gid
!= VNOVAL
)
3184 VATTR_SET(&va
, va_gid
, uap
->gid
);
3186 context
.vc_proc
= p
;
3187 context
.vc_ucred
= kauth_cred_get();
3189 /* preflight and authorize attribute changes */
3190 if ((error
= vnode_authattr(vp
, &va
, &action
, &context
)) != 0)
3192 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0)) {
3193 if (error
== EACCES
)
3197 error
= vnode_setattr(vp
, &va
, &context
);
3200 (void)vnode_put(vp
);
3206 getutimes(usrtvp
, tsp
)
3208 struct timespec
*tsp
;
3210 struct user_timeval tv
[2];
3213 if (usrtvp
== USER_ADDR_NULL
) {
3214 struct timeval old_tv
;
3215 /* XXX Y2038 bug because of microtime argument */
3217 TIMEVAL_TO_TIMESPEC(&old_tv
, &tsp
[0]);
3220 if (IS_64BIT_PROCESS(current_proc())) {
3221 error
= copyin(usrtvp
, (void *)tv
, sizeof(tv
));
3223 struct timeval old_tv
[2];
3224 error
= copyin(usrtvp
, (void *)old_tv
, sizeof(old_tv
));
3225 tv
[0].tv_sec
= old_tv
[0].tv_sec
;
3226 tv
[0].tv_usec
= old_tv
[0].tv_usec
;
3227 tv
[1].tv_sec
= old_tv
[1].tv_sec
;
3228 tv
[1].tv_usec
= old_tv
[1].tv_usec
;
3232 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
3233 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
3239 setutimes(vfs_context_t ctx
, struct vnode
*vp
, const struct timespec
*ts
,
3243 struct vnode_attr va
;
3244 kauth_action_t action
;
3246 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3249 VATTR_SET(&va
, va_access_time
, ts
[0]);
3250 VATTR_SET(&va
, va_modify_time
, ts
[1]);
3252 va
.va_vaflags
|= VA_UTIMES_NULL
;
3254 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
3256 /* since we may not need to auth anything, check here */
3257 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
3259 error
= vnode_setattr(vp
, &va
, ctx
);
3266 * Set the access and modification times of a file.
3270 utimes(struct proc
*p
, register struct utimes_args
*uap
, __unused register_t
*retval
)
3272 struct timespec ts
[2];
3275 struct nameidata nd
;
3276 struct vfs_context context
;
3278 context
.vc_proc
= p
;
3279 context
.vc_ucred
= kauth_cred_get();
3281 /* AUDIT: Needed to change the order of operations to do the
3282 * name lookup first because auditing wants the path.
3284 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3285 UIO_USERSPACE
, uap
->path
, &context
);
3292 * Fetch the user-supplied time. If usrtvp is USER_ADDR_NULL, we fetch
3293 * the current time instead.
3296 if ((error
= getutimes(usrtvp
, ts
)) != 0)
3299 error
= setutimes(&context
, nd
.ni_vp
, ts
, usrtvp
== USER_ADDR_NULL
);
3302 vnode_put(nd
.ni_vp
);
3307 * Set the access and modification times of a file.
3311 futimes(struct proc
*p
, register struct futimes_args
*uap
, __unused register_t
*retval
)
3313 struct timespec ts
[2];
3317 struct vfs_context context
;
3319 context
.vc_proc
= p
;
3320 context
.vc_ucred
= kauth_cred_get();
3322 AUDIT_ARG(fd
, uap
->fd
);
3324 if ((error
= getutimes(usrtvp
, ts
)) != 0)
3326 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
3328 if((error
= vnode_getwithref(vp
))) {
3333 error
= setutimes(&context
, vp
, ts
, usrtvp
== 0);
3340 * Truncate a file given its path name.
3344 truncate(struct proc
*p
, register struct truncate_args
*uap
, __unused register_t
*retval
)
3346 register struct vnode
*vp
;
3347 struct vnode_attr va
;
3348 struct vfs_context context
;
3350 struct nameidata nd
;
3351 kauth_action_t action
;
3353 context
.vc_proc
= p
;
3354 context
.vc_ucred
= kauth_cred_get();
3356 if (uap
->length
< 0)
3358 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3359 UIO_USERSPACE
, uap
->path
, &context
);
3360 if ((error
= namei(&nd
)))
3367 VATTR_SET(&va
, va_data_size
, uap
->length
);
3368 if ((error
= vnode_authattr(vp
, &va
, &action
, &context
)) != 0)
3370 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0))
3372 error
= vnode_setattr(vp
, &va
, &context
);
3379 * Truncate a file given a file descriptor.
3383 ftruncate(p
, uap
, retval
)
3385 register struct ftruncate_args
*uap
;
3388 struct vfs_context context
;
3389 struct vnode_attr va
;
3391 struct fileproc
*fp
;
3395 context
.vc_proc
= current_proc();
3396 context
.vc_ucred
= kauth_cred_get();
3398 AUDIT_ARG(fd
, uap
->fd
);
3399 if (uap
->length
< 0)
3402 if ( (error
= fp_lookup(p
,fd
,&fp
,0)) ) {
3406 if (fp
->f_fglob
->fg_type
== DTYPE_PSXSHM
) {
3407 error
= pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
);
3410 if (fp
->f_fglob
->fg_type
!= DTYPE_VNODE
) {
3415 vp
= (struct vnode
*)fp
->f_fglob
->fg_data
;
3417 if ((fp
->f_fglob
->fg_flag
& FWRITE
) == 0) {
3418 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
3423 if ((error
= vnode_getwithref(vp
)) != 0) {
3427 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3430 VATTR_SET(&va
, va_data_size
, uap
->length
);
3431 error
= vnode_setattr(vp
, &va
, &context
);
3432 (void)vnode_put(vp
);
3440 * Sync an open file.
3444 fsync(struct proc
*p
, struct fsync_args
*uap
, __unused register_t
*retval
)
3447 struct fileproc
*fp
;
3448 struct vfs_context context
;
3451 if ( (error
= fp_getfvp(p
, uap
->fd
, &fp
, &vp
)) )
3453 if ( (error
= vnode_getwithref(vp
)) ) {
3457 context
.vc_proc
= p
;
3458 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
3460 error
= VNOP_FSYNC(vp
, MNT_WAIT
, &context
);
3462 (void)vnode_put(vp
);
3468 * Duplicate files. Source must be a file, target must be a file or
3471 * XXX Copyfile authorisation checking is woefully inadequate, and will not
3472 * perform inheritance correctly.
3476 copyfile(struct proc
*p
, register struct copyfile_args
*uap
, __unused register_t
*retval
)
3478 vnode_t tvp
, fvp
, tdvp
, sdvp
;
3479 struct nameidata fromnd
, tond
;
3481 struct vfs_context context
;
3483 context
.vc_proc
= p
;
3484 context
.vc_ucred
= kauth_cred_get();
3486 /* Check that the flags are valid. */
3488 if (uap
->flags
& ~CPF_MASK
) {
3492 NDINIT(&fromnd
, LOOKUP
, SAVESTART
| AUDITVNPATH1
,
3493 UIO_USERSPACE
, uap
->from
, &context
);
3494 if ((error
= namei(&fromnd
)))
3498 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
| AUDITVNPATH2
,
3499 UIO_USERSPACE
, uap
->to
, &context
);
3500 if ((error
= namei(&tond
))) {
3507 if (!(uap
->flags
& CPF_OVERWRITE
)) {
3512 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
3517 if ((error
= vnode_authorize(tdvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
3523 * If source is the same as the destination (that is the
3524 * same inode number) then there is nothing to do.
3525 * (fixed to have POSIX semantics - CSM 3/2/98)
3530 error
= VNOP_COPYFILE(fvp
,tdvp
,tvp
,&tond
.ni_cnd
,uap
->mode
,uap
->flags
,&context
);
3532 sdvp
= tond
.ni_startdir
;
3534 * nameidone has to happen before we vnode_put(tdvp)
3535 * since it may need to release the fs_nodelock on the tdvp
3546 if (fromnd
.ni_startdir
)
3547 vnode_put(fromnd
.ni_startdir
);
3557 * Rename files. Source and destination must either both be directories,
3558 * or both not be directories. If target is a directory, it must be empty.
3562 rename(proc_t p
, register struct rename_args
*uap
, __unused register_t
*retval
)
3566 struct nameidata fromnd
, tond
;
3567 struct vfs_context context
;
3570 char *oname
, *from_name
, *to_name
;
3571 int from_len
, to_len
;
3572 int holding_mntlock
;
3573 mount_t locked_mp
= NULL
;
3575 fse_info from_finfo
, to_finfo
;
3577 context
.vc_proc
= p
;
3578 context
.vc_ucred
= kauth_cred_get();
3579 holding_mntlock
= 0;
3585 NDINIT(&fromnd
, DELETE
, WANTPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->from
, &context
);
3587 if ( (error
= namei(&fromnd
)) )
3589 fdvp
= fromnd
.ni_dvp
;
3592 NDINIT(&tond
, RENAME
, WANTPARENT
| AUDITVNPATH2
, UIO_USERSPACE
, uap
->to
, &context
);
3593 if (fvp
->v_type
== VDIR
)
3594 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
3596 if ( (error
= namei(&tond
)) ) {
3598 * Translate error code for rename("dir1", "dir2/.").
3600 if (error
== EISDIR
&& fvp
->v_type
== VDIR
)
3608 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
3611 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
3624 * If tvp is a directory and not the same as fdvp, or tdvp is not the same as fdvp,
3625 * the node is moving between directories and we need rights to remove from the
3626 * old and add to the new.
3628 * If tvp already exists and is not a directory, we need to be allowed to delete it.
3630 * Note that we do not inherit when renaming. XXX this needs to be revisited to
3631 * implement the deferred-inherit bit.
3637 if ((tvp
!= NULL
) && vnode_isdir(tvp
)) {
3640 } else if (tdvp
!= fdvp
) {
3644 * must have delete rights to remove the old name even in the simple case of
3647 if ((error
= vnode_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
, &context
)) != 0)
3650 /* moving into tdvp or tvp, must have rights to add */
3651 if ((error
= vnode_authorize(((tvp
!= NULL
) && vnode_isdir(tvp
)) ? tvp
: tdvp
,
3653 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
3657 /* node staying in same directory, must be allowed to add new name */
3658 if ((error
= vnode_authorize(fdvp
, NULL
,
3659 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
3662 /* overwriting tvp */
3663 if ((tvp
!= NULL
) && !vnode_isdir(tvp
) &&
3664 ((error
= vnode_authorize(tvp
, tdvp
, KAUTH_VNODE_DELETE
, &context
)) != 0))
3667 /* XXX more checks? */
3670 /* authorization denied */
3675 * Allow the renaming of mount points.
3676 * - target must not exist
3677 * - target must reside in the same directory as source
3678 * - union mounts cannot be renamed
3679 * - "/" cannot be renamed
3681 if ((fvp
->v_flag
& VROOT
) &&
3682 (fvp
->v_type
== VDIR
) &&
3684 (fvp
->v_mountedhere
== NULL
) &&
3686 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
3687 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
3688 struct vnode
*coveredvp
;
3690 /* switch fvp to the covered vnode */
3691 coveredvp
= fvp
->v_mount
->mnt_vnodecovered
;
3692 if ( (vnode_getwithref(coveredvp
)) ) {
3702 * Check for cross-device rename.
3704 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
3705 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
3710 * Avoid renaming "." and "..".
3712 if (fvp
->v_type
== VDIR
&&
3714 (fromnd
.ni_cnd
.cn_namelen
== 1 && fromnd
.ni_cnd
.cn_nameptr
[0] == '.') ||
3715 ((fromnd
.ni_cnd
.cn_flags
| tond
.ni_cnd
.cn_flags
) & ISDOTDOT
)) ) {
3720 * The following edge case is caught here:
3721 * (to cannot be a descendent of from)
3734 if (tdvp
->v_parent
== fvp
) {
3740 * If source is the same as the destination (that is the
3741 * same inode number) then there is nothing to do...
3742 * EXCEPT if the underlying file system supports case
3743 * insensitivity and is case preserving. In this case
3744 * the file system needs to handle the special case of
3745 * getting the same vnode as target (fvp) and source (tvp).
3747 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
3748 * and _PC_CASE_PRESERVING can have this exception, and they need to
3749 * handle the special case of getting the same vnode as target and
3750 * source. NOTE: Then the target is unlocked going into vnop_rename,
3751 * so not to cause locking problems. There is a single reference on tvp.
3753 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
3754 * that correct behaviour then is just to remove the source (link)
3756 if (fvp
== tvp
&& fdvp
== tdvp
) {
3757 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
3758 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
3759 fromnd
.ni_cnd
.cn_namelen
)) {
3764 if (holding_mntlock
&& fvp
->v_mount
!= locked_mp
) {
3766 * we're holding a reference and lock
3767 * on locked_mp, but it no longer matches
3768 * what we want to do... so drop our hold
3770 mount_unlock_renames(locked_mp
);
3771 mount_drop(locked_mp
, 0);
3772 holding_mntlock
= 0;
3774 if (tdvp
!= fdvp
&& fvp
->v_type
== VDIR
) {
3776 * serialize renames that re-shape
3777 * the tree... if holding_mntlock is
3778 * set, then we're ready to go...
3780 * first need to drop the iocounts
3781 * we picked up, second take the
3782 * lock to serialize the access,
3783 * then finally start the lookup
3784 * process over with the lock held
3786 if (!holding_mntlock
) {
3788 * need to grab a reference on
3789 * the mount point before we
3790 * drop all the iocounts... once
3791 * the iocounts are gone, the mount
3794 locked_mp
= fvp
->v_mount
;
3795 mount_ref(locked_mp
, 0);
3798 * nameidone has to happen before we vnode_put(tvp)
3799 * since it may need to release the fs_nodelock on the tvp
3808 * nameidone has to happen before we vnode_put(fdvp)
3809 * since it may need to release the fs_nodelock on the fvp
3816 mount_lock_renames(locked_mp
);
3817 holding_mntlock
= 1;
3823 * when we dropped the iocounts to take
3824 * the lock, we allowed the identity of
3825 * the various vnodes to change... if they did,
3826 * we may no longer be dealing with a rename
3827 * that reshapes the tree... once we're holding
3828 * the iocounts, the vnodes can't change type
3829 * so we're free to drop the lock at this point
3832 if (holding_mntlock
) {
3833 mount_unlock_renames(locked_mp
);
3834 mount_drop(locked_mp
, 0);
3835 holding_mntlock
= 0;
3838 // save these off so we can later verify that fvp is the same
3839 oname
= fvp
->v_name
;
3840 oparent
= fvp
->v_parent
;
3842 if (need_fsevent(FSE_RENAME
, fvp
)) {
3843 get_fse_info(fvp
, &from_finfo
, &context
);
3846 get_fse_info(tvp
, &to_finfo
, &context
);
3848 from_name
= get_pathbuff();
3849 from_len
= MAXPATHLEN
;
3850 vn_getpath(fvp
, from_name
, &from_len
);
3852 to_name
= get_pathbuff();
3853 to_len
= MAXPATHLEN
;
3855 if (tvp
&& tvp
->v_type
!= VDIR
) {
3856 vn_getpath(tvp
, to_name
, &to_len
);
3858 vn_getpath(tdvp
, to_name
, &to_len
);
3859 // if the path is not just "/", then append a "/"
3861 to_name
[to_len
-1] = '/';
3865 strcpy(&to_name
[to_len
], tond
.ni_cnd
.cn_nameptr
);
3866 to_len
+= tond
.ni_cnd
.cn_namelen
+ 1;
3867 to_name
[to_len
] = '\0';
3873 error
= VNOP_RENAME(fdvp
, fvp
, &fromnd
.ni_cnd
,
3874 tdvp
, tvp
, &tond
.ni_cnd
,
3877 if (holding_mntlock
) {
3879 * we can drop our serialization
3882 mount_unlock_renames(locked_mp
);
3883 mount_drop(locked_mp
, 0);
3884 holding_mntlock
= 0;
3887 if (to_name
!= NULL
)
3888 release_pathbuff(to_name
);
3889 if (from_name
!= NULL
)
3890 release_pathbuff(from_name
);
3891 from_name
= to_name
= NULL
;
3896 /* call out to allow 3rd party notification of rename.
3897 * Ignore result of kauth_authorize_fileop call.
3899 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_RENAME
,
3900 (uintptr_t)from_name
, (uintptr_t)to_name
);
3902 if (from_name
!= NULL
&& to_name
!= NULL
) {
3904 add_fsevent(FSE_RENAME
, &context
,
3905 FSE_ARG_STRING
, from_len
, from_name
,
3906 FSE_ARG_FINFO
, &from_finfo
,
3907 FSE_ARG_STRING
, to_len
, to_name
,
3908 FSE_ARG_FINFO
, &to_finfo
,
3911 add_fsevent(FSE_RENAME
, &context
,
3912 FSE_ARG_STRING
, from_len
, from_name
,
3913 FSE_ARG_FINFO
, &from_finfo
,
3914 FSE_ARG_STRING
, to_len
, to_name
,
3918 if (to_name
!= NULL
)
3919 release_pathbuff(to_name
);
3920 if (from_name
!= NULL
)
3921 release_pathbuff(from_name
);
3922 from_name
= to_name
= NULL
;
3925 * update filesystem's mount point data
3928 char *cp
, *pathend
, *mpname
;
3934 mp
= fvp
->v_mountedhere
;
3936 if (vfs_busy(mp
, LK_NOWAIT
)) {
3940 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
3942 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
3944 /* find current mount point prefix */
3945 pathend
= &mp
->mnt_vfsstat
.f_mntonname
[0];
3946 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
3950 /* find last component of target name */
3951 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
3955 /* append name to prefix */
3956 maxlen
= MAXPATHLEN
- (pathend
- mp
->mnt_vfsstat
.f_mntonname
);
3957 bzero(pathend
, maxlen
);
3958 strncpy(pathend
, mpname
, maxlen
- 1);
3960 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
3965 * fix up name & parent pointers. note that we first
3966 * check that fvp has the same name/parent pointers it
3967 * had before the rename call... this is a 'weak' check
3970 if (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
) {
3973 update_flags
= VNODE_UPDATE_NAME
;
3976 update_flags
|= VNODE_UPDATE_PARENT
;
3978 vnode_update_identity(fvp
, tdvp
, tond
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_namelen
, tond
.ni_cnd
.cn_hash
, update_flags
);
3981 if (holding_mntlock
) {
3982 mount_unlock_renames(locked_mp
);
3983 mount_drop(locked_mp
, 0);
3987 * nameidone has to happen before we vnode_put(tdvp)
3988 * since it may need to release the fs_nodelock on the tdvp
3998 * nameidone has to happen before we vnode_put(fdvp)
3999 * since it may need to release the fs_nodelock on the fdvp
4011 * Make a directory file.
4015 mkdir1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
4019 int update_flags
= 0;
4020 struct nameidata nd
;
4022 AUDIT_ARG(mode
, vap
->va_mode
);
4023 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
4024 UIO_USERSPACE
, path
, ctx
);
4025 nd
.ni_cnd
.cn_flags
|= WILLBEDIR
;
4037 /* authorize addition of a directory to the parent */
4038 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
)) != 0)
4041 VATTR_SET(vap
, va_type
, VDIR
);
4043 /* make the directory */
4044 if ((error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
)) != 0)
4047 // Make sure the name & parent pointers are hooked up
4048 if (vp
->v_name
== NULL
)
4049 update_flags
|= VNODE_UPDATE_NAME
;
4050 if (vp
->v_parent
== NULLVP
)
4051 update_flags
|= VNODE_UPDATE_PARENT
;
4054 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
4056 add_fsevent(FSE_CREATE_DIR
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
4060 * nameidone has to happen before we vnode_put(dvp)
4061 * since it may need to release the fs_nodelock on the dvp
4074 mkdir_extended(struct proc
*p
, register struct mkdir_extended_args
*uap
, __unused register_t
*retval
)
4076 struct vfs_context context
;
4078 kauth_filesec_t xsecdst
;
4079 struct vnode_attr va
;
4082 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
4083 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
4086 context
.vc_proc
= p
;
4087 context
.vc_ucred
= kauth_cred_get();
4090 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
4091 if (xsecdst
!= NULL
)
4092 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
4094 ciferror
= mkdir1(&context
, uap
->path
, &va
);
4095 if (xsecdst
!= NULL
)
4096 kauth_filesec_free(xsecdst
);
4101 mkdir(struct proc
*p
, register struct mkdir_args
*uap
, __unused register_t
*retval
)
4103 struct vfs_context context
;
4104 struct vnode_attr va
;
4106 context
.vc_proc
= p
;
4107 context
.vc_ucred
= kauth_cred_get();
4110 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
4112 return(mkdir1(&context
, uap
->path
, &va
));
4116 * Remove a directory file.
4120 rmdir(struct proc
*p
, struct rmdir_args
*uap
, __unused register_t
*retval
)
4124 struct nameidata nd
;
4125 struct vfs_context context
;
4127 context
.vc_proc
= p
;
4128 context
.vc_ucred
= kauth_cred_get();
4130 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
4131 UIO_USERSPACE
, uap
->path
, &context
);
4138 if (vp
->v_type
!= VDIR
) {
4140 * rmdir only deals with directories
4143 } else if (dvp
== vp
) {
4145 * No rmdir "." please.
4148 } else if (vp
->v_flag
& VROOT
) {
4150 * The root of a mounted filesystem cannot be deleted.
4154 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, &context
);
4161 if (need_fsevent(FSE_DELETE
, dvp
)) {
4162 path
= get_pathbuff();
4164 vn_getpath(vp
, path
, &len
);
4165 get_fse_info(vp
, &finfo
, &context
);
4167 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, &context
);
4169 if (!error
&& path
!= NULL
) {
4170 add_fsevent(FSE_DELETE
, &context
,
4171 FSE_ARG_STRING
, len
, path
,
4172 FSE_ARG_FINFO
, &finfo
,
4176 release_pathbuff(path
);
4179 * nameidone has to happen before we vnode_put(dvp)
4180 * since it may need to release the fs_nodelock on the dvp
4192 * Read a block of directory entries in a file system independent format.
4195 getdirentries(p
, uap
, retval
)
4197 register struct getdirentries_args
*uap
;
4201 struct vfs_context context
;
4202 struct fileproc
*fp
;
4204 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4208 char uio_buf
[ UIO_SIZEOF(1) ];
4210 AUDIT_ARG(fd
, uap
->fd
);
4211 error
= fp_getfvp(p
, fd
, &fp
, &vp
);
4215 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
4216 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4220 if ( (error
= vnode_getwithref(vp
)) ) {
4224 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4227 if (vp
->v_type
!= VDIR
) {
4228 (void)vnode_put(vp
);
4232 context
.vc_proc
= p
;
4233 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
4235 loff
= fp
->f_fglob
->fg_offset
;
4236 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
4237 &uio_buf
[0], sizeof(uio_buf
));
4238 uio_addiov(auio
, uap
->buf
, uap
->count
);
4240 error
= VNOP_READDIR(vp
, auio
, 0, &eofflag
, (int *)NULL
, &context
);
4241 fp
->f_fglob
->fg_offset
= uio_offset(auio
);
4243 (void)vnode_put(vp
);
4249 if ((uap
->count
== uio_resid(auio
)) &&
4250 (vp
->v_op
== union_vnodeop_p
)) {
4253 lvp
= union_dircache(vp
, p
);
4254 if (lvp
!= NULLVP
) {
4255 struct vnode_attr va
;
4257 * If the directory is opaque,
4258 * then don't show lower entries
4261 VATTR_WANTED(&va
, va_flags
);
4262 error
= vnode_getattr(vp
, &va
, &context
);
4263 if (va
.va_flags
& OPAQUE
) {
4269 if (lvp
!= NULLVP
) {
4270 error
= VNOP_OPEN(lvp
, FREAD
, &context
);
4276 fp
->f_fglob
->fg_data
= (caddr_t
) lvp
;
4277 fp
->f_fglob
->fg_offset
= 0;
4278 error
= VNOP_CLOSE(vp
, FREAD
, &context
);
4290 if (((user_ssize_t
)uap
->count
== uio_resid(auio
)) &&
4291 (vp
->v_flag
& VROOT
) &&
4292 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
4293 struct vnode
*tvp
= vp
;
4294 vp
= vp
->v_mount
->mnt_vnodecovered
;
4295 vnode_getwithref(vp
);
4297 fp
->f_fglob
->fg_data
= (caddr_t
) vp
;
4298 fp
->f_fglob
->fg_offset
= 0;
4304 error
= copyout((caddr_t
)&loff
, uap
->basep
, sizeof(long));
4305 // LP64todo - fix this
4306 *retval
= uap
->count
- uio_resid(auio
);
4313 * Set the mode mask for creation of filesystem nodes.
4315 #warning XXX implement xsecurity
4317 #define UMASK_NOXSECURITY (void *)1 /* leave existing xsecurity alone */
4319 umask1(struct proc
*p
, int newmask
, __unused kauth_filesec_t fsec
, register_t
*retval
)
4321 register struct filedesc
*fdp
;
4323 AUDIT_ARG(mask
, newmask
);
4325 *retval
= fdp
->fd_cmask
;
4326 fdp
->fd_cmask
= newmask
& ALLPERMS
;
4332 umask_extended(struct proc
*p
, struct umask_extended_args
*uap
, register_t
*retval
)
4335 kauth_filesec_t xsecdst
;
4337 xsecdst
= KAUTH_FILESEC_NONE
;
4338 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
4339 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
4342 xsecdst
= KAUTH_FILESEC_NONE
;
4345 ciferror
= umask1(p
, uap
->newmask
, xsecdst
, retval
);
4347 if (xsecdst
!= KAUTH_FILESEC_NONE
)
4348 kauth_filesec_free(xsecdst
);
4353 umask(struct proc
*p
, struct umask_args
*uap
, register_t
*retval
)
4355 return(umask1(p
, uap
->newmask
, UMASK_NOXSECURITY
, retval
));
4359 * Void all references to file by ripping underlying filesystem
4364 revoke(struct proc
*p
, register struct revoke_args
*uap
, __unused register_t
*retval
)
4366 register struct vnode
*vp
;
4367 struct vnode_attr va
;
4368 struct vfs_context context
;
4370 struct nameidata nd
;
4372 context
.vc_proc
= p
;
4373 context
.vc_ucred
= kauth_cred_get();
4375 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4376 UIO_USERSPACE
, uap
->path
, &context
);
4385 VATTR_WANTED(&va
, va_uid
);
4386 if ((error
= vnode_getattr(vp
, &va
, &context
)))
4388 if (kauth_cred_getuid(context
.vc_ucred
) != va
.va_uid
&&
4389 (error
= suser(context
.vc_ucred
, &p
->p_acflag
)))
4391 if (vp
->v_usecount
> 1 || (vp
->v_flag
& VALIASED
))
4392 VNOP_REVOKE(vp
, REVOKEALL
, &context
);
4400 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
4401 * The following system calls are designed to support features
4402 * which are specific to the HFS & HFS Plus volume formats
4405 #ifdef __APPLE_API_OBSOLETE
4407 /************************************************/
4408 /* *** Following calls will be deleted soon *** */
4409 /************************************************/
4412 * Make a complex file. A complex file is one with multiple forks (data streams)
4416 mkcomplex(__unused
struct proc
*p
, __unused
struct mkcomplex_args
*uap
, __unused register_t
*retval
)
4422 * Extended stat call which returns volumeid and vnodeid as well as other info
4426 statv(__unused
struct proc
*p
,
4427 __unused
struct statv_args
*uap
,
4428 __unused register_t
*retval
)
4430 return (ENOTSUP
); /* We'll just return an error for now */
4432 } /* end of statv system call */
4435 * Extended lstat call which returns volumeid and vnodeid as well as other info
4439 lstatv(__unused
struct proc
*p
,
4440 __unused
struct lstatv_args
*uap
,
4441 __unused register_t
*retval
)
4443 return (ENOTSUP
); /* We'll just return an error for now */
4444 } /* end of lstatv system call */
4447 * Extended fstat call which returns volumeid and vnodeid as well as other info
4451 fstatv(__unused
struct proc
*p
,
4452 __unused
struct fstatv_args
*uap
,
4453 __unused register_t
*retval
)
4455 return (ENOTSUP
); /* We'll just return an error for now */
4456 } /* end of fstatv system call */
4459 /************************************************/
4460 /* *** Preceding calls will be deleted soon *** */
4461 /************************************************/
4463 #endif /* __APPLE_API_OBSOLETE */
4466 * Obtain attribute information on objects in a directory while enumerating
4467 * the directory. This call does not yet support union mounted directories.
4469 * 1.union mounted directories.
4474 getdirentriesattr (struct proc
*p
, struct getdirentriesattr_args
*uap
, register_t
*retval
)
4477 struct fileproc
*fp
;
4479 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4480 uint64_t actualcount
;
4485 struct attrlist attributelist
;
4486 struct vfs_context context
;
4488 char uio_buf
[ UIO_SIZEOF(1) ];
4489 kauth_action_t action
;
4493 /* Get the attributes into kernel space */
4494 if ((error
= copyin(uap
->alist
, (caddr_t
) &attributelist
, sizeof (attributelist
))))
4496 actualcount
= fuulong(uap
->count
);
4497 if (actualcount
== -1ULL)
4500 if ( (error
= fp_getfvp(p
, fd
, &fp
, &vp
)) )
4503 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
4504 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4508 if ( (error
= vnode_getwithref(vp
)) )
4511 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4513 if (vp
->v_type
!= VDIR
) {
4514 (void)vnode_put(vp
);
4519 /* set up the uio structure which will contain the users return buffer */
4520 loff
= fp
->f_fglob
->fg_offset
;
4521 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
4522 &uio_buf
[0], sizeof(uio_buf
));
4523 uio_addiov(auio
, uap
->buffer
, uap
->buffersize
);
4525 context
.vc_proc
= p
;
4526 context
.vc_ucred
= kauth_cred_get();
4527 tmpcount
= (u_long
) actualcount
;
4530 * If the only item requested is file names, we can let that past with
4531 * just LIST_DIRECTORY. If they want any other attributes, that means
4532 * they need SEARCH as well.
4534 action
= KAUTH_VNODE_LIST_DIRECTORY
;
4535 if ((attributelist
.commonattr
& ~ATTR_CMN_NAME
) ||
4536 attributelist
.fileattr
|| attributelist
.dirattr
)
4537 action
|= KAUTH_VNODE_SEARCH
;
4539 if ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) == 0)
4540 error
= VNOP_READDIRATTR(vp
, &attributelist
, auio
,
4541 tmpcount
, uap
->options
, &newstate
, &eofflag
,
4542 &tmpcount
, &context
);
4543 (void)vnode_put(vp
);
4544 actualcount
= tmpcount
;
4548 fp
->f_fglob
->fg_offset
= uio_offset(auio
); /* should be multiple of dirent, not variable */
4550 if ((error
= suulong(uap
->count
, actualcount
)) != 0)
4552 if ((error
= suulong(uap
->newstate
, (uint64_t)newstate
)) != 0)
4554 if ((error
= suulong(uap
->basep
, (uint64_t)loff
)) != 0)
4557 *retval
= eofflag
; /* similar to getdirentries */
4561 return (error
); /* return error earlier, an retval of 0 or 1 now */
4563 } /* end of getdirentryattr system call */
4566 * Exchange data between two files
4571 exchangedata (struct proc
*p
, register struct exchangedata_args
*uap
, __unused register_t
*retval
)
4574 struct nameidata fnd
, snd
;
4575 struct vfs_context context
;
4576 struct vnode
*fvp
, *svp
;
4582 fse_info f_finfo
, s_finfo
;
4584 context
.vc_proc
= p
;
4585 context
.vc_ucred
= kauth_cred_get();
4588 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4590 NDINIT(&fnd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4591 UIO_USERSPACE
, uap
->path1
, &context
);
4593 error
= namei(&fnd
);
4600 NDINIT(&snd
, LOOKUP
, nameiflags
| AUDITVNPATH2
,
4601 UIO_USERSPACE
, uap
->path2
, &context
);
4603 error
= namei(&snd
);
4612 * if the files are the same, return an inval error
4620 * if the files are on different volumes, return an error
4622 if (svp
->v_mount
!= fvp
->v_mount
) {
4626 if (((error
= vnode_authorize(fvp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0) ||
4627 ((error
= vnode_authorize(svp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0))
4630 if (need_fsevent(FSE_EXCHANGE
, fvp
) || kauth_authorize_fileop_has_listeners()) {
4631 fpath
= get_pathbuff();
4632 spath
= get_pathbuff();
4635 if (vn_getpath(fvp
, fpath
, &flen
) != 0 || fpath
[0] == '\0') {
4636 printf("exchange: vn_getpath(fvp=0x%x) failed <<%s>>\n",
4639 if (vn_getpath(svp
, spath
, &slen
) != 0 || spath
[0] == '\0') {
4640 printf("exchange: vn_getpath(svp=0x%x) failed <<%s>>\n",
4643 get_fse_info(fvp
, &f_finfo
, &context
);
4644 get_fse_info(svp
, &s_finfo
, &context
);
4646 /* Ok, make the call */
4647 error
= VNOP_EXCHANGE(fvp
, svp
, 0, &context
);
4652 if (fpath
!= NULL
&& spath
!= NULL
) {
4653 /* call out to allow 3rd party notification of exchangedata.
4654 * Ignore result of kauth_authorize_fileop call.
4656 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_EXCHANGE
,
4657 (uintptr_t)fpath
, (uintptr_t)spath
);
4661 tmpname
= fvp
->v_name
;
4662 fvp
->v_name
= svp
->v_name
;
4663 svp
->v_name
= tmpname
;
4665 if (fvp
->v_parent
!= svp
->v_parent
) {
4668 tmp
= fvp
->v_parent
;
4669 fvp
->v_parent
= svp
->v_parent
;
4670 svp
->v_parent
= tmp
;
4672 name_cache_unlock();
4674 if (fpath
!= NULL
&& spath
!= NULL
) {
4675 add_fsevent(FSE_EXCHANGE
, &context
,
4676 FSE_ARG_STRING
, flen
, fpath
,
4677 FSE_ARG_FINFO
, &f_finfo
,
4678 FSE_ARG_STRING
, slen
, spath
,
4679 FSE_ARG_FINFO
, &s_finfo
,
4684 release_pathbuff(spath
);
4686 release_pathbuff(fpath
);
4696 #ifdef __APPLE_API_OBSOLETE
4698 /************************************************/
4699 /* *** Following calls will be deleted soon *** */
4700 /************************************************/
4703 * Check users access to a file
4707 #warning "checkuseraccess copies a cred in from user space but"
4708 #warning "user space has no way of knowing what one looks like"
4709 #warning "this code should use the access_extended spoof-as functionality"
4711 checkuseraccess (struct proc
*p
, register struct checkuseraccess_args
*uap
, __unused register_t
*retval
)
4713 register struct vnode
*vp
;
4715 struct nameidata nd
;
4716 struct ucred template_cred
;
4717 int flags
; /*what will actually get passed to access*/
4719 struct vfs_context context
;
4720 kauth_cred_t my_cred
;
4722 /* Make sure that the number of groups is correct before we do anything */
4724 if ((uap
->ngroups
<= 0) || (uap
->ngroups
> NGROUPS
))
4727 /* Verify that the caller is root */
4729 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
4733 * Fill in the template credential structure; we use a template because
4734 * lookup can attempt to take a persistent reference.
4736 template_cred
.cr_uid
= uap
->userid
;
4737 template_cred
.cr_ngroups
= uap
->ngroups
;
4738 if ((error
= copyin(CAST_USER_ADDR_T(uap
->groups
), (caddr_t
) &(template_cred
.cr_groups
), (sizeof(gid_t
))*uap
->ngroups
)))
4741 my_cred
= kauth_cred_create(&template_cred
);
4742 context
.vc_proc
= p
;
4743 context
.vc_ucred
= my_cred
;
4745 /* Get our hands on the file */
4747 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4748 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4749 UIO_USERSPACE
, CAST_USER_ADDR_T(uap
->path
), &context
);
4751 if ((error
= namei(&nd
))) {
4752 kauth_cred_unref(&context
.vc_ucred
);
4758 /* Flags == 0 means only check for existence. */
4762 if (uap
->accessrequired
) {
4763 if (uap
->accessrequired
& R_OK
)
4764 flags
|= KAUTH_VNODE_READ_DATA
;
4765 if (uap
->accessrequired
& W_OK
)
4766 flags
|= KAUTH_VNODE_WRITE_DATA
;
4767 if (uap
->accessrequired
& X_OK
)
4768 flags
|= KAUTH_VNODE_EXECUTE
;
4770 error
= vnode_authorize(vp
, NULL
, flags
, &context
);
4774 kauth_cred_unref(&context
.vc_ucred
);
4776 } /* end of checkuseraccess system call */
4778 /************************************************/
4779 /* *** Preceding calls will be deleted soon *** */
4780 /************************************************/
4782 #endif /* __APPLE_API_OBSOLETE */
4789 searchfs (struct proc
*p
, register struct searchfs_args
*uap
, __unused register_t
*retval
)
4791 register struct vnode
*vp
;
4794 struct nameidata nd
;
4795 struct user_fssearchblock searchblock
;
4796 struct searchstate
*state
;
4797 struct attrlist
*returnattrs
;
4798 void *searchparams1
,*searchparams2
;
4800 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4804 struct vfs_context context
;
4805 char uio_buf
[ UIO_SIZEOF(1) ];
4807 context
.vc_proc
= p
;
4808 context
.vc_ucred
= kauth_cred_get();
4810 /* Start by copying in fsearchblock paramater list */
4811 if (IS_64BIT_PROCESS(p
)) {
4812 error
= copyin(uap
->searchblock
, (caddr_t
) &searchblock
, sizeof(searchblock
));
4815 struct fssearchblock tmp_searchblock
;
4816 error
= copyin(uap
->searchblock
, (caddr_t
) &tmp_searchblock
, sizeof(tmp_searchblock
));
4817 // munge into 64-bit version
4818 searchblock
.returnattrs
= CAST_USER_ADDR_T(tmp_searchblock
.returnattrs
);
4819 searchblock
.returnbuffer
= CAST_USER_ADDR_T(tmp_searchblock
.returnbuffer
);
4820 searchblock
.returnbuffersize
= tmp_searchblock
.returnbuffersize
;
4821 searchblock
.maxmatches
= tmp_searchblock
.maxmatches
;
4822 searchblock
.timelimit
.tv_sec
= tmp_searchblock
.timelimit
.tv_sec
;
4823 searchblock
.timelimit
.tv_usec
= tmp_searchblock
.timelimit
.tv_usec
;
4824 searchblock
.searchparams1
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams1
);
4825 searchblock
.sizeofsearchparams1
= tmp_searchblock
.sizeofsearchparams1
;
4826 searchblock
.searchparams2
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams2
);
4827 searchblock
.sizeofsearchparams2
= tmp_searchblock
.sizeofsearchparams2
;
4828 searchblock
.searchattrs
= tmp_searchblock
.searchattrs
;
4833 /* Do a sanity check on sizeofsearchparams1 and sizeofsearchparams2.
4835 if (searchblock
.sizeofsearchparams1
> SEARCHFS_MAX_SEARCHPARMS
||
4836 searchblock
.sizeofsearchparams2
> SEARCHFS_MAX_SEARCHPARMS
)
4839 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
4840 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
4841 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
4844 mallocsize
= searchblock
.sizeofsearchparams1
+ searchblock
.sizeofsearchparams2
+
4845 sizeof(struct attrlist
) + sizeof(struct searchstate
);
4847 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
4849 /* Now set up the various pointers to the correct place in our newly allocated memory */
4851 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
4852 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
4853 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
4855 /* Now copy in the stuff given our local variables. */
4857 if ((error
= copyin(searchblock
.searchparams1
, searchparams1
, searchblock
.sizeofsearchparams1
)))
4860 if ((error
= copyin(searchblock
.searchparams2
, searchparams2
, searchblock
.sizeofsearchparams2
)))
4863 if ((error
= copyin(searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
))))
4866 if ((error
= copyin(uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
))))
4869 /* set up the uio structure which will contain the users return buffer */
4871 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
4872 &uio_buf
[0], sizeof(uio_buf
));
4873 uio_addiov(auio
, searchblock
.returnbuffer
, searchblock
.returnbuffersize
);
4876 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4877 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4878 UIO_USERSPACE
, uap
->path
, &context
);
4889 * If searchblock.maxmatches == 0, then skip the search. This has happened
4890 * before and sometimes the underlyning code doesnt deal with it well.
4892 if (searchblock
.maxmatches
== 0) {
4898 Allright, we have everything we need, so lets make that call.
4900 We keep special track of the return value from the file system:
4901 EAGAIN is an acceptable error condition that shouldn't keep us
4902 from copying out any results...
4905 fserror
= VNOP_SEARCHFS(vp
,
4908 &searchblock
.searchattrs
,
4909 searchblock
.maxmatches
,
4910 &searchblock
.timelimit
,
4923 /* Now copy out the stuff that needs copying out. That means the number of matches, the
4924 search state. Everything was already put into he return buffer by the vop call. */
4926 if ((error
= copyout((caddr_t
) state
, uap
->state
, sizeof(struct searchstate
))) != 0)
4929 if ((error
= suulong(uap
->nummatches
, (uint64_t)nummatches
)) != 0)
4936 FREE(searchparams1
,M_TEMP
);
4941 } /* end of searchfs system call */
4945 * Make a filesystem-specific control call:
4949 fsctl (struct proc
*p
, struct fsctl_args
*uap
, __unused register_t
*retval
)
4953 struct nameidata nd
;
4955 u_long cmd
= uap
->cmd
;
4956 register u_int size
;
4957 #define STK_PARAMS 128
4958 char stkbuf
[STK_PARAMS
];
4960 struct vfs_context context
;
4962 context
.vc_proc
= p
;
4963 context
.vc_ucred
= kauth_cred_get();
4965 size
= IOCPARM_LEN(cmd
);
4966 if (size
> IOCPARM_MAX
) return (EINVAL
);
4968 is64bit
= proc_is64bit(p
);
4971 if (size
> sizeof (stkbuf
)) {
4972 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
4980 error
= copyin(uap
->data
, data
, size
);
4981 if (error
) goto FSCtl_Exit
;
4984 *(user_addr_t
*)data
= uap
->data
;
4987 *(uint32_t *)data
= (uint32_t)uap
->data
;
4990 } else if ((cmd
& IOC_OUT
) && size
) {
4992 * Zero the buffer so the user always
4993 * gets back something deterministic.
4996 } else if (cmd
& IOC_VOID
) {
4998 *(user_addr_t
*)data
= uap
->data
;
5001 *(uint32_t *)data
= (uint32_t)uap
->data
;
5005 /* Get the vnode for the file we are getting info on: */
5007 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
5008 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, uap
->path
, &context
);
5009 if ((error
= namei(&nd
))) goto FSCtl_Exit
;
5011 /* Invoke the filesystem-specific code */
5012 error
= VNOP_IOCTL(nd
.ni_vp
, IOCBASECMD(cmd
), data
, uap
->options
, &context
);
5014 vnode_put(nd
.ni_vp
);
5018 * Copy any data to user, size was
5019 * already set and checked above.
5021 if (error
== 0 && (cmd
& IOC_OUT
) && size
)
5022 error
= copyout(data
, uap
->data
, size
);
5025 if (memp
) kfree(memp
, size
);
5029 /* end of fsctl system call */
5032 * An in-kernel sync for power management to call.
5034 __private_extern__
int
5039 struct sync_args data
;
5044 error
= sync(current_proc(), &data
, &retval
[0]);
5048 } /* end of sync_internal call */
5052 * Retrieve the data of an extended attribute.
5055 getxattr(struct proc
*p
, struct getxattr_args
*uap
, user_ssize_t
*retval
)
5058 struct nameidata nd
;
5059 char attrname
[XATTR_MAXNAMELEN
+1];
5060 struct vfs_context context
;
5062 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5063 size_t attrsize
= 0;
5067 char uio_buf
[ UIO_SIZEOF(1) ];
5069 context
.vc_proc
= p
;
5070 context
.vc_ucred
= kauth_cred_get();
5072 if (uap
->options
& XATTR_NOSECURITY
)
5075 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5076 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5077 if ((error
= namei(&nd
))) {
5083 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5086 if (xattr_protected(attrname
)) {
5090 if (uap
->value
&& uap
->size
> 0) {
5091 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
5092 &uio_buf
[0], sizeof(uio_buf
));
5093 uio_addiov(auio
, uap
->value
, uap
->size
);
5096 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, &context
);
5101 *retval
= uap
->size
- uio_resid(auio
);
5103 *retval
= (user_ssize_t
)attrsize
;
5110 * Retrieve the data of an extended attribute.
5113 fgetxattr(struct proc
*p
, struct fgetxattr_args
*uap
, user_ssize_t
*retval
)
5116 char attrname
[XATTR_MAXNAMELEN
+1];
5117 struct vfs_context context
;
5119 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5120 size_t attrsize
= 0;
5123 char uio_buf
[ UIO_SIZEOF(1) ];
5125 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5128 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5131 if ( (error
= vnode_getwithref(vp
)) ) {
5135 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5138 if (xattr_protected(attrname
)) {
5142 if (uap
->value
&& uap
->size
> 0) {
5143 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
5144 &uio_buf
[0], sizeof(uio_buf
));
5145 uio_addiov(auio
, uap
->value
, uap
->size
);
5147 context
.vc_proc
= p
;
5148 context
.vc_ucred
= kauth_cred_get();
5150 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, &context
);
5152 (void)vnode_put(vp
);
5156 *retval
= uap
->size
- uio_resid(auio
);
5158 *retval
= (user_ssize_t
)attrsize
;
5164 * Set the data of an extended attribute.
5167 setxattr(struct proc
*p
, struct setxattr_args
*uap
, int *retval
)
5170 struct nameidata nd
;
5171 char attrname
[XATTR_MAXNAMELEN
+1];
5172 struct vfs_context context
;
5174 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5178 char uio_buf
[ UIO_SIZEOF(1) ];
5180 context
.vc_proc
= p
;
5181 context
.vc_ucred
= kauth_cred_get();
5183 if (uap
->options
& XATTR_NOSECURITY
)
5186 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5189 if (xattr_protected(attrname
))
5191 if (uap
->value
== 0 || uap
->size
== 0) {
5195 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5196 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5197 if ((error
= namei(&nd
))) {
5203 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
5204 &uio_buf
[0], sizeof(uio_buf
));
5205 uio_addiov(auio
, uap
->value
, uap
->size
);
5207 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, &context
);
5214 * Set the data of an extended attribute.
5217 fsetxattr(struct proc
*p
, struct fsetxattr_args
*uap
, int *retval
)
5220 char attrname
[XATTR_MAXNAMELEN
+1];
5221 struct vfs_context context
;
5223 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5226 char uio_buf
[ UIO_SIZEOF(1) ];
5228 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5231 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5234 if (xattr_protected(attrname
))
5236 if (uap
->value
== 0 || uap
->size
== 0) {
5239 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5242 if ( (error
= vnode_getwithref(vp
)) ) {
5246 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
5247 &uio_buf
[0], sizeof(uio_buf
));
5248 uio_addiov(auio
, uap
->value
, uap
->size
);
5249 context
.vc_proc
= p
;
5250 context
.vc_ucred
= kauth_cred_get();
5252 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, &context
);
5260 * Remove an extended attribute.
5262 #warning "code duplication"
5264 removexattr(struct proc
*p
, struct removexattr_args
*uap
, int *retval
)
5267 struct nameidata nd
;
5268 char attrname
[XATTR_MAXNAMELEN
+1];
5269 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5270 struct vfs_context context
;
5275 context
.vc_proc
= p
;
5276 context
.vc_ucred
= kauth_cred_get();
5278 if (uap
->options
& XATTR_NOSECURITY
)
5281 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
5285 if (xattr_protected(attrname
))
5287 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5288 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5289 if ((error
= namei(&nd
))) {
5295 error
= vn_removexattr(vp
, attrname
, uap
->options
, &context
);
5302 * Remove an extended attribute.
5304 #warning "code duplication"
5306 fremovexattr(struct proc
*p
, struct fremovexattr_args
*uap
, int *retval
)
5309 char attrname
[XATTR_MAXNAMELEN
+1];
5310 struct vfs_context context
;
5314 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5317 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
5321 if (xattr_protected(attrname
))
5323 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5326 if ( (error
= vnode_getwithref(vp
)) ) {
5330 context
.vc_proc
= p
;
5331 context
.vc_ucred
= kauth_cred_get();
5333 error
= vn_removexattr(vp
, attrname
, uap
->options
, &context
);
5341 * Retrieve the list of extended attribute names.
5343 #warning "code duplication"
5345 listxattr(struct proc
*p
, struct listxattr_args
*uap
, user_ssize_t
*retval
)
5348 struct nameidata nd
;
5349 struct vfs_context context
;
5351 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5352 size_t attrsize
= 0;
5355 char uio_buf
[ UIO_SIZEOF(1) ];
5357 context
.vc_proc
= p
;
5358 context
.vc_ucred
= kauth_cred_get();
5360 if (uap
->options
& XATTR_NOSECURITY
)
5363 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5364 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5365 if ((error
= namei(&nd
))) {
5370 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
5371 // LP64todo - fix this!
5372 auio
= uio_createwithbuffer(1, 0, spacetype
,
5373 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
5374 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
5377 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, &context
);
5381 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
5383 *retval
= (user_ssize_t
)attrsize
;
5389 * Retrieve the list of extended attribute names.
5391 #warning "code duplication"
5393 flistxattr(struct proc
*p
, struct flistxattr_args
*uap
, user_ssize_t
*retval
)
5396 struct vfs_context context
;
5398 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5399 size_t attrsize
= 0;
5401 char uio_buf
[ UIO_SIZEOF(1) ];
5403 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5406 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5409 if ( (error
= vnode_getwithref(vp
)) ) {
5413 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
5414 // LP64todo - fix this!
5415 auio
= uio_createwithbuffer(1, 0, spacetype
,
5416 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
5417 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
5419 context
.vc_proc
= p
;
5420 context
.vc_ucred
= kauth_cred_get();
5422 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, &context
);
5427 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
5429 *retval
= (user_ssize_t
)attrsize
;
5435 * Common routine to handle various flavors of statfs data heading out
5439 munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
5440 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
5441 boolean_t partial_copy
)
5444 int my_size
, copy_size
;
5447 struct user_statfs sfs
;
5448 my_size
= copy_size
= sizeof(sfs
);
5449 bzero(&sfs
, my_size
);
5450 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
5451 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
5452 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
5453 sfs
.f_bsize
= (user_long_t
)sfsp
->f_bsize
;
5454 sfs
.f_iosize
= (user_long_t
)sfsp
->f_iosize
;
5455 sfs
.f_blocks
= (user_long_t
)sfsp
->f_blocks
;
5456 sfs
.f_bfree
= (user_long_t
)sfsp
->f_bfree
;
5457 sfs
.f_bavail
= (user_long_t
)sfsp
->f_bavail
;
5458 sfs
.f_files
= (user_long_t
)sfsp
->f_files
;
5459 sfs
.f_ffree
= (user_long_t
)sfsp
->f_ffree
;
5460 sfs
.f_fsid
= sfsp
->f_fsid
;
5461 sfs
.f_owner
= sfsp
->f_owner
;
5462 strncpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
-1);
5463 strncpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
-1);
5464 strncpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
-1);
5467 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
5469 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
5473 my_size
= copy_size
= sizeof(sfs
);
5474 bzero(&sfs
, my_size
);
5476 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
5477 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
5478 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
5481 * It's possible for there to be more than 2^^31 blocks in the filesystem, so we
5482 * have to fudge the numbers here in that case. We inflate the blocksize in order
5483 * to reflect the filesystem size as best we can.
5485 if ((sfsp
->f_blocks
> LONG_MAX
)
5486 /* Hack for 4061702 . I think the real fix is for Carbon to
5487 * look for some volume capability and not depend on hidden
5488 * semantics agreed between a FS and carbon.
5489 * f_blocks, f_bfree, and f_bavail set to -1 is the trigger
5490 * for Carbon to set bNoVolumeSizes volume attribute.
5491 * Without this the webdavfs files cannot be copied onto
5492 * disk as they look huge. This change should not affect
5493 * XSAN as they should not setting these to -1..
5495 && (sfsp
->f_blocks
!= 0xffffffffffffffff)
5496 && (sfsp
->f_bfree
!= 0xffffffffffffffff)
5497 && (sfsp
->f_bavail
!= 0xffffffffffffffff)) {
5501 * Work out how far we have to shift the block count down to make it fit.
5502 * Note that it's possible to have to shift so far that the resulting
5503 * blocksize would be unreportably large. At that point, we will clip
5504 * any values that don't fit.
5506 * For safety's sake, we also ensure that f_iosize is never reported as
5507 * being smaller than f_bsize.
5509 for (shift
= 0; shift
< 32; shift
++) {
5510 if ((sfsp
->f_blocks
>> shift
) <= LONG_MAX
)
5512 if ((sfsp
->f_bsize
<< (shift
+ 1)) > LONG_MAX
)
5515 #define __SHIFT_OR_CLIP(x, s) ((((x) >> (s)) > LONG_MAX) ? LONG_MAX : ((x) >> (s)))
5516 sfs
.f_blocks
= (long)__SHIFT_OR_CLIP(sfsp
->f_blocks
, shift
);
5517 sfs
.f_bfree
= (long)__SHIFT_OR_CLIP(sfsp
->f_bfree
, shift
);
5518 sfs
.f_bavail
= (long)__SHIFT_OR_CLIP(sfsp
->f_bavail
, shift
);
5519 #undef __SHIFT_OR_CLIP
5520 sfs
.f_bsize
= (long)(sfsp
->f_bsize
<< shift
);
5521 sfs
.f_iosize
= lmax(sfsp
->f_iosize
, sfsp
->f_bsize
);
5523 /* filesystem is small enough to be reported honestly */
5524 sfs
.f_bsize
= (long)sfsp
->f_bsize
;
5525 sfs
.f_iosize
= (long)sfsp
->f_iosize
;
5526 sfs
.f_blocks
= (long)sfsp
->f_blocks
;
5527 sfs
.f_bfree
= (long)sfsp
->f_bfree
;
5528 sfs
.f_bavail
= (long)sfsp
->f_bavail
;
5530 sfs
.f_files
= (long)sfsp
->f_files
;
5531 sfs
.f_ffree
= (long)sfsp
->f_ffree
;
5532 sfs
.f_fsid
= sfsp
->f_fsid
;
5533 sfs
.f_owner
= sfsp
->f_owner
;
5534 strncpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
-1);
5535 strncpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
-1);
5536 strncpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
-1);
5539 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
5541 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
5544 if (sizep
!= NULL
) {
5551 * copy stat structure into user_stat structure.
5553 void munge_stat(struct stat
*sbp
, struct user_stat
*usbp
)
5555 bzero(usbp
, sizeof(struct user_stat
));
5557 usbp
->st_dev
= sbp
->st_dev
;
5558 usbp
->st_ino
= sbp
->st_ino
;
5559 usbp
->st_mode
= sbp
->st_mode
;
5560 usbp
->st_nlink
= sbp
->st_nlink
;
5561 usbp
->st_uid
= sbp
->st_uid
;
5562 usbp
->st_gid
= sbp
->st_gid
;
5563 usbp
->st_rdev
= sbp
->st_rdev
;
5564 #ifndef _POSIX_SOURCE
5565 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
5566 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
5567 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
5568 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
5569 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
5570 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
5572 usbp
->st_atime
= sbp
->st_atime
;
5573 usbp
->st_atimensec
= sbp
->st_atimensec
;
5574 usbp
->st_mtime
= sbp
->st_mtime
;
5575 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
5576 usbp
->st_ctime
= sbp
->st_ctime
;
5577 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
5579 usbp
->st_size
= sbp
->st_size
;
5580 usbp
->st_blocks
= sbp
->st_blocks
;
5581 usbp
->st_blksize
= sbp
->st_blksize
;
5582 usbp
->st_flags
= sbp
->st_flags
;
5583 usbp
->st_gen
= sbp
->st_gen
;
5584 usbp
->st_lspare
= sbp
->st_lspare
;
5585 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
5586 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];