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 <architecture/byte_order.h>
100 #include <libkern/OSAtomic.h>
104 * The currently logged-in user, for ownership of files/directories whose on-disk
105 * permissions are ignored:
109 static int change_dir(struct nameidata
*ndp
, vfs_context_t ctx
);
110 static int checkdirs(vnode_t olddp
, vfs_context_t ctx
);
111 void enablequotas(struct mount
*mp
, vfs_context_t ctx
);
112 static int getfsstat_callback(mount_t mp
, void * arg
);
113 static int getutimes(user_addr_t usrtvp
, struct timespec
*tsp
);
114 static int setutimes(vfs_context_t ctx
, struct vnode
*vp
, const struct timespec
*ts
, int nullflag
);
115 static int sync_callback(mount_t
, void *);
116 static int munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
117 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
118 boolean_t partial_copy
);
120 __private_extern__
int sync_internal(void);
122 #ifdef __APPLE_API_OBSOLETE
124 int fd
; /* file descriptor of the target file */
125 struct vstat
*vsb
; /* vstat structure for returned info */
128 const char *path
; /* pathname of the target file */
129 struct vstat
*vsb
; /* vstat structure for returned info */
131 struct mkcomplex_args
{
132 const char *path
; /* pathname of the file to be created */
133 mode_t mode
; /* access mode for the newly created file */
134 u_long type
; /* format of the complex file */
137 const char *path
; /* pathname of the target file */
138 struct vstat
*vsb
; /* vstat structure for returned info */
141 int fstatv(struct proc
*p
, struct fstatv_args
*uap
, register_t
*retval
);
142 int lstatv(struct proc
*p
, struct lstatv_args
*uap
, register_t
*retval
);
143 int mkcomplex(struct proc
*p
, struct mkcomplex_args
*uap
, register_t
*retval
);
144 int statv(struct proc
*p
, struct statv_args
*uap
, register_t
*retval
);
146 #endif /* __APPLE_API_OBSOLETE */
149 extern int (**union_vnodeop_p
)(void *);
150 extern struct vnode
*union_dircache(struct vnode
*, struct proc
*);
153 /* counts number of mount and unmount operations */
154 unsigned int vfs_nummntops
=0;
156 extern struct fileops vnops
;
158 extern void mount_list_add(mount_t mp
);
159 extern void mount_list_remove(mount_t mp
);
160 extern int mount_refdrain(mount_t mp
);
161 extern int vcount(struct vnode
*vp
);
165 * Virtual File System System Calls
169 * Mount a file system.
173 mount(struct proc
*p
, register struct mount_args
*uap
, __unused register_t
*retval
)
176 struct vnode
*devvp
= NULLVP
;
177 struct vnode
*device_vnode
= NULLVP
;
179 struct vfstable
*vfsp
= (struct vfstable
*)0;
181 struct vnode_attr va
;
182 struct vfs_context context
;
184 struct nameidata nd1
;
185 char fstypename
[MFSNAMELEN
];
187 user_addr_t devpath
= USER_ADDR_NULL
;
188 user_addr_t fsmountargs
= uap
->data
;
193 boolean_t is_rwlock_locked
= FALSE
;
195 AUDIT_ARG(fflags
, uap
->flags
);
198 context
.vc_ucred
= kauth_cred_get();
199 is_64bit
= proc_is64bit(p
);
202 * Get vnode to be covered
204 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
205 UIO_USERSPACE
, uap
->path
, &context
);
211 if ((vp
->v_flag
& VROOT
) &&
212 (vp
->v_mount
->mnt_flag
& MNT_ROOTFS
))
213 uap
->flags
|= MNT_UPDATE
;
215 if (uap
->flags
& MNT_UPDATE
) {
216 if ((vp
->v_flag
& VROOT
) == 0) {
222 /* unmount in progress return error */
224 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
230 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
231 is_rwlock_locked
= TRUE
;
233 * We only allow the filesystem to be reloaded if it
234 * is currently mounted read-only.
236 if ((uap
->flags
& MNT_RELOAD
) &&
237 ((mp
->mnt_flag
& MNT_RDONLY
) == 0)) {
242 * Only root, or the user that did the original mount is
243 * permitted to update it.
245 if (mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(context
.vc_ucred
) &&
246 (error
= suser(context
.vc_ucred
, &p
->p_acflag
))) {
250 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV,
251 * and MNT_NOEXEC if mount point is already MNT_NOEXEC.
253 if (suser(context
.vc_ucred
, NULL
)) {
254 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
255 if (mp
->mnt_flag
& MNT_NOEXEC
)
256 uap
->flags
|= MNT_NOEXEC
;
261 uap
->flags
& (MNT_RELOAD
| MNT_FORCE
| MNT_UPDATE
);
263 vfsp
= mp
->mnt_vtable
;
267 * If the user is not root, ensure that they own the directory
268 * onto which we are attempting to mount.
271 VATTR_WANTED(&va
, va_uid
);
272 if ((error
= vnode_getattr(vp
, &va
, &context
)) ||
273 (va
.va_uid
!= kauth_cred_getuid(context
.vc_ucred
) &&
274 (error
= suser(context
.vc_ucred
, &p
->p_acflag
)))) {
278 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV, and
279 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
281 if (suser(context
.vc_ucred
, NULL
)) {
282 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
283 if (vp
->v_mount
->mnt_flag
& MNT_NOEXEC
)
284 uap
->flags
|= MNT_NOEXEC
;
286 if ( (error
= VNOP_FSYNC(vp
, MNT_WAIT
, &context
)) )
289 if ( (error
= buf_invalidateblks(vp
, BUF_WRITE_DATA
, 0, 0)) )
292 if (vp
->v_type
!= VDIR
) {
296 if ( (error
= copyinstr(uap
->type
, fstypename
, MFSNAMELEN
, &dummy
)) )
299 /* XXXAUDIT: Should we capture the type on the error path as well? */
300 AUDIT_ARG(text
, fstypename
);
302 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
303 if (!strcmp(vfsp
->vfc_name
, fstypename
))
310 if (ISSET(vp
->v_flag
, VMOUNT
) && (vp
->v_mountedhere
!= NULL
)) {
315 SET(vp
->v_flag
, VMOUNT
);
319 * Allocate and initialize the filesystem.
321 MALLOC_ZONE(mp
, struct mount
*, (u_long
)sizeof(struct mount
),
323 bzero((char *)mp
, (u_long
)sizeof(struct mount
));
326 /* Initialize the default IO constraints */
327 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
328 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
329 mp
->mnt_maxsegreadsize
= mp
->mnt_maxreadcnt
;
330 mp
->mnt_maxsegwritesize
= mp
->mnt_maxwritecnt
;
331 mp
->mnt_devblocksize
= DEV_BSIZE
;
333 TAILQ_INIT(&mp
->mnt_vnodelist
);
334 TAILQ_INIT(&mp
->mnt_workerqueue
);
335 TAILQ_INIT(&mp
->mnt_newvnodes
);
337 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
338 is_rwlock_locked
= TRUE
;
339 mp
->mnt_op
= vfsp
->vfc_vfsops
;
340 mp
->mnt_vtable
= vfsp
;
342 vfsp
->vfc_refcount
++;
344 //mp->mnt_stat.f_type = vfsp->vfc_typenum;
345 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
346 strncpy(mp
->mnt_vfsstat
.f_fstypename
, vfsp
->vfc_name
, MFSTYPENAMELEN
);
347 strncpy(mp
->mnt_vfsstat
.f_mntonname
, nd
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
348 mp
->mnt_vnodecovered
= vp
;
349 mp
->mnt_vfsstat
.f_owner
= kauth_cred_getuid(context
.vc_ucred
);
351 /* XXX 3762912 hack to support HFS filesystem 'owner' - filesystem may update later */
352 vfs_setowner(mp
, KAUTH_UID_NONE
, KAUTH_GID_NONE
);
356 * Set the mount level flags.
358 if (uap
->flags
& MNT_RDONLY
)
359 mp
->mnt_flag
|= MNT_RDONLY
;
360 else if (mp
->mnt_flag
& MNT_RDONLY
)
361 mp
->mnt_kern_flag
|= MNTK_WANTRDWR
;
362 mp
->mnt_flag
&= ~(MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
363 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
364 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
);
365 mp
->mnt_flag
|= uap
->flags
& (MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
366 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
367 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
|
370 if (vfsp
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
372 if ( (error
= copyin(fsmountargs
, (caddr_t
)&devpath
, sizeof(devpath
))) )
374 fsmountargs
+= sizeof(devpath
);
377 if ( (error
= copyin(fsmountargs
, (caddr_t
)&tmp
, sizeof(tmp
))) )
379 /* munge into LP64 addr */
380 devpath
= CAST_USER_ADDR_T(tmp
);
381 fsmountargs
+= sizeof(tmp
);
384 /* if it is not update and device name needs to be parsed */
386 NDINIT(&nd1
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, devpath
, &context
);
387 if ( (error
= namei(&nd1
)) )
390 strncpy(mp
->mnt_vfsstat
.f_mntfromname
, nd1
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
395 if (devvp
->v_type
!= VBLK
) {
399 if (major(devvp
->v_rdev
) >= nblkdev
) {
404 * If mount by non-root, then verify that user has necessary
405 * permissions on the device.
407 if (suser(context
.vc_ucred
, NULL
) != 0) {
408 accessmode
= KAUTH_VNODE_READ_DATA
;
409 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
410 accessmode
|= KAUTH_VNODE_WRITE_DATA
;
411 if ((error
= vnode_authorize(devvp
, NULL
, accessmode
, &context
)) != 0)
415 if (devpath
&& ((uap
->flags
& MNT_UPDATE
) == 0)) {
416 if ( (error
= vnode_ref(devvp
)) )
419 * Disallow multiple mounts of the same device.
420 * Disallow mounting of a device that is currently in use
421 * (except for root, which might share swap device for miniroot).
422 * Flush out any old buffers remaining from a previous use.
424 if ( (error
= vfs_mountedon(devvp
)) )
427 if (vcount(devvp
) > 1 && !(vfs_flags(mp
) & MNT_ROOTFS
)) {
431 if ( (error
= VNOP_FSYNC(devvp
, MNT_WAIT
, &context
)) ) {
435 if ( (error
= buf_invalidateblks(devvp
, BUF_WRITE_DATA
, 0, 0)) )
438 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
439 if ( (error
= VNOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, &context
)) )
442 mp
->mnt_devvp
= devvp
;
443 device_vnode
= devvp
;
445 if ((mp
->mnt_flag
& MNT_RDONLY
) && (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)) {
447 * If upgrade to read-write by non-root, then verify
448 * that user has necessary permissions on the device.
450 device_vnode
= mp
->mnt_devvp
;
451 if (device_vnode
&& suser(context
.vc_ucred
, NULL
)) {
452 if ((error
= vnode_authorize(device_vnode
, NULL
,
453 KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0)
457 device_vnode
= NULLVP
;
463 * Mount the filesystem.
465 error
= VFS_MOUNT(mp
, device_vnode
, fsmountargs
, &context
);
467 if (uap
->flags
& MNT_UPDATE
) {
468 if (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)
469 mp
->mnt_flag
&= ~MNT_RDONLY
;
471 (MNT_UPDATE
| MNT_RELOAD
| MNT_FORCE
);
472 mp
->mnt_kern_flag
&=~ MNTK_WANTRDWR
;
475 vfs_event_signal(NULL
, VQ_UPDATE
, (intptr_t)NULL
);
476 lck_rw_done(&mp
->mnt_rwlock
);
477 is_rwlock_locked
= FALSE
;
479 enablequotas(mp
,&context
);
483 * Put the new filesystem on the mount list after root.
487 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
)
555 (void)VFS_UNMOUNT(mp
, MNT_FORCE
, &context
);
556 if (device_vnode
!= NULLVP
) {
557 VNOP_CLOSE(device_vnode
, mp
->mnt_flag
& MNT_RDONLY
? FREAD
: FREAD
|FWRITE
, &context
);
560 vp
->v_mountedhere
= (mount_t
) 0;
566 if (devpath
&& devvp
)
569 /* Release mnt_rwlock only when it was taken */
570 if (is_rwlock_locked
== TRUE
) {
571 lck_rw_done(&mp
->mnt_rwlock
);
575 vfsp
->vfc_refcount
--;
577 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
587 enablequotas(struct mount
*mp
, vfs_context_t context
)
589 struct nameidata qnd
;
591 char qfpath
[MAXPATHLEN
];
592 const char *qfname
= QUOTAFILENAME
;
593 const char *qfopsname
= QUOTAOPSNAME
;
594 const char *qfextension
[] = INITQFNAMES
;
596 if ((strcmp(mp
->mnt_vfsstat
.f_fstypename
, "hfs") != 0 )
597 && (strcmp( mp
->mnt_vfsstat
.f_fstypename
, "ufs") != 0))
601 * Enable filesystem disk quotas if necessary.
602 * We ignore errors as this should not interfere with final mount
604 for (type
=0; type
< MAXQUOTAS
; type
++) {
605 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfopsname
, qfextension
[type
]);
606 NDINIT(&qnd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE32
, CAST_USER_ADDR_T(qfpath
), context
);
607 if (namei(&qnd
) != 0)
608 continue; /* option file to trigger quotas is not present */
609 vnode_put(qnd
.ni_vp
);
611 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfname
, qfextension
[type
]);
613 (void) VFS_QUOTACTL(mp
, QCMD(Q_QUOTAON
, type
), 0, qfpath
, context
);
619 * Scan all active processes to see if any of them have a current
620 * or root directory onto which the new filesystem has just been
621 * mounted. If so, replace them with the new mount point.
624 checkdirs(olddp
, context
)
626 vfs_context_t context
;
628 struct filedesc
*fdp
;
632 struct vnode
*fdp_cvp
;
633 struct vnode
*fdp_rvp
;
634 int cdir_changed
= 0;
635 int rdir_changed
= 0;
636 boolean_t funnel_state
;
639 if (olddp
->v_usecount
== 1)
641 err
= VFS_ROOT(olddp
->v_mountedhere
, &newdp
, context
);
644 panic("mount: lost mount");
648 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
650 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
653 if (fdp
== (struct filedesc
*)0) {
657 fdp_cvp
= fdp
->fd_cdir
;
658 fdp_rvp
= fdp
->fd_rdir
;
661 if (fdp_cvp
== olddp
) {
668 if (fdp_rvp
== olddp
) {
675 if (cdir_changed
|| rdir_changed
) {
677 fdp
->fd_cdir
= fdp_cvp
;
678 fdp
->fd_rdir
= fdp_rvp
;
682 if (rootvnode
== olddp
) {
688 thread_funnel_set(kernel_flock
, funnel_state
);
695 * Unmount a file system.
697 * Note: unmount takes a path to the vnode mounted on as argument,
698 * not special file (as before).
702 unmount(struct proc
*p
, register struct unmount_args
*uap
, __unused register_t
*retval
)
704 register struct vnode
*vp
;
708 struct vfs_context context
;
711 context
.vc_ucred
= kauth_cred_get();
713 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
714 UIO_USERSPACE
, uap
->path
, &context
);
723 * Must be the root of the filesystem
725 if ((vp
->v_flag
& VROOT
) == 0) {
731 /* safedounmount consumes the mount ref */
732 return (safedounmount(mp
, uap
->flags
, p
));
736 * The mount struct comes with a mount ref which will be consumed.
737 * Do the actual file system unmount, prevent some common foot shooting.
739 * XXX Should take a "vfs_context_t" instead of a "struct proc *"
742 safedounmount(mp
, flags
, p
)
750 * Only root, or the user that did the original mount is
751 * permitted to unmount this filesystem.
753 if ((mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(kauth_cred_get())) &&
754 (error
= suser(kauth_cred_get(), &p
->p_acflag
))) {
759 * Don't allow unmounting the root file system.
761 if (mp
->mnt_flag
& MNT_ROOTFS
) {
766 return (dounmount(mp
, flags
, 1, p
));
773 * Do the actual file system unmount.
776 dounmount(mp
, flags
, withref
, p
)
777 register struct mount
*mp
;
782 struct vnode
*coveredvp
= (vnode_t
)0;
785 struct vfs_context context
;
786 int forcedunmount
= 0;
790 context
.vc_ucred
= kauth_cred_get();
792 if (flags
& MNT_FORCE
)
795 /* XXX post jaguar fix LK_DRAIN - then clean this up */
796 if ((flags
& MNT_FORCE
)) {
797 mp
->mnt_kern_flag
|= MNTK_FRCUNMOUNT
;
798 mp
->mnt_lflag
|= MNT_LFORCE
;
800 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
801 mp
->mnt_lflag
|= MNT_LWAIT
;
804 msleep((caddr_t
)mp
, &mp
->mnt_mlock
, (PVFS
| PDROP
), "dounmount", 0 );
806 * The prior unmount attempt has probably succeeded.
807 * Do not dereference mp here - returning EBUSY is safest.
811 mp
->mnt_kern_flag
|= MNTK_UNMOUNT
;
812 mp
->mnt_lflag
|= MNT_LUNMOUNT
;
813 mp
->mnt_flag
&=~ MNT_ASYNC
;
815 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
818 fsevent_unmount(mp
); /* has to come first! */
820 if (forcedunmount
== 0) {
821 ubc_umount(mp
); /* release cached vnodes */
822 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
823 error
= VFS_SYNC(mp
, MNT_WAIT
, &context
);
826 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
827 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
828 mp
->mnt_lflag
&= ~MNT_LFORCE
;
835 lflags
|= FORCECLOSE
;
836 error
= vflush(mp
, NULLVP
, SKIPSWAP
| SKIPSYSTEM
| SKIPROOT
| lflags
);
837 if ((forcedunmount
== 0) && error
) {
839 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
840 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
841 mp
->mnt_lflag
&= ~MNT_LFORCE
;
845 /* make sure there are no one in the mount iterations or lookup */
848 error
= VFS_UNMOUNT(mp
, flags
, &context
);
852 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
853 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
854 mp
->mnt_lflag
&= ~MNT_LFORCE
;
858 /* increment the operations count */
860 OSAddAtomic(1, (SInt32
*)&vfs_nummntops
);
862 if ( mp
->mnt_devvp
&& mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
863 mp
->mnt_devvp
->v_specflags
&= ~SI_MOUNTEDON
;
864 VNOP_CLOSE(mp
->mnt_devvp
, mp
->mnt_flag
& MNT_RDONLY
? FREAD
: FREAD
|FWRITE
,
866 vnode_rele(mp
->mnt_devvp
);
868 lck_rw_done(&mp
->mnt_rwlock
);
869 mount_list_remove(mp
);
870 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
872 /* mark the mount point hook in the vp but not drop the ref yet */
873 if ((coveredvp
= mp
->mnt_vnodecovered
) != NULLVP
) {
874 vnode_getwithref(coveredvp
);
875 vnode_lock(coveredvp
);
876 coveredvp
->v_mountedhere
= (struct mount
*)0;
877 vnode_unlock(coveredvp
);
878 vnode_put(coveredvp
);
882 mp
->mnt_vtable
->vfc_refcount
--;
885 cache_purgevfs(mp
); /* remove cache entries for this file sys */
886 vfs_event_signal(NULL
, VQ_UNMOUNT
, (intptr_t)NULL
);
888 mp
->mnt_lflag
|= MNT_LDEAD
;
890 if (mp
->mnt_lflag
& MNT_LWAIT
) {
893 * in case we block in mount_refdrain
894 * which will drop the mount lock
895 * and allow anyone blocked in vfs_busy
896 * to wakeup and see the LDEAD state
898 mp
->mnt_lflag
&= ~MNT_LWAIT
;
903 if (mp
->mnt_lflag
& MNT_LWAIT
) {
904 mp
->mnt_lflag
&= ~MNT_LWAIT
;
908 lck_rw_done(&mp
->mnt_rwlock
);
913 if ((coveredvp
!= NULLVP
)) {
914 vnode_getwithref(coveredvp
);
915 vnode_rele(coveredvp
);
916 vnode_lock(coveredvp
);
917 if(mp
->mnt_crossref
== 0) {
918 vnode_unlock(coveredvp
);
919 mount_lock_destroy(mp
);
920 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
922 coveredvp
->v_lflag
|= VL_MOUNTDEAD
;
923 vnode_unlock(coveredvp
);
925 vnode_put(coveredvp
);
926 } else if (mp
->mnt_flag
& MNT_ROOTFS
) {
927 mount_lock_destroy(mp
);
928 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
930 panic("dounmount: no coveredvp");
936 mount_dropcrossref(mount_t mp
, vnode_t dp
, int need_put
)
940 if (mp
->mnt_crossref
< 0)
941 panic("mount cross refs -ve");
942 if (((dp
->v_lflag
& VL_MOUNTDEAD
) == VL_MOUNTDEAD
) && (mp
->mnt_crossref
== 0)) {
943 dp
->v_lflag
&= ~VL_MOUNTDEAD
;
945 vnode_put_locked(dp
);
947 mount_lock_destroy(mp
);
948 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
952 vnode_put_locked(dp
);
958 * Sync each mounted filesystem.
962 struct ctldebug debug0
= { "syncprt", &syncprt
};
965 int print_vmpage_stat
=0;
968 sync_callback(mount_t mp
, __unused
void * arg
)
970 struct proc
* p
= current_proc();
972 struct vfs_context context
;
975 context
.vc_ucred
= kauth_cred_get();
977 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
978 asyncflag
= mp
->mnt_flag
& MNT_ASYNC
;
979 mp
->mnt_flag
&= ~MNT_ASYNC
;
980 VFS_SYNC(mp
, MNT_NOWAIT
, &context
);
982 mp
->mnt_flag
|= MNT_ASYNC
;
984 return(VFS_RETURNED
);
988 extern unsigned int vp_pagein
, vp_pgodirty
, vp_pgoclean
;
989 extern unsigned int dp_pgins
, dp_pgouts
;
993 sync(__unused
struct proc
*p
, __unused
struct sync_args
*uap
, __unused register_t
*retval
)
996 vfs_iterate(LK_NOWAIT
, sync_callback
, (void *)0);
998 if(print_vmpage_stat
) {
999 vm_countdirtypages();
1000 printf("VP: %d: %d: %d: %d: %d\n", vp_pgodirty
, vp_pgoclean
, vp_pagein
,
1001 dp_pgins
, dp_pgouts
);
1007 #endif /* DIAGNOSTIC */
1012 * Change filesystem quotas.
1016 quotactl(struct proc
*p
, register struct quotactl_args
*uap
, __unused register_t
*retval
)
1018 register struct mount
*mp
;
1019 int error
, quota_cmd
, quota_status
;
1022 struct nameidata nd
;
1023 struct vfs_context context
;
1024 struct dqblk my_dqblk
;
1026 context
.vc_proc
= p
;
1027 context
.vc_ucred
= kauth_cred_get();
1029 AUDIT_ARG(uid
, uap
->uid
, 0, 0, 0);
1030 AUDIT_ARG(cmd
, uap
->cmd
);
1031 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1032 UIO_USERSPACE
, uap
->path
, &context
);
1036 mp
= nd
.ni_vp
->v_mount
;
1037 vnode_put(nd
.ni_vp
);
1040 /* copyin any data we will need for downstream code */
1041 quota_cmd
= uap
->cmd
>> SUBCMDSHIFT
;
1043 switch (quota_cmd
) {
1045 /* uap->arg specifies a file from which to take the quotas */
1046 fnamelen
= MAXPATHLEN
;
1047 datap
= kalloc(MAXPATHLEN
);
1048 error
= copyinstr(uap
->arg
, datap
, MAXPATHLEN
, &fnamelen
);
1051 /* uap->arg is a pointer to a dqblk structure. */
1052 datap
= (caddr_t
) &my_dqblk
;
1056 /* uap->arg is a pointer to a dqblk structure. */
1057 datap
= (caddr_t
) &my_dqblk
;
1058 if (proc_is64bit(p
)) {
1059 struct user_dqblk my_dqblk64
;
1060 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk64
, sizeof (my_dqblk64
));
1062 munge_dqblk(&my_dqblk
, &my_dqblk64
, FALSE
);
1066 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk
, sizeof (my_dqblk
));
1070 /* uap->arg is a pointer to an integer */
1071 datap
= (caddr_t
) "a_status
;
1079 error
= VFS_QUOTACTL(mp
, uap
->cmd
, uap
->uid
, datap
, &context
);
1082 switch (quota_cmd
) {
1085 kfree(datap
, MAXPATHLEN
);
1088 /* uap->arg is a pointer to a dqblk structure we need to copy out to */
1090 if (proc_is64bit(p
)) {
1091 struct user_dqblk my_dqblk64
;
1092 munge_dqblk(&my_dqblk
, &my_dqblk64
, TRUE
);
1093 error
= copyout((caddr_t
)&my_dqblk64
, uap
->arg
, sizeof (my_dqblk64
));
1096 error
= copyout(datap
, uap
->arg
, sizeof (struct dqblk
));
1101 /* uap->arg is a pointer to an integer */
1103 error
= copyout(datap
, uap
->arg
, sizeof(quota_status
));
1114 * Get filesystem statistics.
1118 statfs(struct proc
*p
, register struct statfs_args
*uap
, __unused register_t
*retval
)
1121 struct vfsstatfs
*sp
;
1123 struct nameidata nd
;
1124 struct vfs_context context
;
1127 context
.vc_proc
= p
;
1128 context
.vc_ucred
= kauth_cred_get();
1130 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1131 UIO_USERSPACE
, uap
->path
, &context
);
1137 sp
= &mp
->mnt_vfsstat
;
1140 error
= vfs_update_vfsstat(mp
, &context
);
1145 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1150 * Get filesystem statistics.
1154 fstatfs(struct proc
*p
, register struct fstatfs_args
*uap
, __unused register_t
*retval
)
1158 struct vfsstatfs
*sp
;
1160 struct vfs_context context
;
1162 context
.vc_proc
= p
;
1163 context
.vc_ucred
= kauth_cred_get();
1165 AUDIT_ARG(fd
, uap
->fd
);
1167 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1170 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
1177 sp
= &mp
->mnt_vfsstat
;
1178 if ((error
= vfs_update_vfsstat(mp
, &context
)) != 0) {
1184 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1190 struct getfsstat_struct
{
1200 getfsstat_callback(mount_t mp
, void * arg
)
1203 struct getfsstat_struct
*fstp
= (struct getfsstat_struct
*)arg
;
1204 struct vfsstatfs
*sp
;
1205 struct proc
* p
= current_proc();
1207 struct vfs_context context
;
1209 context
.vc_proc
= p
;
1210 context
.vc_ucred
= kauth_cred_get();
1212 if (fstp
->sfsp
&& fstp
->count
< fstp
->maxcount
) {
1213 sp
= &mp
->mnt_vfsstat
;
1215 * If MNT_NOWAIT is specified, do not refresh the
1216 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
1218 if (((fstp
->flags
& MNT_NOWAIT
) == 0 || (fstp
->flags
& MNT_WAIT
)) &&
1219 (error
= vfs_update_vfsstat(mp
, &context
))) {
1220 KAUTH_DEBUG("vfs_update_vfsstat returned %d", error
);
1221 return(VFS_RETURNED
);
1225 * Need to handle LP64 version of struct statfs
1227 error
= munge_statfs(mp
, sp
, fstp
->sfsp
, &my_size
, IS_64BIT_PROCESS(p
), FALSE
);
1229 fstp
->error
= error
;
1230 return(VFS_RETURNED_DONE
);
1232 fstp
->sfsp
+= my_size
;
1235 return(VFS_RETURNED
);
1239 * Get statistics on all filesystems.
1242 getfsstat(__unused proc_t p
, struct getfsstat_args
*uap
, int *retval
)
1245 int count
, maxcount
;
1246 struct getfsstat_struct fst
;
1248 if (IS_64BIT_PROCESS(p
)) {
1249 maxcount
= uap
->bufsize
/ sizeof(struct user_statfs
);
1252 maxcount
= uap
->bufsize
/ sizeof(struct statfs
);
1258 fst
.flags
= uap
->flags
;
1261 fst
.maxcount
= maxcount
;
1264 vfs_iterate(0, getfsstat_callback
, &fst
);
1267 KAUTH_DEBUG("ERROR - %s gets %d", p
->p_comm
, fst
.error
);
1271 if (fst
.sfsp
&& fst
.count
> fst
.maxcount
)
1272 *retval
= fst
.maxcount
;
1274 *retval
= fst
.count
;
1278 #if COMPAT_GETFSSTAT
1279 ogetfsstat(p
, uap
, retval
)
1281 register struct getfsstat_args
*uap
;
1289 * Change current working directory to a given file descriptor.
1293 fchdir(struct proc
*p
, struct fchdir_args
*uap
, __unused register_t
*retval
)
1295 register struct filedesc
*fdp
= p
->p_fd
;
1296 struct vnode
*vp
, *tdp
, *tvp
;
1299 struct vfs_context context
;
1301 context
.vc_proc
= p
;
1302 context
.vc_ucred
= kauth_cred_get();
1304 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1306 if ( (error
= vnode_getwithref(vp
)) ) {
1311 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
1313 if (vp
->v_type
!= VDIR
)
1316 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, &context
);
1317 while (!error
&& (mp
= vp
->v_mountedhere
) != NULL
) {
1318 if (vfs_busy(mp
, LK_NOWAIT
)) {
1322 error
= VFS_ROOT(mp
, &tdp
, &context
);
1331 if ( (error
= vnode_ref(vp
)) )
1353 * Change current working directory (``.'').
1357 chdir(struct proc
*p
, struct chdir_args
*uap
, __unused register_t
*retval
)
1359 register struct filedesc
*fdp
= p
->p_fd
;
1361 struct nameidata nd
;
1363 struct vfs_context context
;
1365 context
.vc_proc
= p
;
1366 context
.vc_ucred
= kauth_cred_get();
1368 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1369 UIO_USERSPACE
, uap
->path
, &context
);
1370 error
= change_dir(&nd
, &context
);
1373 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
1374 vnode_put(nd
.ni_vp
);
1378 * drop the iocount we picked up in change_dir
1380 vnode_put(nd
.ni_vp
);
1384 fdp
->fd_cdir
= nd
.ni_vp
;
1394 * Change notion of root (``/'') directory.
1398 chroot(struct proc
*p
, struct chroot_args
*uap
, __unused register_t
*retval
)
1400 register struct filedesc
*fdp
= p
->p_fd
;
1402 struct nameidata nd
;
1403 boolean_t shared_regions_active
;
1405 struct vfs_context context
;
1407 context
.vc_proc
= p
;
1408 context
.vc_ucred
= kauth_cred_get();
1410 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
1413 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1414 UIO_USERSPACE
, uap
->path
, &context
);
1415 error
= change_dir(&nd
, &context
);
1419 if(p
->p_flag
& P_NOSHLIB
) {
1420 shared_regions_active
= FALSE
;
1422 shared_regions_active
= TRUE
;
1424 if ((error
= clone_system_shared_regions(shared_regions_active
,
1425 TRUE
, /* chain_regions */
1427 vnode_put(nd
.ni_vp
);
1430 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
1431 vnode_put(nd
.ni_vp
);
1434 vnode_put(nd
.ni_vp
);
1438 fdp
->fd_rdir
= nd
.ni_vp
;
1439 fdp
->fd_flags
|= FD_CHROOT
;
1449 * Common routine for chroot and chdir.
1452 change_dir(struct nameidata
*ndp
, vfs_context_t ctx
)
1457 if ((error
= namei(ndp
)))
1461 if (vp
->v_type
!= VDIR
)
1464 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, ctx
);
1472 * Check permissions, allocate an open file structure,
1473 * and call the device open routine if any.
1476 #warning XXX implement uid, gid
1478 open1(vfs_context_t ctx
, user_addr_t upath
, int uflags
, struct vnode_attr
*vap
, register_t
*retval
)
1480 struct proc
*p
= vfs_context_proc(ctx
);
1481 register struct filedesc
*fdp
= p
->p_fd
;
1482 register struct fileproc
*fp
;
1483 register struct vnode
*vp
;
1485 struct fileproc
*nfp
;
1486 int type
, indx
, error
;
1488 struct nameidata nd
;
1492 if ((oflags
& O_ACCMODE
) == O_ACCMODE
)
1494 flags
= FFLAGS(uflags
);
1496 AUDIT_ARG(fflags
, oflags
);
1497 AUDIT_ARG(mode
, vap
->va_mode
);
1499 if ( (error
= falloc(p
, &nfp
, &indx
)) ) {
1503 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1504 UIO_USERSPACE
, upath
, ctx
);
1505 p
->p_dupfd
= -indx
- 1; /* XXX check for fdopen */
1507 if ((error
= vn_open_auth(&nd
, &flags
, vap
))) {
1508 if ((error
== ENODEV
|| error
== ENXIO
) && (p
->p_dupfd
>= 0)) { /* XXX from fdopen */
1509 if ((error
= dupfdopen(fdp
, indx
, p
->p_dupfd
, flags
, error
)) == 0) {
1510 fp_drop(p
, indx
, 0, 0);
1515 if (error
== ERESTART
)
1517 fp_free(p
, indx
, fp
);
1524 fp
->f_fglob
->fg_flag
= flags
& (FMASK
| O_EVTONLY
);
1525 fp
->f_fglob
->fg_type
= DTYPE_VNODE
;
1526 fp
->f_fglob
->fg_ops
= &vnops
;
1527 fp
->f_fglob
->fg_data
= (caddr_t
)vp
;
1529 if (flags
& (O_EXLOCK
| O_SHLOCK
)) {
1530 lf
.l_whence
= SEEK_SET
;
1533 if (flags
& O_EXLOCK
)
1534 lf
.l_type
= F_WRLCK
;
1536 lf
.l_type
= F_RDLCK
;
1538 if ((flags
& FNONBLOCK
) == 0)
1540 if ((error
= VNOP_ADVLOCK(vp
, (caddr_t
)fp
->f_fglob
, F_SETLK
, &lf
, type
, ctx
)))
1542 fp
->f_fglob
->fg_flag
|= FHASLOCK
;
1545 /* try to truncate by setting the size attribute */
1546 if ((flags
& O_TRUNC
) && ((error
= vnode_setsize(vp
, (off_t
)0, 0, ctx
)) != 0))
1552 procfdtbl_releasefd(p
, indx
, NULL
);
1553 fp_drop(p
, indx
, fp
, 1);
1560 vn_close(vp
, fp
->f_fglob
->fg_flag
, fp
->f_fglob
->fg_cred
, p
);
1562 fp_free(p
, indx
, fp
);
1569 open_extended(struct proc
*p
, struct open_extended_args
*uap
, register_t
*retval
)
1571 struct vfs_context context
;
1572 register struct filedesc
*fdp
= p
->p_fd
;
1574 kauth_filesec_t xsecdst
;
1575 struct vnode_attr va
;
1579 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
1580 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
1583 context
.vc_proc
= p
;
1584 context
.vc_ucred
= kauth_cred_get();
1587 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
1588 VATTR_SET(&va
, va_mode
, cmode
);
1589 if (uap
->uid
!= KAUTH_UID_NONE
)
1590 VATTR_SET(&va
, va_uid
, uap
->uid
);
1591 if (uap
->gid
!= KAUTH_GID_NONE
)
1592 VATTR_SET(&va
, va_gid
, uap
->gid
);
1593 if (xsecdst
!= NULL
)
1594 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
1596 ciferror
= open1(&context
, uap
->path
, uap
->flags
, &va
, retval
);
1597 if (xsecdst
!= NULL
)
1598 kauth_filesec_free(xsecdst
);
1604 open(struct proc
*p
, struct open_args
*uap
, register_t
*retval
)
1606 struct vfs_context context
;
1607 register struct filedesc
*fdp
= p
->p_fd
;
1608 struct vnode_attr va
;
1611 context
.vc_proc
= p
;
1612 context
.vc_ucred
= kauth_cred_get();
1615 /* Mask off all but regular access permissions */
1616 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
1617 VATTR_SET(&va
, va_mode
, cmode
& ACCESSPERMS
);
1619 return(open1(&context
, uap
->path
, uap
->flags
, &va
, retval
));
1624 * Create a special file.
1626 static int mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
);
1629 mknod(struct proc
*p
, register struct mknod_args
*uap
, __unused register_t
*retval
)
1631 struct vnode_attr va
;
1632 struct vfs_context context
;
1635 struct nameidata nd
;
1638 context
.vc_proc
= p
;
1639 context
.vc_ucred
= kauth_cred_get();
1642 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1643 VATTR_SET(&va
, va_rdev
, uap
->dev
);
1645 /* If it's a mknod() of a FIFO, call mkfifo1() instead */
1646 if ((uap
->mode
& S_IFMT
) == S_IFIFO
)
1647 return(mkfifo1(&context
, uap
->path
, &va
));
1649 AUDIT_ARG(mode
, uap
->mode
);
1650 AUDIT_ARG(dev
, uap
->dev
);
1652 if ((error
= suser(context
.vc_ucred
, &p
->p_acflag
)))
1654 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1655 UIO_USERSPACE
, uap
->path
, &context
);
1667 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
1670 switch (uap
->mode
& S_IFMT
) {
1671 case S_IFMT
: /* used by badsect to flag bad sectors */
1672 VATTR_SET(&va
, va_type
, VBAD
);
1675 VATTR_SET(&va
, va_type
, VCHR
);
1678 VATTR_SET(&va
, va_type
, VBLK
);
1688 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, CREATE
, &context
);
1690 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, &va
, 0, &context
);
1696 int update_flags
= 0;
1698 // Make sure the name & parent pointers are hooked up
1699 if (vp
->v_name
== NULL
)
1700 update_flags
|= VNODE_UPDATE_NAME
;
1701 if (vp
->v_parent
== NULLVP
)
1702 update_flags
|= VNODE_UPDATE_PARENT
;
1705 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
1707 add_fsevent(FSE_CREATE_FILE
, &context
,
1714 * nameidone has to happen before we vnode_put(dvp)
1715 * since it may need to release the fs_nodelock on the dvp
1727 * Create a named pipe.
1730 mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
)
1734 struct nameidata nd
;
1736 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1737 UIO_USERSPACE
, upath
, ctx
);
1744 /* check that this is a new file and authorize addition */
1749 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
1752 VATTR_SET(vap
, va_type
, VFIFO
);
1754 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
);
1757 * nameidone has to happen before we vnode_put(dvp)
1758 * since it may need to release the fs_nodelock on the dvp
1770 mkfifo_extended(struct proc
*p
, struct mkfifo_extended_args
*uap
, __unused register_t
*retval
)
1773 kauth_filesec_t xsecdst
;
1774 struct vfs_context context
;
1775 struct vnode_attr va
;
1777 xsecdst
= KAUTH_FILESEC_NONE
;
1778 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
1779 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
1783 context
.vc_proc
= p
;
1784 context
.vc_ucred
= kauth_cred_get();
1787 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1788 if (uap
->uid
!= KAUTH_UID_NONE
)
1789 VATTR_SET(&va
, va_uid
, uap
->uid
);
1790 if (uap
->gid
!= KAUTH_GID_NONE
)
1791 VATTR_SET(&va
, va_gid
, uap
->gid
);
1792 if (xsecdst
!= KAUTH_FILESEC_NONE
)
1793 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
1795 ciferror
= mkfifo1(&context
, uap
->path
, &va
);
1797 if (xsecdst
!= KAUTH_FILESEC_NONE
)
1798 kauth_filesec_free(xsecdst
);
1804 mkfifo(struct proc
*p
, register struct mkfifo_args
*uap
, __unused register_t
*retval
)
1806 struct vfs_context context
;
1807 struct vnode_attr va
;
1809 context
.vc_proc
= p
;
1810 context
.vc_ucred
= kauth_cred_get();
1813 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1815 return(mkfifo1(&context
, uap
->path
, &va
));
1819 * Make a hard file link.
1823 link(struct proc
*p
, register struct link_args
*uap
, __unused register_t
*retval
)
1825 vnode_t vp
, dvp
, lvp
;
1826 struct nameidata nd
;
1827 struct vfs_context context
;
1830 int need_event
, has_listeners
;
1832 context
.vc_proc
= p
;
1833 context
.vc_ucred
= kauth_cred_get();
1834 vp
= dvp
= lvp
= NULLVP
;
1836 /* look up the object we are linking to */
1837 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1838 UIO_USERSPACE
, uap
->path
, &context
);
1846 /* we're not allowed to link to directories */
1847 if (vp
->v_type
== VDIR
) {
1848 error
= EPERM
; /* POSIX */
1852 /* or to anything that kauth doesn't want us to (eg. immutable items) */
1853 if ((error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_LINKTARGET
, &context
)) != 0)
1856 /* lookup the target node */
1857 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1858 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| AUDITVNPATH2
;
1859 nd
.ni_dirp
= uap
->link
;
1865 /* target node must not exist */
1866 if (lvp
!= NULLVP
) {
1870 /* cannot link across mountpoints */
1871 if (vnode_mount(vp
) != vnode_mount(dvp
)) {
1876 /* authorize creation of the target note */
1877 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
1880 /* and finally make the link */
1881 error
= VNOP_LINK(vp
, dvp
, &nd
.ni_cnd
, &context
);
1885 need_event
= need_fsevent(FSE_CREATE_FILE
, dvp
);
1886 has_listeners
= kauth_authorize_fileop_has_listeners();
1888 if (need_event
|| has_listeners
) {
1889 char *target_path
= NULL
;
1890 char *link_to_path
= NULL
;
1891 int len
, link_name_len
;
1893 /* build the path to the new link file */
1894 target_path
= get_pathbuff();
1896 vn_getpath(dvp
, target_path
, &len
);
1897 target_path
[len
-1] = '/';
1898 strcpy(&target_path
[len
], nd
.ni_cnd
.cn_nameptr
);
1899 len
+= nd
.ni_cnd
.cn_namelen
;
1901 if (has_listeners
) {
1902 /* build the path to file we are linking to */
1903 link_to_path
= get_pathbuff();
1904 link_name_len
= MAXPATHLEN
;
1905 vn_getpath(vp
, link_to_path
, &link_name_len
);
1907 /* call out to allow 3rd party notification of rename.
1908 * Ignore result of kauth_authorize_fileop call.
1910 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_LINK
,
1911 (uintptr_t)link_to_path
, (uintptr_t)target_path
);
1912 if (link_to_path
!= NULL
)
1913 release_pathbuff(link_to_path
);
1916 /* construct fsevent */
1917 if (get_fse_info(vp
, &finfo
, &context
) == 0) {
1918 // build the path to the destination of the link
1919 add_fsevent(FSE_CREATE_FILE
, &context
,
1920 FSE_ARG_STRING
, len
, target_path
,
1921 FSE_ARG_FINFO
, &finfo
,
1925 release_pathbuff(target_path
);
1929 * nameidone has to happen before we vnode_put(dvp)
1930 * since it may need to release the fs_nodelock on the dvp
1943 * Make a symbolic link.
1945 * We could add support for ACLs here too...
1949 symlink(struct proc
*p
, register struct symlink_args
*uap
, __unused register_t
*retval
)
1951 struct vnode_attr va
;
1954 struct nameidata nd
;
1955 struct vfs_context context
;
1959 context
.vc_proc
= p
;
1960 context
.vc_ucred
= kauth_cred_get();
1962 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1963 error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
);
1966 AUDIT_ARG(text
, path
); /* This is the link string */
1968 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1969 UIO_USERSPACE
, uap
->link
, &context
);
1978 VATTR_SET(&va
, va_type
, VLNK
);
1979 VATTR_SET(&va
, va_mode
, ACCESSPERMS
& ~p
->p_fd
->fd_cmask
);
1982 error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
);
1983 /* get default ownership, etc. */
1985 error
= vnode_authattr_new(dvp
, &va
, 0, &context
);
1987 error
= VNOP_SYMLINK(dvp
, &vp
, &nd
.ni_cnd
, &va
, path
, &context
);
1989 /* do fallback attribute handling */
1991 error
= vnode_setattr_fallback(vp
, &va
, &context
);
1994 int update_flags
= 0;
1997 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
1998 nd
.ni_cnd
.cn_flags
= 0;
2006 #if 0 /* XXX - kauth_todo - is KAUTH_FILEOP_SYMLINK needed? */
2007 /* call out to allow 3rd party notification of rename.
2008 * Ignore result of kauth_authorize_fileop call.
2010 if (kauth_authorize_fileop_has_listeners() &&
2012 char *new_link_path
= NULL
;
2015 /* build the path to the new link file */
2016 new_link_path
= get_pathbuff();
2018 vn_getpath(dvp
, new_link_path
, &len
);
2019 new_link_path
[len
- 1] = '/';
2020 strcpy(&new_link_path
[len
], nd
.ni_cnd
.cn_nameptr
);
2022 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_SYMLINK
,
2023 (uintptr_t)path
, (uintptr_t)new_link_path
);
2024 if (new_link_path
!= NULL
)
2025 release_pathbuff(new_link_path
);
2028 // Make sure the name & parent pointers are hooked up
2029 if (vp
->v_name
== NULL
)
2030 update_flags
|= VNODE_UPDATE_NAME
;
2031 if (vp
->v_parent
== NULLVP
)
2032 update_flags
|= VNODE_UPDATE_PARENT
;
2035 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
2037 add_fsevent(FSE_CREATE_FILE
, &context
,
2046 * nameidone has to happen before we vnode_put(dvp)
2047 * since it may need to release the fs_nodelock on the dvp
2055 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
2061 * Delete a whiteout from the filesystem.
2064 #warning XXX authorization not implmented for whiteouts
2066 undelete(struct proc
*p
, register struct undelete_args
*uap
, __unused register_t
*retval
)
2069 struct nameidata nd
;
2070 struct vfs_context context
;
2073 context
.vc_proc
= p
;
2074 context
.vc_ucred
= kauth_cred_get();
2076 NDINIT(&nd
, DELETE
, LOCKPARENT
|DOWHITEOUT
|AUDITVNPATH1
,
2077 UIO_USERSPACE
, uap
->path
, &context
);
2084 if (vp
== NULLVP
&& (nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
2085 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, DELETE
, &context
);
2090 * nameidone has to happen before we vnode_put(dvp)
2091 * since it may need to release the fs_nodelock on the dvp
2103 * Delete a name from the filesystem.
2107 _unlink(struct proc
*p
, struct unlink_args
*uap
, __unused register_t
*retval
, int nodelbusy
)
2111 struct nameidata nd
;
2112 struct vfs_context context
;
2113 struct componentname
*cnp
;
2116 context
.vc_proc
= p
;
2117 context
.vc_ucred
= kauth_cred_get();
2119 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
2120 UIO_USERSPACE
, uap
->path
, &context
);
2123 /* With Carbon delete semantics, busy files cannot be deleted */
2125 flags
|= VNODE_REMOVE_NODELETEBUSY
;
2133 if (vp
->v_type
== VDIR
) {
2134 error
= EPERM
; /* POSIX */
2137 * The root of a mounted filesystem cannot be deleted.
2139 if (vp
->v_flag
& VROOT
) {
2143 /* authorize the delete operation */
2145 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, &context
);
2152 if (need_fsevent(FSE_DELETE
, dvp
)) {
2153 path
= get_pathbuff();
2155 vn_getpath(vp
, path
, &len
);
2156 get_fse_info(vp
, &finfo
, &context
);
2158 error
= VNOP_REMOVE(dvp
, vp
, &nd
.ni_cnd
, flags
, &context
);
2160 if ( !error
&& path
!= NULL
) {
2161 add_fsevent(FSE_DELETE
, &context
,
2162 FSE_ARG_STRING
, len
, path
,
2163 FSE_ARG_FINFO
, &finfo
,
2167 release_pathbuff(path
);
2170 * nameidone has to happen before we vnode_put(dvp)
2171 * since it may need to release the fs_nodelock on the dvp
2180 * Delete a name from the filesystem using POSIX semantics.
2183 unlink(p
, uap
, retval
)
2185 struct unlink_args
*uap
;
2188 return _unlink(p
, uap
, retval
, 0);
2192 * Delete a name from the filesystem using Carbon semantics.
2195 delete(p
, uap
, retval
)
2197 struct delete_args
*uap
;
2200 return _unlink(p
, (struct unlink_args
*)uap
, retval
, 1);
2204 * Reposition read/write file offset.
2207 lseek(p
, uap
, retval
)
2209 register struct lseek_args
*uap
;
2212 struct fileproc
*fp
;
2214 struct vfs_context context
;
2215 off_t offset
= uap
->offset
, file_size
;
2218 if ( (error
= fp_getfvp(p
,uap
->fd
, &fp
, &vp
)) ) {
2219 if (error
== ENOTSUP
)
2223 if (vnode_isfifo(vp
)) {
2227 if ( (error
= vnode_getwithref(vp
)) ) {
2232 switch (uap
->whence
) {
2234 offset
+= fp
->f_fglob
->fg_offset
;
2237 context
.vc_proc
= p
;
2238 context
.vc_ucred
= kauth_cred_get();
2239 if ((error
= vnode_size(vp
, &file_size
, &context
)) != 0)
2241 offset
+= file_size
;
2249 if (uap
->offset
> 0 && offset
< 0) {
2250 /* Incremented/relative move past max size */
2254 * Allow negative offsets on character devices, per
2255 * POSIX 1003.1-2001. Most likely for writing disk
2258 if (offset
< 0 && vp
->v_type
!= VCHR
) {
2259 /* Decremented/relative move before start */
2263 fp
->f_fglob
->fg_offset
= offset
;
2264 *retval
= fp
->f_fglob
->fg_offset
;
2268 (void)vnode_put(vp
);
2275 * Check access permissions.
2278 access1(vnode_t vp
, vnode_t dvp
, int uflags
, vfs_context_t ctx
)
2280 kauth_action_t action
;
2284 * If just the regular access bits, convert them to something
2285 * that vnode_authorize will understand.
2287 if (!(uflags
& _ACCESS_EXTENDED_MASK
)) {
2290 action
|= KAUTH_VNODE_READ_DATA
; /* aka KAUTH_VNODE_LIST_DIRECTORY */
2291 if (uflags
& W_OK
) {
2292 if (vnode_isdir(vp
)) {
2293 action
|= KAUTH_VNODE_ADD_FILE
|
2294 KAUTH_VNODE_ADD_SUBDIRECTORY
;
2295 /* might want delete rights here too */
2297 action
|= KAUTH_VNODE_WRITE_DATA
;
2300 if (uflags
& X_OK
) {
2301 if (vnode_isdir(vp
)) {
2302 action
|= KAUTH_VNODE_SEARCH
;
2304 action
|= KAUTH_VNODE_EXECUTE
;
2308 /* take advantage of definition of uflags */
2309 action
= uflags
>> 8;
2312 /* action == 0 means only check for existence */
2314 error
= vnode_authorize(vp
, dvp
, action
| KAUTH_VNODE_ACCESS
, ctx
);
2324 /* XXX need to support the check-as uid argument */
2326 access_extended(__unused
struct proc
*p
, struct access_extended_args
*uap
, __unused register_t
*retval
)
2328 struct accessx_descriptor
*input
;
2330 int error
, limit
, nent
, i
, j
, wantdelete
;
2331 struct vfs_context context
;
2332 struct nameidata nd
;
2341 context
.vc_ucred
= NULL
;
2343 /* check input size and fetch descriptor array into allocated storage */
2344 if (uap
->size
> ACCESSX_MAX_TABLESIZE
)
2346 if (uap
->size
< sizeof(struct accessx_descriptor
))
2348 MALLOC(input
, struct accessx_descriptor
*, uap
->size
, M_TEMP
, M_WAITOK
);
2349 if (input
== NULL
) {
2353 error
= copyin(uap
->entries
, input
, uap
->size
);
2358 * Access is defined as checking against the process'
2359 * real identity, even if operations are checking the
2360 * effective identity. So we need to tweak the credential
2363 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
2364 context
.vc_proc
= current_proc();
2367 * Find out how many entries we have, so we can allocate the result array.
2369 limit
= uap
->size
/ sizeof(struct accessx_descriptor
);
2372 for (i
= 0; i
< nent
; i
++) {
2374 * Take the offset to the name string for this entry and convert to an
2375 * input array index, which would be one off the end of the array if this
2376 * was the lowest-addressed name string.
2378 j
= input
[i
].ad_name_offset
/ sizeof(struct accessx_descriptor
);
2384 /* implicit reference to previous name, not a real offset */
2386 /* first entry must have a name string */
2396 if (nent
> ACCESSX_MAX_DESCRIPTORS
) {
2400 MALLOC(result
, errno_t
*, nent
* sizeof(errno_t
), M_TEMP
, M_WAITOK
);
2401 if (result
== NULL
) {
2410 for (i
= 0; i
< nent
; i
++) {
2412 * Looking up a new name?
2414 if (input
[i
].ad_name_offset
!= 0) {
2415 /* discard old vnodes */
2425 /* scan forwards to see if we need the parent this time */
2426 wantdelete
= input
[i
].ad_flags
& _DELETE_OK
;
2427 for (j
= i
+ 1; (j
< nent
) && (input
[j
].ad_name_offset
== 0); j
++)
2428 if (input
[j
].ad_flags
& _DELETE_OK
)
2431 niopts
= FOLLOW
| AUDITVNPATH1
;
2432 /* need parent for vnode_authorize for deletion test */
2434 niopts
|= WANTPARENT
;
2437 NDINIT(&nd
, LOOKUP
, niopts
, UIO_SYSSPACE
, CAST_USER_ADDR_T((const char *)input
+ input
[i
].ad_name_offset
), &context
);
2448 * Handle lookup errors.
2458 /* run this access check */
2459 result
[i
] = access1(vp
, dvp
, input
[i
].ad_flags
, &context
);
2462 /* fatal lookup error */
2468 /* copy out results */
2469 error
= copyout(result
, uap
->results
, nent
* sizeof(errno_t
));
2473 FREE(input
, M_TEMP
);
2475 FREE(result
, M_TEMP
);
2480 if (context
.vc_ucred
)
2481 kauth_cred_rele(context
.vc_ucred
);
2486 access(__unused
struct proc
*p
, register struct access_args
*uap
, __unused register_t
*retval
)
2489 struct nameidata nd
;
2491 struct vfs_context context
;
2494 * Access is defined as checking against the process'
2495 * real identity, even if operations are checking the
2496 * effective identity. So we need to tweak the credential
2499 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
2500 context
.vc_proc
= current_proc();
2502 niopts
= FOLLOW
| AUDITVNPATH1
;
2503 /* need parent for vnode_authorize for deletion test */
2504 if (uap
->flags
& _DELETE_OK
)
2505 niopts
|= WANTPARENT
;
2506 NDINIT(&nd
, LOOKUP
, niopts
, UIO_USERSPACE
, uap
->path
, &context
);
2511 error
= access1(nd
.ni_vp
, nd
.ni_dvp
, uap
->flags
, &context
);
2513 vnode_put(nd
.ni_vp
);
2514 if (uap
->flags
& _DELETE_OK
)
2515 vnode_put(nd
.ni_dvp
);
2519 kauth_cred_rele(context
.vc_ucred
);
2525 stat2(vfs_context_t ctx
, struct nameidata
*ndp
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2528 struct user_stat user_sb
;
2531 kauth_filesec_t fsec
;
2532 size_t xsecurity_bufsize
;
2537 fsec
= KAUTH_FILESEC_NONE
;
2538 error
= vn_stat(ndp
->ni_vp
, &sb
, (xsecurity
!= USER_ADDR_NULL
? &fsec
: NULL
), ctx
);
2539 vnode_put(ndp
->ni_vp
);
2544 /* Zap spare fields */
2546 sb
.st_qspare
[0] = 0LL;
2547 sb
.st_qspare
[1] = 0LL;
2548 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
2549 munge_stat(&sb
, &user_sb
);
2550 my_size
= sizeof(user_sb
);
2551 sbp
= (caddr_t
)&user_sb
;
2554 my_size
= sizeof(sb
);
2557 if ((error
= copyout(sbp
, ub
, my_size
)) != 0)
2560 /* caller wants extended security information? */
2561 if (xsecurity
!= USER_ADDR_NULL
) {
2563 /* did we get any? */
2564 if (fsec
== KAUTH_FILESEC_NONE
) {
2565 if (susize(xsecurity_size
, 0) != 0) {
2570 /* find the user buffer size */
2571 xsecurity_bufsize
= fusize(xsecurity_size
);
2573 /* copy out the actual data size */
2574 if (susize(xsecurity_size
, KAUTH_FILESEC_COPYSIZE(fsec
)) != 0) {
2579 /* if the caller supplied enough room, copy out to it */
2580 if (xsecurity_bufsize
>= KAUTH_FILESEC_COPYSIZE(fsec
))
2581 error
= copyout(fsec
, xsecurity
, KAUTH_FILESEC_COPYSIZE(fsec
));
2585 if (fsec
!= KAUTH_FILESEC_NONE
)
2586 kauth_filesec_free(fsec
);
2591 * Get file status; this version follows links.
2594 stat1(struct proc
*p
, user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2596 struct nameidata nd
;
2597 struct vfs_context context
;
2599 context
.vc_proc
= p
;
2600 context
.vc_ucred
= kauth_cred_get();
2602 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2603 UIO_USERSPACE
, path
, &context
);
2604 return(stat2(&context
, &nd
, ub
, xsecurity
, xsecurity_size
));
2608 stat_extended(struct proc
*p
, struct stat_extended_args
*uap
, __unused register_t
*retval
)
2610 return (stat1(p
, uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
));
2614 stat(struct proc
*p
, struct stat_args
*uap
, __unused register_t
*retval
)
2616 return(stat1(p
, uap
->path
, uap
->ub
, 0, 0));
2620 * Get file status; this version does not follow links.
2623 lstat1(struct proc
*p
, user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2625 struct nameidata nd
;
2626 struct vfs_context context
;
2628 context
.vc_proc
= p
;
2629 context
.vc_ucred
= kauth_cred_get();
2631 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
2632 UIO_USERSPACE
, path
, &context
);
2634 return(stat2(&context
, &nd
, ub
, xsecurity
, xsecurity_size
));
2638 lstat_extended(struct proc
*p
, struct lstat_extended_args
*uap
, __unused register_t
*retval
)
2640 return (lstat1(p
, uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
));
2644 lstat(struct proc
*p
, struct lstat_args
*uap
, __unused register_t
*retval
)
2646 return(lstat1(p
, uap
->path
, uap
->ub
, 0, 0));
2650 * Get configurable pathname variables.
2654 pathconf(p
, uap
, retval
)
2656 register struct pathconf_args
*uap
;
2660 struct nameidata nd
;
2661 struct vfs_context context
;
2663 context
.vc_proc
= p
;
2664 context
.vc_ucred
= kauth_cred_get();
2666 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2667 UIO_USERSPACE
, uap
->path
, &context
);
2672 error
= vn_pathconf(nd
.ni_vp
, uap
->name
, retval
, &context
);
2674 vnode_put(nd
.ni_vp
);
2680 * Return target name of a symbolic link.
2684 readlink(p
, uap
, retval
)
2686 register struct readlink_args
*uap
;
2689 register struct vnode
*vp
;
2691 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
2693 struct nameidata nd
;
2694 struct vfs_context context
;
2695 char uio_buf
[ UIO_SIZEOF(1) ];
2697 context
.vc_proc
= p
;
2698 context
.vc_ucred
= kauth_cred_get();
2700 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
2701 UIO_USERSPACE
, uap
->path
, &context
);
2709 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
2710 &uio_buf
[0], sizeof(uio_buf
));
2711 uio_addiov(auio
, uap
->buf
, uap
->count
);
2712 if (vp
->v_type
!= VLNK
)
2715 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, &context
);
2717 error
= VNOP_READLINK(vp
, auio
, &context
);
2720 // LP64todo - fix this
2721 *retval
= uap
->count
- (int)uio_resid(auio
);
2726 * Change file flags.
2729 chflags1(vnode_t vp
, int flags
, vfs_context_t ctx
)
2731 struct vnode_attr va
;
2732 kauth_action_t action
;
2736 VATTR_SET(&va
, va_flags
, flags
);
2738 /* request authorisation, disregard immutability */
2739 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
2742 * Request that the auth layer disregard those file flags it's allowed to when
2743 * authorizing this operation; we need to do this in order to be able to
2744 * clear immutable flags.
2746 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
| KAUTH_VNODE_NOIMMUTABLE
, ctx
)) != 0))
2748 error
= vnode_setattr(vp
, &va
, ctx
);
2756 * Change flags of a file given a path name.
2760 chflags(struct proc
*p
, register struct chflags_args
*uap
, __unused register_t
*retval
)
2762 register struct vnode
*vp
;
2763 struct vfs_context context
;
2765 struct nameidata nd
;
2767 context
.vc_proc
= p
;
2768 context
.vc_ucred
= kauth_cred_get();
2770 AUDIT_ARG(fflags
, uap
->flags
);
2771 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2772 UIO_USERSPACE
, uap
->path
, &context
);
2779 error
= chflags1(vp
, uap
->flags
, &context
);
2785 * Change flags of a file given a file descriptor.
2789 fchflags(struct proc
*p
, register struct fchflags_args
*uap
, __unused register_t
*retval
)
2791 struct vfs_context context
;
2795 AUDIT_ARG(fd
, uap
->fd
);
2796 AUDIT_ARG(fflags
, uap
->flags
);
2797 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
2800 if ((error
= vnode_getwithref(vp
))) {
2805 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2807 context
.vc_proc
= p
;
2808 context
.vc_ucred
= kauth_cred_get();
2810 error
= chflags1(vp
, uap
->flags
, &context
);
2817 * Change security information on a filesystem object.
2820 chmod2(vfs_context_t ctx
, struct vnode
*vp
, struct vnode_attr
*vap
)
2822 kauth_action_t action
;
2825 AUDIT_ARG(mode
, (mode_t
)vap
->va_mode
);
2826 #warning XXX audit new args
2828 /* make sure that the caller is allowed to set this security information */
2829 if (((error
= vnode_authattr(vp
, vap
, &action
, ctx
)) != 0) ||
2830 ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
2831 if (error
== EACCES
)
2836 error
= vnode_setattr(vp
, vap
, ctx
);
2843 * Change mode of a file given path name.
2846 chmod1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
2848 struct nameidata nd
;
2851 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2852 UIO_USERSPACE
, path
, ctx
);
2853 if ((error
= namei(&nd
)))
2855 error
= chmod2(ctx
, nd
.ni_vp
, vap
);
2856 vnode_put(nd
.ni_vp
);
2862 chmod_extended(struct proc
*p
, struct chmod_extended_args
*uap
, __unused register_t
*retval
)
2864 struct vfs_context context
;
2866 struct vnode_attr va
;
2867 kauth_filesec_t xsecdst
;
2870 if (uap
->mode
!= -1)
2871 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2872 if (uap
->uid
!= KAUTH_UID_NONE
)
2873 VATTR_SET(&va
, va_uid
, uap
->uid
);
2874 if (uap
->gid
!= KAUTH_GID_NONE
)
2875 VATTR_SET(&va
, va_gid
, uap
->gid
);
2878 switch(uap
->xsecurity
) {
2879 /* explicit remove request */
2880 case CAST_USER_ADDR_T((void *)1): /* _FILESEC_REMOVE_ACL */
2881 VATTR_SET(&va
, va_acl
, NULL
);
2884 case USER_ADDR_NULL
:
2887 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
2889 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2890 KAUTH_DEBUG("CHMOD - setting ACL with %d entries", va
.va_acl
->acl_entrycount
);
2892 context
.vc_proc
= p
;
2893 context
.vc_ucred
= kauth_cred_get();
2895 error
= chmod1(&context
, uap
->path
, &va
);
2897 if (xsecdst
!= NULL
)
2898 kauth_filesec_free(xsecdst
);
2903 chmod(struct proc
*p
, register struct chmod_args
*uap
, __unused register_t
*retval
)
2905 struct vfs_context context
;
2906 struct vnode_attr va
;
2909 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2911 context
.vc_proc
= p
;
2912 context
.vc_ucred
= kauth_cred_get();
2914 return(chmod1(&context
, uap
->path
, &va
));
2918 * Change mode of a file given a file descriptor.
2921 fchmod1(struct proc
*p
, int fd
, struct vnode_attr
*vap
)
2925 struct vfs_context context
;
2927 context
.vc_proc
= p
;
2928 context
.vc_ucred
= kauth_cred_get();
2932 if ((error
= file_vnode(fd
, &vp
)) != 0)
2934 if ((error
= vnode_getwithref(vp
)) != 0) {
2938 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2940 error
= chmod2(&context
, vp
, vap
);
2941 (void)vnode_put(vp
);
2948 fchmod_extended(struct proc
*p
, struct fchmod_extended_args
*uap
, __unused register_t
*retval
)
2951 struct vnode_attr va
;
2952 kauth_filesec_t xsecdst
;
2955 if (uap
->mode
!= -1)
2956 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2957 if (uap
->uid
!= KAUTH_UID_NONE
)
2958 VATTR_SET(&va
, va_uid
, uap
->uid
);
2959 if (uap
->gid
!= KAUTH_GID_NONE
)
2960 VATTR_SET(&va
, va_gid
, uap
->gid
);
2963 switch(uap
->xsecurity
) {
2964 case USER_ADDR_NULL
:
2965 VATTR_SET(&va
, va_acl
, NULL
);
2967 case CAST_USER_ADDR_T(-1):
2970 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
2972 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2975 error
= fchmod1(p
, uap
->fd
, &va
);
2978 switch(uap
->xsecurity
) {
2979 case USER_ADDR_NULL
:
2980 case CAST_USER_ADDR_T(-1):
2983 if (xsecdst
!= NULL
)
2984 kauth_filesec_free(xsecdst
);
2990 fchmod(struct proc
*p
, register struct fchmod_args
*uap
, __unused register_t
*retval
)
2992 struct vnode_attr va
;
2995 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2997 return(fchmod1(p
, uap
->fd
, &va
));
3002 * Set ownership given a path name.
3006 chown1(vfs_context_t ctx
, register struct chown_args
*uap
, __unused register_t
*retval
, int follow
)
3008 register struct vnode
*vp
;
3009 struct vnode_attr va
;
3011 struct nameidata nd
;
3012 kauth_action_t action
;
3014 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
3016 NDINIT(&nd
, LOOKUP
, (follow
? FOLLOW
: 0) | AUDITVNPATH1
,
3017 UIO_USERSPACE
, uap
->path
, ctx
);
3026 * XXX A TEMPORARY HACK FOR NOW: Try to track console_user
3027 * by looking for chown() calls on /dev/console from a console process.
3029 if ((vp
) && (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
) && (vp
->v_specinfo
) &&
3030 (major(vp
->v_specinfo
->si_rdev
) == CONSMAJOR
) &&
3031 (minor(vp
->v_specinfo
->si_rdev
) == 0)) {
3032 console_user
= uap
->uid
;
3035 if (uap
->uid
!= VNOVAL
)
3036 VATTR_SET(&va
, va_uid
, uap
->uid
);
3037 if (uap
->gid
!= VNOVAL
)
3038 VATTR_SET(&va
, va_gid
, uap
->gid
);
3040 /* preflight and authorize attribute changes */
3041 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
3043 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
3045 error
= vnode_setattr(vp
, &va
, ctx
);
3049 * EACCES is only allowed from namei(); permissions failure should
3050 * return EPERM, so we need to translate the error code.
3052 if (error
== EACCES
)
3060 chown(struct proc
*p
, register struct chown_args
*uap
, register_t
*retval
)
3062 struct vfs_context context
;
3064 context
.vc_proc
= p
;
3065 context
.vc_ucred
= kauth_cred_get();
3067 return chown1(&context
, uap
, retval
, 1);
3071 lchown(struct proc
*p
, register struct lchown_args
*uap
, register_t
*retval
)
3073 struct vfs_context context
;
3075 context
.vc_proc
= p
;
3076 context
.vc_ucred
= kauth_cred_get();
3078 /* Argument list identical, but machine generated; cast for chown1() */
3079 return chown1(&context
, (struct chown_args
*)uap
, retval
, 0);
3083 * Set ownership given a file descriptor.
3087 fchown(struct proc
*p
, register struct fchown_args
*uap
, __unused register_t
*retval
)
3089 struct vnode_attr va
;
3090 struct vfs_context context
;
3093 kauth_action_t action
;
3095 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
3096 AUDIT_ARG(fd
, uap
->fd
);
3098 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
3101 if ( (error
= vnode_getwithref(vp
)) ) {
3105 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
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 context
.vc_proc
= p
;
3114 context
.vc_ucred
= kauth_cred_get();
3116 /* preflight and authorize attribute changes */
3117 if ((error
= vnode_authattr(vp
, &va
, &action
, &context
)) != 0)
3119 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0)) {
3120 if (error
== EACCES
)
3124 error
= vnode_setattr(vp
, &va
, &context
);
3127 (void)vnode_put(vp
);
3133 getutimes(usrtvp
, tsp
)
3135 struct timespec
*tsp
;
3137 struct user_timeval tv
[2];
3140 if (usrtvp
== USER_ADDR_NULL
) {
3141 struct timeval old_tv
;
3142 /* XXX Y2038 bug because of microtime argument */
3144 TIMEVAL_TO_TIMESPEC(&old_tv
, &tsp
[0]);
3147 if (IS_64BIT_PROCESS(current_proc())) {
3148 error
= copyin(usrtvp
, (void *)tv
, sizeof(tv
));
3150 struct timeval old_tv
[2];
3151 error
= copyin(usrtvp
, (void *)old_tv
, sizeof(old_tv
));
3152 tv
[0].tv_sec
= old_tv
[0].tv_sec
;
3153 tv
[0].tv_usec
= old_tv
[0].tv_usec
;
3154 tv
[1].tv_sec
= old_tv
[1].tv_sec
;
3155 tv
[1].tv_usec
= old_tv
[1].tv_usec
;
3159 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
3160 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
3166 setutimes(vfs_context_t ctx
, struct vnode
*vp
, const struct timespec
*ts
,
3170 struct vnode_attr va
;
3171 kauth_action_t action
;
3173 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3176 VATTR_SET(&va
, va_access_time
, ts
[0]);
3177 VATTR_SET(&va
, va_modify_time
, ts
[1]);
3179 va
.va_vaflags
|= VA_UTIMES_NULL
;
3181 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
3183 /* since we may not need to auth anything, check here */
3184 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
3186 error
= vnode_setattr(vp
, &va
, ctx
);
3193 * Set the access and modification times of a file.
3197 utimes(struct proc
*p
, register struct utimes_args
*uap
, __unused register_t
*retval
)
3199 struct timespec ts
[2];
3202 struct nameidata nd
;
3203 struct vfs_context context
;
3205 context
.vc_proc
= p
;
3206 context
.vc_ucred
= kauth_cred_get();
3208 /* AUDIT: Needed to change the order of operations to do the
3209 * name lookup first because auditing wants the path.
3211 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3212 UIO_USERSPACE
, uap
->path
, &context
);
3219 * Fetch the user-supplied time. If usrtvp is USER_ADDR_NULL, we fetch
3220 * the current time instead.
3223 if ((error
= getutimes(usrtvp
, ts
)) != 0)
3226 error
= setutimes(&context
, nd
.ni_vp
, ts
, usrtvp
== USER_ADDR_NULL
);
3229 vnode_put(nd
.ni_vp
);
3234 * Set the access and modification times of a file.
3238 futimes(struct proc
*p
, register struct futimes_args
*uap
, __unused register_t
*retval
)
3240 struct timespec ts
[2];
3244 struct vfs_context context
;
3246 context
.vc_proc
= p
;
3247 context
.vc_ucred
= kauth_cred_get();
3249 AUDIT_ARG(fd
, uap
->fd
);
3251 if ((error
= getutimes(usrtvp
, ts
)) != 0)
3253 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
3255 if((error
= vnode_getwithref(vp
))) {
3260 error
= setutimes(&context
, vp
, ts
, usrtvp
== 0);
3267 * Truncate a file given its path name.
3271 truncate(struct proc
*p
, register struct truncate_args
*uap
, __unused register_t
*retval
)
3273 register struct vnode
*vp
;
3274 struct vnode_attr va
;
3275 struct vfs_context context
;
3277 struct nameidata nd
;
3278 kauth_action_t action
;
3280 context
.vc_proc
= p
;
3281 context
.vc_ucred
= kauth_cred_get();
3283 if (uap
->length
< 0)
3285 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3286 UIO_USERSPACE
, uap
->path
, &context
);
3287 if ((error
= namei(&nd
)))
3294 VATTR_SET(&va
, va_data_size
, uap
->length
);
3295 if ((error
= vnode_authattr(vp
, &va
, &action
, &context
)) != 0)
3297 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0))
3299 error
= vnode_setattr(vp
, &va
, &context
);
3306 * Truncate a file given a file descriptor.
3310 ftruncate(p
, uap
, retval
)
3312 register struct ftruncate_args
*uap
;
3315 struct vfs_context context
;
3316 struct vnode_attr va
;
3318 struct fileproc
*fp
;
3322 context
.vc_proc
= current_proc();
3323 context
.vc_ucred
= kauth_cred_get();
3325 AUDIT_ARG(fd
, uap
->fd
);
3326 if (uap
->length
< 0)
3329 if ( (error
= fp_lookup(p
,fd
,&fp
,0)) ) {
3333 if (fp
->f_fglob
->fg_type
== DTYPE_PSXSHM
) {
3334 error
= pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
);
3337 if (fp
->f_fglob
->fg_type
!= DTYPE_VNODE
) {
3342 vp
= (struct vnode
*)fp
->f_fglob
->fg_data
;
3344 if ((fp
->f_fglob
->fg_flag
& FWRITE
) == 0) {
3345 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
3350 if ((error
= vnode_getwithref(vp
)) != 0) {
3354 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3357 VATTR_SET(&va
, va_data_size
, uap
->length
);
3358 error
= vnode_setattr(vp
, &va
, &context
);
3359 (void)vnode_put(vp
);
3367 * Sync an open file.
3371 fsync(struct proc
*p
, struct fsync_args
*uap
, __unused register_t
*retval
)
3374 struct fileproc
*fp
;
3375 struct vfs_context context
;
3378 if ( (error
= fp_getfvp(p
, uap
->fd
, &fp
, &vp
)) )
3380 if ( (error
= vnode_getwithref(vp
)) ) {
3384 context
.vc_proc
= p
;
3385 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
3387 error
= VNOP_FSYNC(vp
, MNT_WAIT
, &context
);
3389 (void)vnode_put(vp
);
3395 * Duplicate files. Source must be a file, target must be a file or
3398 * XXX Copyfile authorisation checking is woefully inadequate, and will not
3399 * perform inheritance correctly.
3403 copyfile(struct proc
*p
, register struct copyfile_args
*uap
, __unused register_t
*retval
)
3405 vnode_t tvp
, fvp
, tdvp
, sdvp
;
3406 struct nameidata fromnd
, tond
;
3408 struct vfs_context context
;
3410 context
.vc_proc
= p
;
3411 context
.vc_ucred
= kauth_cred_get();
3413 /* Check that the flags are valid. */
3415 if (uap
->flags
& ~CPF_MASK
) {
3419 NDINIT(&fromnd
, LOOKUP
, SAVESTART
| AUDITVNPATH1
,
3420 UIO_USERSPACE
, uap
->from
, &context
);
3421 if ((error
= namei(&fromnd
)))
3425 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
| AUDITVNPATH2
,
3426 UIO_USERSPACE
, uap
->to
, &context
);
3427 if ((error
= namei(&tond
))) {
3434 if (!(uap
->flags
& CPF_OVERWRITE
)) {
3439 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
3444 if ((error
= vnode_authorize(tdvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
3450 * If source is the same as the destination (that is the
3451 * same inode number) then there is nothing to do.
3452 * (fixed to have POSIX semantics - CSM 3/2/98)
3457 error
= VNOP_COPYFILE(fvp
,tdvp
,tvp
,&tond
.ni_cnd
,uap
->mode
,uap
->flags
,&context
);
3459 sdvp
= tond
.ni_startdir
;
3461 * nameidone has to happen before we vnode_put(tdvp)
3462 * since it may need to release the fs_nodelock on the tdvp
3473 if (fromnd
.ni_startdir
)
3474 vnode_put(fromnd
.ni_startdir
);
3484 * Rename files. Source and destination must either both be directories,
3485 * or both not be directories. If target is a directory, it must be empty.
3489 rename(proc_t p
, register struct rename_args
*uap
, __unused register_t
*retval
)
3493 struct nameidata fromnd
, tond
;
3494 struct vfs_context context
;
3497 char *oname
, *from_name
, *to_name
;
3498 int from_len
, to_len
;
3499 int holding_mntlock
;
3500 mount_t locked_mp
= NULL
;
3502 fse_info from_finfo
, to_finfo
;
3504 context
.vc_proc
= p
;
3505 context
.vc_ucred
= kauth_cred_get();
3506 holding_mntlock
= 0;
3512 NDINIT(&fromnd
, DELETE
, WANTPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->from
, &context
);
3514 if ( (error
= namei(&fromnd
)) )
3516 fdvp
= fromnd
.ni_dvp
;
3519 NDINIT(&tond
, RENAME
, WANTPARENT
| AUDITVNPATH2
, UIO_USERSPACE
, uap
->to
, &context
);
3520 if (fvp
->v_type
== VDIR
)
3521 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
3523 if ( (error
= namei(&tond
)) ) {
3525 * Translate error code for rename("dir1", "dir2/.").
3527 if (error
== EISDIR
&& fvp
->v_type
== VDIR
)
3535 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
3538 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
3551 * If tvp is a directory and not the same as fdvp, or tdvp is not the same as fdvp,
3552 * the node is moving between directories and we need rights to remove from the
3553 * old and add to the new.
3555 * If tvp already exists and is not a directory, we need to be allowed to delete it.
3557 * Note that we do not inherit when renaming. XXX this needs to be revisited to
3558 * implement the deferred-inherit bit.
3564 if ((tvp
!= NULL
) && vnode_isdir(tvp
)) {
3567 } else if (tdvp
!= fdvp
) {
3571 * must have delete rights to remove the old name even in the simple case of
3574 if ((error
= vnode_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
, &context
)) != 0)
3577 /* moving into tdvp or tvp, must have rights to add */
3578 if ((error
= vnode_authorize(((tvp
!= NULL
) && vnode_isdir(tvp
)) ? tvp
: tdvp
,
3580 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
3584 /* node staying in same directory, must be allowed to add new name */
3585 if ((error
= vnode_authorize(fdvp
, NULL
,
3586 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
3589 /* overwriting tvp */
3590 if ((tvp
!= NULL
) && !vnode_isdir(tvp
) &&
3591 ((error
= vnode_authorize(tvp
, tdvp
, KAUTH_VNODE_DELETE
, &context
)) != 0))
3594 /* XXX more checks? */
3597 /* authorization denied */
3602 * Allow the renaming of mount points.
3603 * - target must not exist
3604 * - target must reside in the same directory as source
3605 * - union mounts cannot be renamed
3606 * - "/" cannot be renamed
3608 if ((fvp
->v_flag
& VROOT
) &&
3609 (fvp
->v_type
== VDIR
) &&
3611 (fvp
->v_mountedhere
== NULL
) &&
3613 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
3614 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
3615 struct vnode
*coveredvp
;
3617 /* switch fvp to the covered vnode */
3618 coveredvp
= fvp
->v_mount
->mnt_vnodecovered
;
3619 if ( (vnode_getwithref(coveredvp
)) ) {
3629 * Check for cross-device rename.
3631 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
3632 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
3637 * Avoid renaming "." and "..".
3639 if (fvp
->v_type
== VDIR
&&
3641 (fromnd
.ni_cnd
.cn_namelen
== 1 && fromnd
.ni_cnd
.cn_nameptr
[0] == '.') ||
3642 ((fromnd
.ni_cnd
.cn_flags
| tond
.ni_cnd
.cn_flags
) & ISDOTDOT
)) ) {
3647 * The following edge case is caught here:
3648 * (to cannot be a descendent of from)
3661 if (tdvp
->v_parent
== fvp
) {
3667 * If source is the same as the destination (that is the
3668 * same inode number) then there is nothing to do...
3669 * EXCEPT if the underlying file system supports case
3670 * insensitivity and is case preserving. In this case
3671 * the file system needs to handle the special case of
3672 * getting the same vnode as target (fvp) and source (tvp).
3674 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
3675 * and _PC_CASE_PRESERVING can have this exception, and they need to
3676 * handle the special case of getting the same vnode as target and
3677 * source. NOTE: Then the target is unlocked going into vnop_rename,
3678 * so not to cause locking problems. There is a single reference on tvp.
3680 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
3681 * that correct behaviour then is just to remove the source (link)
3683 if (fvp
== tvp
&& fdvp
== tdvp
) {
3684 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
3685 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
3686 fromnd
.ni_cnd
.cn_namelen
)) {
3691 if (holding_mntlock
&& fvp
->v_mount
!= locked_mp
) {
3693 * we're holding a reference and lock
3694 * on locked_mp, but it no longer matches
3695 * what we want to do... so drop our hold
3697 mount_unlock_renames(locked_mp
);
3698 mount_drop(locked_mp
, 0);
3699 holding_mntlock
= 0;
3701 if (tdvp
!= fdvp
&& fvp
->v_type
== VDIR
) {
3703 * serialize renames that re-shape
3704 * the tree... if holding_mntlock is
3705 * set, then we're ready to go...
3707 * first need to drop the iocounts
3708 * we picked up, second take the
3709 * lock to serialize the access,
3710 * then finally start the lookup
3711 * process over with the lock held
3713 if (!holding_mntlock
) {
3715 * need to grab a reference on
3716 * the mount point before we
3717 * drop all the iocounts... once
3718 * the iocounts are gone, the mount
3721 locked_mp
= fvp
->v_mount
;
3722 mount_ref(locked_mp
, 0);
3725 * nameidone has to happen before we vnode_put(tvp)
3726 * since it may need to release the fs_nodelock on the tvp
3735 * nameidone has to happen before we vnode_put(fdvp)
3736 * since it may need to release the fs_nodelock on the fvp
3743 mount_lock_renames(locked_mp
);
3744 holding_mntlock
= 1;
3750 * when we dropped the iocounts to take
3751 * the lock, we allowed the identity of
3752 * the various vnodes to change... if they did,
3753 * we may no longer be dealing with a rename
3754 * that reshapes the tree... once we're holding
3755 * the iocounts, the vnodes can't change type
3756 * so we're free to drop the lock at this point
3759 if (holding_mntlock
) {
3760 mount_unlock_renames(locked_mp
);
3761 mount_drop(locked_mp
, 0);
3762 holding_mntlock
= 0;
3765 // save these off so we can later verify that fvp is the same
3766 oname
= fvp
->v_name
;
3767 oparent
= fvp
->v_parent
;
3769 if (need_fsevent(FSE_RENAME
, fvp
)) {
3770 get_fse_info(fvp
, &from_finfo
, &context
);
3773 get_fse_info(tvp
, &to_finfo
, &context
);
3775 from_name
= get_pathbuff();
3776 from_len
= MAXPATHLEN
;
3777 vn_getpath(fvp
, from_name
, &from_len
);
3779 to_name
= get_pathbuff();
3780 to_len
= MAXPATHLEN
;
3782 if (tvp
&& tvp
->v_type
!= VDIR
) {
3783 vn_getpath(tvp
, to_name
, &to_len
);
3785 vn_getpath(tdvp
, to_name
, &to_len
);
3786 // if the path is not just "/", then append a "/"
3788 to_name
[to_len
-1] = '/';
3792 strcpy(&to_name
[to_len
], tond
.ni_cnd
.cn_nameptr
);
3793 to_len
+= tond
.ni_cnd
.cn_namelen
+ 1;
3794 to_name
[to_len
] = '\0';
3800 error
= VNOP_RENAME(fdvp
, fvp
, &fromnd
.ni_cnd
,
3801 tdvp
, tvp
, &tond
.ni_cnd
,
3804 if (holding_mntlock
) {
3806 * we can drop our serialization
3809 mount_unlock_renames(locked_mp
);
3810 mount_drop(locked_mp
, 0);
3811 holding_mntlock
= 0;
3814 if (to_name
!= NULL
)
3815 release_pathbuff(to_name
);
3816 if (from_name
!= NULL
)
3817 release_pathbuff(from_name
);
3818 from_name
= to_name
= NULL
;
3823 /* call out to allow 3rd party notification of rename.
3824 * Ignore result of kauth_authorize_fileop call.
3826 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_RENAME
,
3827 (uintptr_t)from_name
, (uintptr_t)to_name
);
3829 if (from_name
!= NULL
&& to_name
!= NULL
) {
3831 add_fsevent(FSE_RENAME
, &context
,
3832 FSE_ARG_STRING
, from_len
, from_name
,
3833 FSE_ARG_FINFO
, &from_finfo
,
3834 FSE_ARG_STRING
, to_len
, to_name
,
3835 FSE_ARG_FINFO
, &to_finfo
,
3838 add_fsevent(FSE_RENAME
, &context
,
3839 FSE_ARG_STRING
, from_len
, from_name
,
3840 FSE_ARG_FINFO
, &from_finfo
,
3841 FSE_ARG_STRING
, to_len
, to_name
,
3845 if (to_name
!= NULL
)
3846 release_pathbuff(to_name
);
3847 if (from_name
!= NULL
)
3848 release_pathbuff(from_name
);
3849 from_name
= to_name
= NULL
;
3852 * update filesystem's mount point data
3855 char *cp
, *pathend
, *mpname
;
3861 mp
= fvp
->v_mountedhere
;
3863 if (vfs_busy(mp
, LK_NOWAIT
)) {
3867 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
3869 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
3871 /* find current mount point prefix */
3872 pathend
= &mp
->mnt_vfsstat
.f_mntonname
[0];
3873 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
3877 /* find last component of target name */
3878 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
3882 /* append name to prefix */
3883 maxlen
= MAXPATHLEN
- (pathend
- mp
->mnt_vfsstat
.f_mntonname
);
3884 bzero(pathend
, maxlen
);
3885 strncpy(pathend
, mpname
, maxlen
- 1);
3887 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
3892 * fix up name & parent pointers. note that we first
3893 * check that fvp has the same name/parent pointers it
3894 * had before the rename call... this is a 'weak' check
3897 if (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
) {
3900 update_flags
= VNODE_UPDATE_NAME
;
3903 update_flags
|= VNODE_UPDATE_PARENT
;
3905 vnode_update_identity(fvp
, tdvp
, tond
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_namelen
, tond
.ni_cnd
.cn_hash
, update_flags
);
3908 if (holding_mntlock
) {
3909 mount_unlock_renames(locked_mp
);
3910 mount_drop(locked_mp
, 0);
3914 * nameidone has to happen before we vnode_put(tdvp)
3915 * since it may need to release the fs_nodelock on the tdvp
3925 * nameidone has to happen before we vnode_put(fdvp)
3926 * since it may need to release the fs_nodelock on the fdvp
3938 * Make a directory file.
3942 mkdir1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
3946 int update_flags
= 0;
3947 struct nameidata nd
;
3949 AUDIT_ARG(mode
, vap
->va_mode
);
3950 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
3951 UIO_USERSPACE
, path
, ctx
);
3952 nd
.ni_cnd
.cn_flags
|= WILLBEDIR
;
3964 /* authorize addition of a directory to the parent */
3965 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
)) != 0)
3968 VATTR_SET(vap
, va_type
, VDIR
);
3970 /* make the directory */
3971 if ((error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
)) != 0)
3974 // Make sure the name & parent pointers are hooked up
3975 if (vp
->v_name
== NULL
)
3976 update_flags
|= VNODE_UPDATE_NAME
;
3977 if (vp
->v_parent
== NULLVP
)
3978 update_flags
|= VNODE_UPDATE_PARENT
;
3981 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
3983 add_fsevent(FSE_CREATE_DIR
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
3987 * nameidone has to happen before we vnode_put(dvp)
3988 * since it may need to release the fs_nodelock on the dvp
4001 mkdir_extended(struct proc
*p
, register struct mkdir_extended_args
*uap
, __unused register_t
*retval
)
4003 struct vfs_context context
;
4005 kauth_filesec_t xsecdst
;
4006 struct vnode_attr va
;
4009 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
4010 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
4013 context
.vc_proc
= p
;
4014 context
.vc_ucred
= kauth_cred_get();
4017 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
4018 if (xsecdst
!= NULL
)
4019 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
4021 ciferror
= mkdir1(&context
, uap
->path
, &va
);
4022 if (xsecdst
!= NULL
)
4023 kauth_filesec_free(xsecdst
);
4028 mkdir(struct proc
*p
, register struct mkdir_args
*uap
, __unused register_t
*retval
)
4030 struct vfs_context context
;
4031 struct vnode_attr va
;
4033 context
.vc_proc
= p
;
4034 context
.vc_ucred
= kauth_cred_get();
4037 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
4039 return(mkdir1(&context
, uap
->path
, &va
));
4043 * Remove a directory file.
4047 rmdir(struct proc
*p
, struct rmdir_args
*uap
, __unused register_t
*retval
)
4051 struct nameidata nd
;
4052 struct vfs_context context
;
4054 context
.vc_proc
= p
;
4055 context
.vc_ucred
= kauth_cred_get();
4057 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
4058 UIO_USERSPACE
, uap
->path
, &context
);
4065 if (vp
->v_type
!= VDIR
) {
4067 * rmdir only deals with directories
4070 } else if (dvp
== vp
) {
4072 * No rmdir "." please.
4075 } else if (vp
->v_flag
& VROOT
) {
4077 * The root of a mounted filesystem cannot be deleted.
4081 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, &context
);
4088 if (need_fsevent(FSE_DELETE
, dvp
)) {
4089 path
= get_pathbuff();
4091 vn_getpath(vp
, path
, &len
);
4092 get_fse_info(vp
, &finfo
, &context
);
4094 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, &context
);
4096 if (!error
&& path
!= NULL
) {
4097 add_fsevent(FSE_DELETE
, &context
,
4098 FSE_ARG_STRING
, len
, path
,
4099 FSE_ARG_FINFO
, &finfo
,
4103 release_pathbuff(path
);
4106 * nameidone has to happen before we vnode_put(dvp)
4107 * since it may need to release the fs_nodelock on the dvp
4119 * Read a block of directory entries in a file system independent format.
4122 getdirentries(p
, uap
, retval
)
4124 register struct getdirentries_args
*uap
;
4128 struct vfs_context context
;
4129 struct fileproc
*fp
;
4131 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4135 char uio_buf
[ UIO_SIZEOF(1) ];
4137 AUDIT_ARG(fd
, uap
->fd
);
4138 error
= fp_getfvp(p
, fd
, &fp
, &vp
);
4142 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
4143 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4147 if ( (error
= vnode_getwithref(vp
)) ) {
4151 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4154 if (vp
->v_type
!= VDIR
) {
4155 (void)vnode_put(vp
);
4159 context
.vc_proc
= p
;
4160 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
4162 loff
= fp
->f_fglob
->fg_offset
;
4163 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
4164 &uio_buf
[0], sizeof(uio_buf
));
4165 uio_addiov(auio
, uap
->buf
, uap
->count
);
4167 error
= VNOP_READDIR(vp
, auio
, 0, &eofflag
, (int *)NULL
, &context
);
4168 fp
->f_fglob
->fg_offset
= uio_offset(auio
);
4170 (void)vnode_put(vp
);
4176 if ((uap
->count
== uio_resid(auio
)) &&
4177 (vp
->v_op
== union_vnodeop_p
)) {
4180 lvp
= union_dircache(vp
, p
);
4181 if (lvp
!= NULLVP
) {
4182 struct vnode_attr va
;
4184 * If the directory is opaque,
4185 * then don't show lower entries
4188 VATTR_WANTED(&va
, va_flags
);
4189 error
= vnode_getattr(vp
, &va
, &context
);
4190 if (va
.va_flags
& OPAQUE
) {
4196 if (lvp
!= NULLVP
) {
4197 error
= VNOP_OPEN(lvp
, FREAD
, &context
);
4203 fp
->f_fglob
->fg_data
= (caddr_t
) lvp
;
4204 fp
->f_fglob
->fg_offset
= 0;
4205 error
= VNOP_CLOSE(vp
, FREAD
, &context
);
4217 if (((user_ssize_t
)uap
->count
== uio_resid(auio
)) &&
4218 (vp
->v_flag
& VROOT
) &&
4219 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
4220 struct vnode
*tvp
= vp
;
4221 vp
= vp
->v_mount
->mnt_vnodecovered
;
4222 vnode_getwithref(vp
);
4224 fp
->f_fglob
->fg_data
= (caddr_t
) vp
;
4225 fp
->f_fglob
->fg_offset
= 0;
4231 error
= copyout((caddr_t
)&loff
, uap
->basep
, sizeof(long));
4232 // LP64todo - fix this
4233 *retval
= uap
->count
- uio_resid(auio
);
4240 * Set the mode mask for creation of filesystem nodes.
4242 #warning XXX implement xsecurity
4244 #define UMASK_NOXSECURITY (void *)1 /* leave existing xsecurity alone */
4246 umask1(struct proc
*p
, int newmask
, __unused kauth_filesec_t fsec
, register_t
*retval
)
4248 register struct filedesc
*fdp
;
4250 AUDIT_ARG(mask
, newmask
);
4252 *retval
= fdp
->fd_cmask
;
4253 fdp
->fd_cmask
= newmask
& ALLPERMS
;
4259 umask_extended(struct proc
*p
, struct umask_extended_args
*uap
, register_t
*retval
)
4262 kauth_filesec_t xsecdst
;
4264 xsecdst
= KAUTH_FILESEC_NONE
;
4265 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
4266 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
4269 xsecdst
= KAUTH_FILESEC_NONE
;
4272 ciferror
= umask1(p
, uap
->newmask
, xsecdst
, retval
);
4274 if (xsecdst
!= KAUTH_FILESEC_NONE
)
4275 kauth_filesec_free(xsecdst
);
4280 umask(struct proc
*p
, struct umask_args
*uap
, register_t
*retval
)
4282 return(umask1(p
, uap
->newmask
, UMASK_NOXSECURITY
, retval
));
4286 * Void all references to file by ripping underlying filesystem
4291 revoke(struct proc
*p
, register struct revoke_args
*uap
, __unused register_t
*retval
)
4293 register struct vnode
*vp
;
4294 struct vnode_attr va
;
4295 struct vfs_context context
;
4297 struct nameidata nd
;
4299 context
.vc_proc
= p
;
4300 context
.vc_ucred
= kauth_cred_get();
4302 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4303 UIO_USERSPACE
, uap
->path
, &context
);
4312 VATTR_WANTED(&va
, va_uid
);
4313 if ((error
= vnode_getattr(vp
, &va
, &context
)))
4315 if (kauth_cred_getuid(context
.vc_ucred
) != va
.va_uid
&&
4316 (error
= suser(context
.vc_ucred
, &p
->p_acflag
)))
4318 if (vp
->v_usecount
> 1 || (vp
->v_flag
& VALIASED
))
4319 VNOP_REVOKE(vp
, REVOKEALL
, &context
);
4327 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
4328 * The following system calls are designed to support features
4329 * which are specific to the HFS & HFS Plus volume formats
4332 #ifdef __APPLE_API_OBSOLETE
4334 /************************************************/
4335 /* *** Following calls will be deleted soon *** */
4336 /************************************************/
4339 * Make a complex file. A complex file is one with multiple forks (data streams)
4343 mkcomplex(__unused
struct proc
*p
, __unused
struct mkcomplex_args
*uap
, __unused register_t
*retval
)
4349 * Extended stat call which returns volumeid and vnodeid as well as other info
4353 statv(__unused
struct proc
*p
,
4354 __unused
struct statv_args
*uap
,
4355 __unused register_t
*retval
)
4357 return (ENOTSUP
); /* We'll just return an error for now */
4359 } /* end of statv system call */
4362 * Extended lstat call which returns volumeid and vnodeid as well as other info
4366 lstatv(__unused
struct proc
*p
,
4367 __unused
struct lstatv_args
*uap
,
4368 __unused register_t
*retval
)
4370 return (ENOTSUP
); /* We'll just return an error for now */
4371 } /* end of lstatv system call */
4374 * Extended fstat call which returns volumeid and vnodeid as well as other info
4378 fstatv(__unused
struct proc
*p
,
4379 __unused
struct fstatv_args
*uap
,
4380 __unused register_t
*retval
)
4382 return (ENOTSUP
); /* We'll just return an error for now */
4383 } /* end of fstatv system call */
4386 /************************************************/
4387 /* *** Preceding calls will be deleted soon *** */
4388 /************************************************/
4390 #endif /* __APPLE_API_OBSOLETE */
4393 * Obtain attribute information on objects in a directory while enumerating
4394 * the directory. This call does not yet support union mounted directories.
4396 * 1.union mounted directories.
4401 getdirentriesattr (struct proc
*p
, struct getdirentriesattr_args
*uap
, register_t
*retval
)
4404 struct fileproc
*fp
;
4406 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4407 uint64_t actualcount
;
4412 struct attrlist attributelist
;
4413 struct vfs_context context
;
4415 char uio_buf
[ UIO_SIZEOF(1) ];
4416 kauth_action_t action
;
4420 /* Get the attributes into kernel space */
4421 if ((error
= copyin(uap
->alist
, (caddr_t
) &attributelist
, sizeof (attributelist
))))
4423 actualcount
= fuulong(uap
->count
);
4424 if (actualcount
== -1ULL)
4427 if ( (error
= fp_getfvp(p
, fd
, &fp
, &vp
)) )
4430 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
4431 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4435 if ( (error
= vnode_getwithref(vp
)) )
4438 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4440 if (vp
->v_type
!= VDIR
) {
4441 (void)vnode_put(vp
);
4446 /* set up the uio structure which will contain the users return buffer */
4447 loff
= fp
->f_fglob
->fg_offset
;
4448 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
4449 &uio_buf
[0], sizeof(uio_buf
));
4450 uio_addiov(auio
, uap
->buffer
, uap
->buffersize
);
4452 context
.vc_proc
= p
;
4453 context
.vc_ucred
= kauth_cred_get();
4454 tmpcount
= (u_long
) actualcount
;
4457 * If the only item requested is file names, we can let that past with
4458 * just LIST_DIRECTORY. If they want any other attributes, that means
4459 * they need SEARCH as well.
4461 action
= KAUTH_VNODE_LIST_DIRECTORY
;
4462 if ((attributelist
.commonattr
& ~ATTR_CMN_NAME
) ||
4463 attributelist
.fileattr
|| attributelist
.dirattr
)
4464 action
|= KAUTH_VNODE_SEARCH
;
4466 if ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) == 0)
4467 error
= VNOP_READDIRATTR(vp
, &attributelist
, auio
,
4468 tmpcount
, uap
->options
, &newstate
, &eofflag
,
4469 &tmpcount
, &context
);
4470 (void)vnode_put(vp
);
4471 actualcount
= tmpcount
;
4475 fp
->f_fglob
->fg_offset
= uio_offset(auio
); /* should be multiple of dirent, not variable */
4477 if ((error
= suulong(uap
->count
, actualcount
)) != 0)
4479 if ((error
= suulong(uap
->newstate
, (uint64_t)newstate
)) != 0)
4481 if ((error
= suulong(uap
->basep
, (uint64_t)loff
)) != 0)
4484 *retval
= eofflag
; /* similar to getdirentries */
4488 return (error
); /* return error earlier, an retval of 0 or 1 now */
4490 } /* end of getdirentryattr system call */
4493 * Exchange data between two files
4498 exchangedata (struct proc
*p
, register struct exchangedata_args
*uap
, __unused register_t
*retval
)
4501 struct nameidata fnd
, snd
;
4502 struct vfs_context context
;
4503 struct vnode
*fvp
, *svp
;
4509 fse_info f_finfo
, s_finfo
;
4511 context
.vc_proc
= p
;
4512 context
.vc_ucred
= kauth_cred_get();
4515 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4517 NDINIT(&fnd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4518 UIO_USERSPACE
, uap
->path1
, &context
);
4520 error
= namei(&fnd
);
4527 NDINIT(&snd
, LOOKUP
, nameiflags
| AUDITVNPATH2
,
4528 UIO_USERSPACE
, uap
->path2
, &context
);
4530 error
= namei(&snd
);
4539 * if the files are the same, return an inval error
4547 * if the files are on different volumes, return an error
4549 if (svp
->v_mount
!= fvp
->v_mount
) {
4553 if (((error
= vnode_authorize(fvp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0) ||
4554 ((error
= vnode_authorize(svp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0))
4557 if (need_fsevent(FSE_EXCHANGE
, fvp
) || kauth_authorize_fileop_has_listeners()) {
4558 fpath
= get_pathbuff();
4559 spath
= get_pathbuff();
4562 if (vn_getpath(fvp
, fpath
, &flen
) != 0 || fpath
[0] == '\0') {
4563 printf("exchange: vn_getpath(fvp=0x%x) failed <<%s>>\n",
4566 if (vn_getpath(svp
, spath
, &slen
) != 0 || spath
[0] == '\0') {
4567 printf("exchange: vn_getpath(svp=0x%x) failed <<%s>>\n",
4570 get_fse_info(fvp
, &f_finfo
, &context
);
4571 get_fse_info(svp
, &s_finfo
, &context
);
4573 /* Ok, make the call */
4574 error
= VNOP_EXCHANGE(fvp
, svp
, 0, &context
);
4579 if (fpath
!= NULL
&& spath
!= NULL
) {
4580 /* call out to allow 3rd party notification of exchangedata.
4581 * Ignore result of kauth_authorize_fileop call.
4583 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_EXCHANGE
,
4584 (uintptr_t)fpath
, (uintptr_t)spath
);
4588 tmpname
= fvp
->v_name
;
4589 fvp
->v_name
= svp
->v_name
;
4590 svp
->v_name
= tmpname
;
4592 if (fvp
->v_parent
!= svp
->v_parent
) {
4595 tmp
= fvp
->v_parent
;
4596 fvp
->v_parent
= svp
->v_parent
;
4597 svp
->v_parent
= tmp
;
4599 name_cache_unlock();
4601 if (fpath
!= NULL
&& spath
!= NULL
) {
4602 add_fsevent(FSE_EXCHANGE
, &context
,
4603 FSE_ARG_STRING
, flen
, fpath
,
4604 FSE_ARG_FINFO
, &f_finfo
,
4605 FSE_ARG_STRING
, slen
, spath
,
4606 FSE_ARG_FINFO
, &s_finfo
,
4611 release_pathbuff(spath
);
4613 release_pathbuff(fpath
);
4623 #ifdef __APPLE_API_OBSOLETE
4625 /************************************************/
4626 /* *** Following calls will be deleted soon *** */
4627 /************************************************/
4630 * Check users access to a file
4634 #warning "checkuseraccess copies a cred in from user space but"
4635 #warning "user space has no way of knowing what one looks like"
4636 #warning "this code should use the access_extended spoof-as functionality"
4638 checkuseraccess (struct proc
*p
, register struct checkuseraccess_args
*uap
, __unused register_t
*retval
)
4640 register struct vnode
*vp
;
4642 struct nameidata nd
;
4643 struct ucred cred
; /* XXX ILLEGAL */
4644 int flags
; /*what will actually get passed to access*/
4646 struct vfs_context context
;
4648 /* Make sure that the number of groups is correct before we do anything */
4650 if ((uap
->ngroups
<= 0) || (uap
->ngroups
> NGROUPS
))
4653 /* Verify that the caller is root */
4655 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
4658 /* Fill in the credential structure */
4661 cred
.cr_uid
= uap
->userid
;
4662 cred
.cr_ngroups
= uap
->ngroups
;
4663 if ((error
= copyin(CAST_USER_ADDR_T(uap
->groups
), (caddr_t
) &(cred
.cr_groups
), (sizeof(gid_t
))*uap
->ngroups
)))
4666 context
.vc_proc
= p
;
4667 context
.vc_ucred
= &cred
;
4669 /* Get our hands on the file */
4671 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4672 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4673 UIO_USERSPACE
, CAST_USER_ADDR_T(uap
->path
), &context
);
4675 if ((error
= namei(&nd
)))
4680 /* Flags == 0 means only check for existence. */
4684 if (uap
->accessrequired
) {
4685 if (uap
->accessrequired
& R_OK
)
4686 flags
|= KAUTH_VNODE_READ_DATA
;
4687 if (uap
->accessrequired
& W_OK
)
4688 flags
|= KAUTH_VNODE_WRITE_DATA
;
4689 if (uap
->accessrequired
& X_OK
)
4690 flags
|= KAUTH_VNODE_EXECUTE
;
4692 error
= vnode_authorize(vp
, NULL
, flags
, &context
);
4701 } /* end of checkuseraccess system call */
4703 /************************************************/
4704 /* *** Preceding calls will be deleted soon *** */
4705 /************************************************/
4707 #endif /* __APPLE_API_OBSOLETE */
4714 searchfs (struct proc
*p
, register struct searchfs_args
*uap
, __unused register_t
*retval
)
4716 register struct vnode
*vp
;
4719 struct nameidata nd
;
4720 struct user_fssearchblock searchblock
;
4721 struct searchstate
*state
;
4722 struct attrlist
*returnattrs
;
4723 void *searchparams1
,*searchparams2
;
4725 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4729 struct vfs_context context
;
4730 char uio_buf
[ UIO_SIZEOF(1) ];
4732 context
.vc_proc
= p
;
4733 context
.vc_ucred
= kauth_cred_get();
4735 /* Start by copying in fsearchblock paramater list */
4736 if (IS_64BIT_PROCESS(p
)) {
4737 error
= copyin(uap
->searchblock
, (caddr_t
) &searchblock
, sizeof(searchblock
));
4740 struct fssearchblock tmp_searchblock
;
4741 error
= copyin(uap
->searchblock
, (caddr_t
) &tmp_searchblock
, sizeof(tmp_searchblock
));
4742 // munge into 64-bit version
4743 searchblock
.returnattrs
= CAST_USER_ADDR_T(tmp_searchblock
.returnattrs
);
4744 searchblock
.returnbuffer
= CAST_USER_ADDR_T(tmp_searchblock
.returnbuffer
);
4745 searchblock
.returnbuffersize
= tmp_searchblock
.returnbuffersize
;
4746 searchblock
.maxmatches
= tmp_searchblock
.maxmatches
;
4747 searchblock
.timelimit
= tmp_searchblock
.timelimit
;
4748 searchblock
.searchparams1
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams1
);
4749 searchblock
.sizeofsearchparams1
= tmp_searchblock
.sizeofsearchparams1
;
4750 searchblock
.searchparams2
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams2
);
4751 searchblock
.sizeofsearchparams2
= tmp_searchblock
.sizeofsearchparams2
;
4752 searchblock
.searchattrs
= tmp_searchblock
.searchattrs
;
4757 /* Do a sanity check on sizeofsearchparams1 and sizeofsearchparams2.
4759 if (searchblock
.sizeofsearchparams1
> SEARCHFS_MAX_SEARCHPARMS
||
4760 searchblock
.sizeofsearchparams2
> SEARCHFS_MAX_SEARCHPARMS
)
4763 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
4764 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
4765 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
4768 mallocsize
= searchblock
.sizeofsearchparams1
+ searchblock
.sizeofsearchparams2
+
4769 sizeof(struct attrlist
) + sizeof(struct searchstate
);
4771 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
4773 /* Now set up the various pointers to the correct place in our newly allocated memory */
4775 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
4776 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
4777 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
4779 /* Now copy in the stuff given our local variables. */
4781 if ((error
= copyin(searchblock
.searchparams1
, searchparams1
, searchblock
.sizeofsearchparams1
)))
4784 if ((error
= copyin(searchblock
.searchparams2
, searchparams2
, searchblock
.sizeofsearchparams2
)))
4787 if ((error
= copyin(searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
))))
4790 if ((error
= copyin(uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
))))
4793 /* set up the uio structure which will contain the users return buffer */
4795 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
4796 &uio_buf
[0], sizeof(uio_buf
));
4797 uio_addiov(auio
, searchblock
.returnbuffer
, searchblock
.returnbuffersize
);
4800 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4801 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4802 UIO_USERSPACE
, uap
->path
, &context
);
4813 * If searchblock.maxmatches == 0, then skip the search. This has happened
4814 * before and sometimes the underlyning code doesnt deal with it well.
4816 if (searchblock
.maxmatches
== 0) {
4822 Allright, we have everything we need, so lets make that call.
4824 We keep special track of the return value from the file system:
4825 EAGAIN is an acceptable error condition that shouldn't keep us
4826 from copying out any results...
4829 fserror
= VNOP_SEARCHFS(vp
,
4832 &searchblock
.searchattrs
,
4833 searchblock
.maxmatches
,
4834 &searchblock
.timelimit
,
4847 /* Now copy out the stuff that needs copying out. That means the number of matches, the
4848 search state. Everything was already put into he return buffer by the vop call. */
4850 if ((error
= copyout((caddr_t
) state
, uap
->state
, sizeof(struct searchstate
))) != 0)
4853 if ((error
= suulong(uap
->nummatches
, (uint64_t)nummatches
)) != 0)
4860 FREE(searchparams1
,M_TEMP
);
4865 } /* end of searchfs system call */
4869 * Make a filesystem-specific control call:
4873 fsctl (struct proc
*p
, struct fsctl_args
*uap
, __unused register_t
*retval
)
4877 struct nameidata nd
;
4879 u_long cmd
= uap
->cmd
;
4880 register u_int size
;
4881 #define STK_PARAMS 128
4882 char stkbuf
[STK_PARAMS
];
4884 struct vfs_context context
;
4886 context
.vc_proc
= p
;
4887 context
.vc_ucred
= kauth_cred_get();
4889 size
= IOCPARM_LEN(cmd
);
4890 if (size
> IOCPARM_MAX
) return (EINVAL
);
4892 is64bit
= proc_is64bit(p
);
4895 if (size
> sizeof (stkbuf
)) {
4896 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
4904 error
= copyin(uap
->data
, data
, size
);
4905 if (error
) goto FSCtl_Exit
;
4908 *(user_addr_t
*)data
= uap
->data
;
4911 *(uint32_t *)data
= (uint32_t)uap
->data
;
4914 } else if ((cmd
& IOC_OUT
) && size
) {
4916 * Zero the buffer so the user always
4917 * gets back something deterministic.
4920 } else if (cmd
& IOC_VOID
) {
4922 *(user_addr_t
*)data
= uap
->data
;
4925 *(uint32_t *)data
= (uint32_t)uap
->data
;
4929 /* Get the vnode for the file we are getting info on: */
4931 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4932 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, uap
->path
, &context
);
4933 if ((error
= namei(&nd
))) goto FSCtl_Exit
;
4935 /* Invoke the filesystem-specific code */
4936 error
= VNOP_IOCTL(nd
.ni_vp
, IOCBASECMD(cmd
), data
, uap
->options
, &context
);
4938 vnode_put(nd
.ni_vp
);
4942 * Copy any data to user, size was
4943 * already set and checked above.
4945 if (error
== 0 && (cmd
& IOC_OUT
) && size
)
4946 error
= copyout(data
, uap
->data
, size
);
4949 if (memp
) kfree(memp
, size
);
4953 /* end of fsctl system call */
4956 * An in-kernel sync for power management to call.
4958 __private_extern__
int
4963 struct sync_args data
;
4968 error
= sync(current_proc(), &data
, &retval
[0]);
4972 } /* end of sync_internal call */
4976 * Retrieve the data of an extended attribute.
4979 getxattr(struct proc
*p
, struct getxattr_args
*uap
, user_ssize_t
*retval
)
4982 struct nameidata nd
;
4983 char attrname
[XATTR_MAXNAMELEN
+1];
4984 struct vfs_context context
;
4986 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4987 size_t attrsize
= 0;
4991 char uio_buf
[ UIO_SIZEOF(1) ];
4993 context
.vc_proc
= p
;
4994 context
.vc_ucred
= kauth_cred_get();
4996 if (uap
->options
& XATTR_NOSECURITY
)
4999 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5000 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5001 if ((error
= namei(&nd
))) {
5007 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5010 if (xattr_protected(attrname
)) {
5014 if (uap
->value
&& uap
->size
> 0) {
5015 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
5016 &uio_buf
[0], sizeof(uio_buf
));
5017 uio_addiov(auio
, uap
->value
, uap
->size
);
5020 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, &context
);
5025 *retval
= uap
->size
- uio_resid(auio
);
5027 *retval
= (user_ssize_t
)attrsize
;
5034 * Retrieve the data of an extended attribute.
5037 fgetxattr(struct proc
*p
, struct fgetxattr_args
*uap
, user_ssize_t
*retval
)
5040 char attrname
[XATTR_MAXNAMELEN
+1];
5041 struct vfs_context context
;
5043 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5044 size_t attrsize
= 0;
5047 char uio_buf
[ UIO_SIZEOF(1) ];
5049 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5052 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5055 if ( (error
= vnode_getwithref(vp
)) ) {
5059 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5062 if (xattr_protected(attrname
)) {
5066 if (uap
->value
&& uap
->size
> 0) {
5067 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
5068 &uio_buf
[0], sizeof(uio_buf
));
5069 uio_addiov(auio
, uap
->value
, uap
->size
);
5071 context
.vc_proc
= p
;
5072 context
.vc_ucred
= kauth_cred_get();
5074 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, &context
);
5076 (void)vnode_put(vp
);
5080 *retval
= uap
->size
- uio_resid(auio
);
5082 *retval
= (user_ssize_t
)attrsize
;
5088 * Set the data of an extended attribute.
5091 setxattr(struct proc
*p
, struct setxattr_args
*uap
, int *retval
)
5094 struct nameidata nd
;
5095 char attrname
[XATTR_MAXNAMELEN
+1];
5096 struct vfs_context context
;
5098 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5102 char uio_buf
[ UIO_SIZEOF(1) ];
5104 context
.vc_proc
= p
;
5105 context
.vc_ucred
= kauth_cred_get();
5107 if (uap
->options
& XATTR_NOSECURITY
)
5110 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5113 if (xattr_protected(attrname
))
5115 if (uap
->value
== 0 || uap
->size
== 0) {
5119 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5120 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5121 if ((error
= namei(&nd
))) {
5127 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
5128 &uio_buf
[0], sizeof(uio_buf
));
5129 uio_addiov(auio
, uap
->value
, uap
->size
);
5131 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, &context
);
5138 * Set the data of an extended attribute.
5141 fsetxattr(struct proc
*p
, struct fsetxattr_args
*uap
, int *retval
)
5144 char attrname
[XATTR_MAXNAMELEN
+1];
5145 struct vfs_context context
;
5147 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5150 char uio_buf
[ UIO_SIZEOF(1) ];
5152 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5155 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5158 if (xattr_protected(attrname
))
5160 if (uap
->value
== 0 || uap
->size
== 0) {
5163 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5166 if ( (error
= vnode_getwithref(vp
)) ) {
5170 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
5171 &uio_buf
[0], sizeof(uio_buf
));
5172 uio_addiov(auio
, uap
->value
, uap
->size
);
5173 context
.vc_proc
= p
;
5174 context
.vc_ucred
= kauth_cred_get();
5176 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, &context
);
5184 * Remove an extended attribute.
5186 #warning "code duplication"
5188 removexattr(struct proc
*p
, struct removexattr_args
*uap
, int *retval
)
5191 struct nameidata nd
;
5192 char attrname
[XATTR_MAXNAMELEN
+1];
5193 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5194 struct vfs_context context
;
5199 context
.vc_proc
= p
;
5200 context
.vc_ucred
= kauth_cred_get();
5202 if (uap
->options
& XATTR_NOSECURITY
)
5205 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
5209 if (xattr_protected(attrname
))
5211 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5212 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5213 if ((error
= namei(&nd
))) {
5219 error
= vn_removexattr(vp
, attrname
, uap
->options
, &context
);
5226 * Remove an extended attribute.
5228 #warning "code duplication"
5230 fremovexattr(struct proc
*p
, struct fremovexattr_args
*uap
, int *retval
)
5233 char attrname
[XATTR_MAXNAMELEN
+1];
5234 struct vfs_context context
;
5238 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5241 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
5245 if (xattr_protected(attrname
))
5247 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5250 if ( (error
= vnode_getwithref(vp
)) ) {
5254 context
.vc_proc
= p
;
5255 context
.vc_ucred
= kauth_cred_get();
5257 error
= vn_removexattr(vp
, attrname
, uap
->options
, &context
);
5265 * Retrieve the list of extended attribute names.
5267 #warning "code duplication"
5269 listxattr(struct proc
*p
, struct listxattr_args
*uap
, user_ssize_t
*retval
)
5272 struct nameidata nd
;
5273 struct vfs_context context
;
5275 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5276 size_t attrsize
= 0;
5279 char uio_buf
[ UIO_SIZEOF(1) ];
5281 context
.vc_proc
= p
;
5282 context
.vc_ucred
= kauth_cred_get();
5284 if (uap
->options
& XATTR_NOSECURITY
)
5287 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5288 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5289 if ((error
= namei(&nd
))) {
5294 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
5295 // LP64todo - fix this!
5296 auio
= uio_createwithbuffer(1, 0, spacetype
,
5297 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
5298 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
5301 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, &context
);
5305 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
5307 *retval
= (user_ssize_t
)attrsize
;
5313 * Retrieve the list of extended attribute names.
5315 #warning "code duplication"
5317 flistxattr(struct proc
*p
, struct flistxattr_args
*uap
, user_ssize_t
*retval
)
5320 struct vfs_context context
;
5322 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5323 size_t attrsize
= 0;
5325 char uio_buf
[ UIO_SIZEOF(1) ];
5327 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5330 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5333 if ( (error
= vnode_getwithref(vp
)) ) {
5337 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
5338 // LP64todo - fix this!
5339 auio
= uio_createwithbuffer(1, 0, spacetype
,
5340 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
5341 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
5343 context
.vc_proc
= p
;
5344 context
.vc_ucred
= kauth_cred_get();
5346 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, &context
);
5351 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
5353 *retval
= (user_ssize_t
)attrsize
;
5359 * Common routine to handle various flavors of statfs data heading out
5363 munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
5364 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
5365 boolean_t partial_copy
)
5368 int my_size
, copy_size
;
5371 struct user_statfs sfs
;
5372 my_size
= copy_size
= sizeof(sfs
);
5373 bzero(&sfs
, my_size
);
5374 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
5375 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
5376 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
5377 sfs
.f_bsize
= (user_long_t
)sfsp
->f_bsize
;
5378 sfs
.f_iosize
= (user_long_t
)sfsp
->f_iosize
;
5379 sfs
.f_blocks
= (user_long_t
)sfsp
->f_blocks
;
5380 sfs
.f_bfree
= (user_long_t
)sfsp
->f_bfree
;
5381 sfs
.f_bavail
= (user_long_t
)sfsp
->f_bavail
;
5382 sfs
.f_files
= (user_long_t
)sfsp
->f_files
;
5383 sfs
.f_ffree
= (user_long_t
)sfsp
->f_ffree
;
5384 sfs
.f_fsid
= sfsp
->f_fsid
;
5385 sfs
.f_owner
= sfsp
->f_owner
;
5386 strncpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
-1);
5387 strncpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
-1);
5388 strncpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
-1);
5391 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
5393 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
5397 my_size
= copy_size
= sizeof(sfs
);
5398 bzero(&sfs
, my_size
);
5400 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
5401 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
5402 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
5405 * It's possible for there to be more than 2^^31 blocks in the filesystem, so we
5406 * have to fudge the numbers here in that case. We inflate the blocksize in order
5407 * to reflect the filesystem size as best we can.
5409 if ((sfsp
->f_blocks
> LONG_MAX
)
5410 /* Hack for 4061702 . I think the real fix is for Carbon to
5411 * look for some volume capability and not depend on hidden
5412 * semantics agreed between a FS and carbon.
5413 * f_blocks, f_bfree, and f_bavail set to -1 is the trigger
5414 * for Carbon to set bNoVolumeSizes volume attribute.
5415 * Without this the webdavfs files cannot be copied onto
5416 * disk as they look huge. This change should not affect
5417 * XSAN as they should not setting these to -1..
5419 && (sfsp
->f_blocks
!= 0xffffffffffffffff)
5420 && (sfsp
->f_bfree
!= 0xffffffffffffffff)
5421 && (sfsp
->f_bavail
!= 0xffffffffffffffff)) {
5425 * Work out how far we have to shift the block count down to make it fit.
5426 * Note that it's possible to have to shift so far that the resulting
5427 * blocksize would be unreportably large. At that point, we will clip
5428 * any values that don't fit.
5430 * For safety's sake, we also ensure that f_iosize is never reported as
5431 * being smaller than f_bsize.
5433 for (shift
= 0; shift
< 32; shift
++) {
5434 if ((sfsp
->f_blocks
>> shift
) <= LONG_MAX
)
5436 if ((sfsp
->f_bsize
<< (shift
+ 1)) > LONG_MAX
)
5439 #define __SHIFT_OR_CLIP(x, s) ((((x) >> (s)) > LONG_MAX) ? LONG_MAX : ((x) >> (s)))
5440 sfs
.f_blocks
= (long)__SHIFT_OR_CLIP(sfsp
->f_blocks
, shift
);
5441 sfs
.f_bfree
= (long)__SHIFT_OR_CLIP(sfsp
->f_bfree
, shift
);
5442 sfs
.f_bavail
= (long)__SHIFT_OR_CLIP(sfsp
->f_bavail
, shift
);
5443 #undef __SHIFT_OR_CLIP
5444 sfs
.f_bsize
= (long)(sfsp
->f_bsize
<< shift
);
5445 sfs
.f_iosize
= lmax(sfsp
->f_iosize
, sfsp
->f_bsize
);
5447 /* filesystem is small enough to be reported honestly */
5448 sfs
.f_bsize
= (long)sfsp
->f_bsize
;
5449 sfs
.f_iosize
= (long)sfsp
->f_iosize
;
5450 sfs
.f_blocks
= (long)sfsp
->f_blocks
;
5451 sfs
.f_bfree
= (long)sfsp
->f_bfree
;
5452 sfs
.f_bavail
= (long)sfsp
->f_bavail
;
5454 sfs
.f_files
= (long)sfsp
->f_files
;
5455 sfs
.f_ffree
= (long)sfsp
->f_ffree
;
5456 sfs
.f_fsid
= sfsp
->f_fsid
;
5457 sfs
.f_owner
= sfsp
->f_owner
;
5458 strncpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
-1);
5459 strncpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
-1);
5460 strncpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
-1);
5463 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
5465 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
5468 if (sizep
!= NULL
) {
5475 * copy stat structure into user_stat structure.
5477 void munge_stat(struct stat
*sbp
, struct user_stat
*usbp
)
5479 usbp
->st_dev
= sbp
->st_dev
;
5480 usbp
->st_ino
= sbp
->st_ino
;
5481 usbp
->st_mode
= sbp
->st_mode
;
5482 usbp
->st_nlink
= sbp
->st_nlink
;
5483 usbp
->st_uid
= sbp
->st_uid
;
5484 usbp
->st_gid
= sbp
->st_gid
;
5485 usbp
->st_rdev
= sbp
->st_rdev
;
5486 #ifndef _POSIX_SOURCE
5487 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
5488 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
5489 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
5490 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
5491 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
5492 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
5494 usbp
->st_atime
= sbp
->st_atime
;
5495 usbp
->st_atimensec
= sbp
->st_atimensec
;
5496 usbp
->st_mtime
= sbp
->st_mtime
;
5497 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
5498 usbp
->st_ctime
= sbp
->st_ctime
;
5499 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
5501 usbp
->st_size
= sbp
->st_size
;
5502 usbp
->st_blocks
= sbp
->st_blocks
;
5503 usbp
->st_blksize
= sbp
->st_blksize
;
5504 usbp
->st_flags
= sbp
->st_flags
;
5505 usbp
->st_gen
= sbp
->st_gen
;
5506 usbp
->st_lspare
= sbp
->st_lspare
;
5507 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
5508 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];