2 * Copyright (c) 1995-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * Copyright (c) 1989, 1993
30 * The Regents of the University of California. All rights reserved.
31 * (c) UNIX System Laboratories, Inc.
32 * All or some portions of this file are derived from material licensed
33 * to the University of California by American Telephone and Telegraph
34 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
35 * the permission of UNIX System Laboratories, Inc.
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by the University of
48 * California, Berkeley and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 * @(#)vfs_syscalls.c 8.41 (Berkeley) 6/15/95
68 #include <sys/param.h>
69 #include <sys/systm.h>
70 #include <sys/namei.h>
71 #include <sys/filedesc.h>
72 #include <sys/kernel.h>
73 #include <sys/file_internal.h>
75 #include <sys/vnode_internal.h>
76 #include <sys/mount_internal.h>
77 #include <sys/proc_internal.h>
78 #include <sys/kauth.h>
79 #include <sys/uio_internal.h>
80 #include <sys/malloc.h>
82 #include <sys/dirent.h>
84 #include <sys/sysctl.h>
86 #include <sys/quota.h>
87 #include <sys/kdebug.h>
88 #include <sys/fsevents.h>
89 #include <sys/sysproto.h>
90 #include <sys/xattr.h>
91 #include <sys/ubc_internal.h>
92 #include <machine/cons.h>
93 #include <machine/limits.h>
94 #include <miscfs/specfs/specdev.h>
96 #include <bsm/audit_kernel.h>
97 #include <bsm/audit_kevents.h>
99 #include <mach/mach_types.h>
100 #include <kern/kern_types.h>
101 #include <kern/kalloc.h>
103 #include <vm/vm_pageout.h>
105 #include <architecture/byte_order.h>
106 #include <libkern/OSAtomic.h>
110 * The currently logged-in user, for ownership of files/directories whose on-disk
111 * permissions are ignored:
115 static int change_dir(struct nameidata
*ndp
, vfs_context_t ctx
);
116 static void checkdirs(struct vnode
*olddp
, vfs_context_t ctx
);
117 void enablequotas(struct mount
*mp
, vfs_context_t ctx
);
118 static int getfsstat_callback(mount_t mp
, void * arg
);
119 static int getutimes(user_addr_t usrtvp
, struct timespec
*tsp
);
120 static int setutimes(vfs_context_t ctx
, struct vnode
*vp
, const struct timespec
*ts
, int nullflag
);
121 static int sync_callback(mount_t
, void *);
122 static int munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
123 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
124 boolean_t partial_copy
);
126 __private_extern__
int sync_internal(void);
128 #ifdef __APPLE_API_OBSOLETE
130 int fd
; /* file descriptor of the target file */
131 struct vstat
*vsb
; /* vstat structure for returned info */
134 const char *path
; /* pathname of the target file */
135 struct vstat
*vsb
; /* vstat structure for returned info */
137 struct mkcomplex_args
{
138 const char *path
; /* pathname of the file to be created */
139 mode_t mode
; /* access mode for the newly created file */
140 u_long type
; /* format of the complex file */
143 const char *path
; /* pathname of the target file */
144 struct vstat
*vsb
; /* vstat structure for returned info */
147 int fstatv(struct proc
*p
, struct fstatv_args
*uap
, register_t
*retval
);
148 int lstatv(struct proc
*p
, struct lstatv_args
*uap
, register_t
*retval
);
149 int mkcomplex(struct proc
*p
, struct mkcomplex_args
*uap
, register_t
*retval
);
150 int statv(struct proc
*p
, struct statv_args
*uap
, register_t
*retval
);
152 #endif /* __APPLE_API_OBSOLETE */
155 extern int (**union_vnodeop_p
)(void *);
156 extern struct vnode
*union_dircache(struct vnode
*, struct proc
*);
159 /* counts number of mount and unmount operations */
160 unsigned int vfs_nummntops
=0;
162 extern struct fileops vnops
;
164 extern void mount_list_add(mount_t mp
);
165 extern void mount_list_remove(mount_t mp
);
166 extern int mount_refdrain(mount_t mp
);
167 extern int vcount(struct vnode
*vp
);
171 * Virtual File System System Calls
175 * Mount a file system.
179 mount(struct proc
*p
, register struct mount_args
*uap
, __unused register_t
*retval
)
182 struct vnode
*devvp
= NULLVP
;
183 struct vnode
*device_vnode
= NULLVP
;
185 struct vfstable
*vfsp
;
187 struct vnode_attr va
;
188 struct vfs_context context
;
190 struct nameidata nd1
;
191 char fstypename
[MFSNAMELEN
];
193 user_addr_t devpath
= USER_ADDR_NULL
;
194 user_addr_t fsmountargs
= uap
->data
;
199 boolean_t is_rwlock_locked
= FALSE
;
201 AUDIT_ARG(fflags
, uap
->flags
);
204 context
.vc_ucred
= kauth_cred_get();
205 is_64bit
= proc_is64bit(p
);
208 * Get vnode to be covered
210 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
211 UIO_USERSPACE
, uap
->path
, &context
);
217 if ((vp
->v_flag
& VROOT
) &&
218 (vp
->v_mount
->mnt_flag
& MNT_ROOTFS
))
219 uap
->flags
|= MNT_UPDATE
;
221 if (uap
->flags
& MNT_UPDATE
) {
222 if ((vp
->v_flag
& VROOT
) == 0) {
228 /* unmount in progress return error */
230 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
236 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
237 is_rwlock_locked
= TRUE
;
239 * We only allow the filesystem to be reloaded if it
240 * is currently mounted read-only.
242 if ((uap
->flags
& MNT_RELOAD
) &&
243 ((mp
->mnt_flag
& MNT_RDONLY
) == 0)) {
248 * Only root, or the user that did the original mount is
249 * permitted to update it.
251 if (mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(context
.vc_ucred
) &&
252 (error
= suser(context
.vc_ucred
, &p
->p_acflag
))) {
256 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV,
257 * and MNT_NOEXEC if mount point is already MNT_NOEXEC.
259 if (suser(context
.vc_ucred
, NULL
)) {
260 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
261 if (mp
->mnt_flag
& MNT_NOEXEC
)
262 uap
->flags
|= MNT_NOEXEC
;
267 uap
->flags
& (MNT_RELOAD
| MNT_FORCE
| MNT_UPDATE
);
269 vfsp
= mp
->mnt_vtable
;
273 * If the user is not root, ensure that they own the directory
274 * onto which we are attempting to mount.
277 VATTR_WANTED(&va
, va_uid
);
278 if ((error
= vnode_getattr(vp
, &va
, &context
)) ||
279 (va
.va_uid
!= kauth_cred_getuid(context
.vc_ucred
) &&
280 (error
= suser(context
.vc_ucred
, &p
->p_acflag
)))) {
284 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV, and
285 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
287 if (suser(context
.vc_ucred
, NULL
)) {
288 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
289 if (vp
->v_mount
->mnt_flag
& MNT_NOEXEC
)
290 uap
->flags
|= MNT_NOEXEC
;
292 if ( (error
= VNOP_FSYNC(vp
, MNT_WAIT
, &context
)) )
295 if ( (error
= buf_invalidateblks(vp
, BUF_WRITE_DATA
, 0, 0)) )
298 if (vp
->v_type
!= VDIR
) {
302 if ( (error
= copyinstr(uap
->type
, fstypename
, MFSNAMELEN
, &dummy
)) )
305 /* XXXAUDIT: Should we capture the type on the error path as well? */
306 AUDIT_ARG(text
, fstypename
);
308 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
309 if (!strcmp(vfsp
->vfc_name
, fstypename
))
316 if (ISSET(vp
->v_flag
, VMOUNT
) && (vp
->v_mountedhere
!= NULL
)) {
320 SET(vp
->v_flag
, VMOUNT
);
323 * Allocate and initialize the filesystem.
325 MALLOC_ZONE(mp
, struct mount
*, (u_long
)sizeof(struct mount
),
327 bzero((char *)mp
, (u_long
)sizeof(struct mount
));
330 /* Initialize the default IO constraints */
331 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
332 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
333 mp
->mnt_maxsegreadsize
= mp
->mnt_maxreadcnt
;
334 mp
->mnt_maxsegwritesize
= mp
->mnt_maxwritecnt
;
335 mp
->mnt_devblocksize
= DEV_BSIZE
;
337 TAILQ_INIT(&mp
->mnt_vnodelist
);
338 TAILQ_INIT(&mp
->mnt_workerqueue
);
339 TAILQ_INIT(&mp
->mnt_newvnodes
);
341 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
342 is_rwlock_locked
= TRUE
;
343 mp
->mnt_op
= vfsp
->vfc_vfsops
;
344 mp
->mnt_vtable
= vfsp
;
346 vfsp
->vfc_refcount
++;
348 //mp->mnt_stat.f_type = vfsp->vfc_typenum;
349 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
350 strncpy(mp
->mnt_vfsstat
.f_fstypename
, vfsp
->vfc_name
, MFSTYPENAMELEN
);
351 strncpy(mp
->mnt_vfsstat
.f_mntonname
, nd
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
352 mp
->mnt_vnodecovered
= vp
;
353 mp
->mnt_vfsstat
.f_owner
= kauth_cred_getuid(context
.vc_ucred
);
355 /* XXX 3762912 hack to support HFS filesystem 'owner' - filesystem may update later */
356 vfs_setowner(mp
, KAUTH_UID_NONE
, KAUTH_GID_NONE
);
360 * Set the mount level flags.
362 if (uap
->flags
& MNT_RDONLY
)
363 mp
->mnt_flag
|= MNT_RDONLY
;
364 else if (mp
->mnt_flag
& MNT_RDONLY
)
365 mp
->mnt_kern_flag
|= MNTK_WANTRDWR
;
366 mp
->mnt_flag
&= ~(MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
367 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
368 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
);
369 mp
->mnt_flag
|= uap
->flags
& (MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
370 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
371 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
|
374 if (vfsp
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
376 if ( (error
= copyin(fsmountargs
, (caddr_t
)&devpath
, sizeof(devpath
))) )
378 fsmountargs
+= sizeof(devpath
);
381 if ( (error
= copyin(fsmountargs
, (caddr_t
)&tmp
, sizeof(tmp
))) )
383 /* munge into LP64 addr */
384 devpath
= CAST_USER_ADDR_T(tmp
);
385 fsmountargs
+= sizeof(tmp
);
388 /* if it is not update and device name needs to be parsed */
390 NDINIT(&nd1
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, devpath
, &context
);
391 if ( (error
= namei(&nd1
)) )
394 strncpy(mp
->mnt_vfsstat
.f_mntfromname
, nd1
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
399 if (devvp
->v_type
!= VBLK
) {
403 if (major(devvp
->v_rdev
) >= nblkdev
) {
408 * If mount by non-root, then verify that user has necessary
409 * permissions on the device.
411 if (suser(context
.vc_ucred
, NULL
) != 0) {
412 accessmode
= KAUTH_VNODE_READ_DATA
;
413 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
414 accessmode
|= KAUTH_VNODE_WRITE_DATA
;
415 if ((error
= vnode_authorize(devvp
, NULL
, accessmode
, &context
)) != 0)
419 if (devpath
&& ((uap
->flags
& MNT_UPDATE
) == 0)) {
420 if ( (error
= vnode_ref(devvp
)) )
423 * Disallow multiple mounts of the same device.
424 * Disallow mounting of a device that is currently in use
425 * (except for root, which might share swap device for miniroot).
426 * Flush out any old buffers remaining from a previous use.
428 if ( (error
= vfs_mountedon(devvp
)) )
431 if (vcount(devvp
) > 1 && !(vfs_flags(mp
) & MNT_ROOTFS
)) {
435 if ( (error
= VNOP_FSYNC(devvp
, MNT_WAIT
, &context
)) ) {
439 if ( (error
= buf_invalidateblks(devvp
, BUF_WRITE_DATA
, 0, 0)) )
442 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
443 if ( (error
= VNOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, &context
)) )
446 mp
->mnt_devvp
= devvp
;
447 device_vnode
= devvp
;
449 if ((mp
->mnt_flag
& MNT_RDONLY
) && (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)) {
451 * If upgrade to read-write by non-root, then verify
452 * that user has necessary permissions on the device.
454 device_vnode
= mp
->mnt_devvp
;
455 if (device_vnode
&& suser(context
.vc_ucred
, NULL
)) {
456 if ((error
= vnode_authorize(device_vnode
, NULL
,
457 KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0)
461 device_vnode
= NULLVP
;
467 * Mount the filesystem.
469 error
= VFS_MOUNT(mp
, device_vnode
, fsmountargs
, &context
);
471 if (uap
->flags
& MNT_UPDATE
) {
472 if (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)
473 mp
->mnt_flag
&= ~MNT_RDONLY
;
475 (MNT_UPDATE
| MNT_RELOAD
| MNT_FORCE
);
476 mp
->mnt_kern_flag
&=~ MNTK_WANTRDWR
;
479 vfs_event_signal(NULL
, VQ_UPDATE
, (intptr_t)NULL
);
480 lck_rw_done(&mp
->mnt_rwlock
);
481 is_rwlock_locked
= FALSE
;
483 enablequotas(mp
,&context
);
487 * Put the new filesystem on the mount list after root.
490 CLR(vp
->v_flag
, VMOUNT
);
493 vp
->v_mountedhere
= mp
;
498 vfs_event_signal(NULL
, VQ_MOUNT
, (intptr_t)NULL
);
499 checkdirs(vp
, &context
);
500 lck_rw_done(&mp
->mnt_rwlock
);
501 is_rwlock_locked
= FALSE
;
504 * there is no cleanup code here so I have made it void
505 * we need to revisit this
507 (void)VFS_START(mp
, 0, &context
);
509 /* increment the operations count */
510 OSAddAtomic(1, (SInt32
*)&vfs_nummntops
);
511 enablequotas(mp
,&context
);
514 device_vnode
->v_specflags
|= SI_MOUNTEDON
;
517 * cache the IO attributes for the underlying physical media...
518 * an error return indicates the underlying driver doesn't
519 * support all the queries necessary... however, reasonable
520 * defaults will have been set, so no reason to bail or care
522 vfs_init_io_attributes(device_vnode
, mp
);
525 CLR(vp
->v_flag
, VMOUNT
);
527 mp
->mnt_vtable
->vfc_refcount
--;
531 VNOP_CLOSE(device_vnode
, ronly
? FREAD
: FREAD
|FWRITE
, &context
);
532 vnode_rele(device_vnode
);
534 lck_rw_done(&mp
->mnt_rwlock
);
535 is_rwlock_locked
= FALSE
;
536 mount_lock_destroy(mp
);
537 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
542 * drop I/O count on covered 'vp' and
543 * on the device vp if there was one
545 if (devpath
&& devvp
)
554 if (devpath
&& devvp
)
557 /* Release mnt_rwlock only when it was taken */
558 if (is_rwlock_locked
== TRUE
) {
559 lck_rw_done(&mp
->mnt_rwlock
);
562 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
571 enablequotas(struct mount
*mp
, vfs_context_t context
)
573 struct nameidata qnd
;
575 char qfpath
[MAXPATHLEN
];
576 const char *qfname
= QUOTAFILENAME
;
577 const char *qfopsname
= QUOTAOPSNAME
;
578 const char *qfextension
[] = INITQFNAMES
;
580 if ((strcmp(mp
->mnt_vfsstat
.f_fstypename
, "hfs") != 0 )
581 && (strcmp( mp
->mnt_vfsstat
.f_fstypename
, "ufs") != 0))
585 * Enable filesystem disk quotas if necessary.
586 * We ignore errors as this should not interfere with final mount
588 for (type
=0; type
< MAXQUOTAS
; type
++) {
589 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfopsname
, qfextension
[type
]);
590 NDINIT(&qnd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE32
, CAST_USER_ADDR_T(qfpath
), context
);
591 if (namei(&qnd
) != 0)
592 continue; /* option file to trigger quotas is not present */
593 vnode_put(qnd
.ni_vp
);
595 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfname
, qfextension
[type
]);
597 (void) VFS_QUOTACTL(mp
, QCMD(Q_QUOTAON
, type
), 0, qfpath
, context
);
603 * Scan all active processes to see if any of them have a current
604 * or root directory onto which the new filesystem has just been
605 * mounted. If so, replace them with the new mount point.
608 checkdirs(olddp
, context
)
610 vfs_context_t context
;
612 struct filedesc
*fdp
;
616 struct vnode
*fdp_cvp
;
617 struct vnode
*fdp_rvp
;
618 int cdir_changed
= 0;
619 int rdir_changed
= 0;
620 boolean_t funnel_state
;
622 if (olddp
->v_usecount
== 1)
624 if (VFS_ROOT(olddp
->v_mountedhere
, &newdp
, context
))
625 panic("mount: lost mount");
626 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
628 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
631 if (fdp
== (struct filedesc
*)0) {
635 fdp_cvp
= fdp
->fd_cdir
;
636 fdp_rvp
= fdp
->fd_rdir
;
639 if (fdp_cvp
== olddp
) {
646 if (fdp_rvp
== olddp
) {
653 if (cdir_changed
|| rdir_changed
) {
655 fdp
->fd_cdir
= fdp_cvp
;
656 fdp
->fd_rdir
= fdp_rvp
;
660 if (rootvnode
== olddp
) {
666 thread_funnel_set(kernel_flock
, funnel_state
);
672 * Unmount a file system.
674 * Note: unmount takes a path to the vnode mounted on as argument,
675 * not special file (as before).
679 unmount(struct proc
*p
, register struct unmount_args
*uap
, __unused register_t
*retval
)
681 register struct vnode
*vp
;
685 struct vfs_context context
;
688 context
.vc_ucred
= kauth_cred_get();
690 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
691 UIO_USERSPACE
, uap
->path
, &context
);
700 * Must be the root of the filesystem
702 if ((vp
->v_flag
& VROOT
) == 0) {
707 return (safedounmount(mp
, uap
->flags
, p
));
711 * Do the actual file system unmount, prevent some common foot shooting.
713 * XXX Should take a "vfs_context_t" instead of a "struct proc *"
716 safedounmount(mp
, flags
, p
)
724 * Only root, or the user that did the original mount is
725 * permitted to unmount this filesystem.
727 if ((mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(kauth_cred_get())) &&
728 (error
= suser(kauth_cred_get(), &p
->p_acflag
)))
732 * Don't allow unmounting the root file system.
734 if (mp
->mnt_flag
& MNT_ROOTFS
)
735 return (EBUSY
); /* the root is always busy */
737 return (dounmount(mp
, flags
, p
));
741 * Do the actual file system unmount.
744 dounmount(mp
, flags
, p
)
745 register struct mount
*mp
;
749 struct vnode
*coveredvp
= (vnode_t
)0;
752 struct vfs_context context
;
753 int forcedunmount
= 0;
757 context
.vc_ucred
= kauth_cred_get();
759 if (flags
& MNT_FORCE
)
762 /* XXX post jaguar fix LK_DRAIN - then clean this up */
763 if ((flags
& MNT_FORCE
)) {
764 mp
->mnt_kern_flag
|= MNTK_FRCUNMOUNT
;
765 mp
->mnt_lflag
|= MNT_LFORCE
;
767 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
768 mp
->mnt_lflag
|= MNT_LWAIT
;
769 msleep((caddr_t
)mp
, &mp
->mnt_mlock
, (PVFS
| PDROP
), "dounmount", 0 );
771 * The prior unmount attempt has probably succeeded.
772 * Do not dereference mp here - returning EBUSY is safest.
776 mp
->mnt_kern_flag
|= MNTK_UNMOUNT
;
777 mp
->mnt_lflag
|= MNT_LUNMOUNT
;
778 mp
->mnt_flag
&=~ MNT_ASYNC
;
780 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
781 fsevent_unmount(mp
); /* has to come first! */
783 if (forcedunmount
== 0) {
784 ubc_umount(mp
); /* release cached vnodes */
785 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
786 error
= VFS_SYNC(mp
, MNT_WAIT
, &context
);
789 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
790 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
791 mp
->mnt_lflag
&= ~MNT_LFORCE
;
798 lflags
|= FORCECLOSE
;
799 error
= vflush(mp
, NULLVP
, SKIPSWAP
| SKIPSYSTEM
| SKIPROOT
| lflags
);
800 if ((forcedunmount
== 0) && error
) {
802 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
803 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
804 mp
->mnt_lflag
&= ~MNT_LFORCE
;
808 /* make sure there are no one in the mount iterations or lookup */
811 error
= VFS_UNMOUNT(mp
, flags
, &context
);
815 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
816 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
817 mp
->mnt_lflag
&= ~MNT_LFORCE
;
821 /* increment the operations count */
823 OSAddAtomic(1, (SInt32
*)&vfs_nummntops
);
825 if ( mp
->mnt_devvp
&& mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
826 mp
->mnt_devvp
->v_specflags
&= ~SI_MOUNTEDON
;
827 VNOP_CLOSE(mp
->mnt_devvp
, mp
->mnt_flag
& MNT_RDONLY
? FREAD
: FREAD
|FWRITE
,
829 vnode_rele(mp
->mnt_devvp
);
831 lck_rw_done(&mp
->mnt_rwlock
);
832 mount_list_remove(mp
);
833 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
835 /* mark the mount point hook in the vp but not drop the ref yet */
836 if ((coveredvp
= mp
->mnt_vnodecovered
) != NULLVP
) {
837 vnode_getwithref(coveredvp
);
838 vnode_lock(coveredvp
);
839 coveredvp
->v_mountedhere
= (struct mount
*)0;
840 vnode_unlock(coveredvp
);
841 vnode_put(coveredvp
);
845 mp
->mnt_vtable
->vfc_refcount
--;
848 cache_purgevfs(mp
); /* remove cache entries for this file sys */
849 vfs_event_signal(NULL
, VQ_UNMOUNT
, (intptr_t)NULL
);
851 mp
->mnt_lflag
|= MNT_LDEAD
;
853 if (mp
->mnt_lflag
& MNT_LWAIT
) {
856 * in case we block in mount_refdrain
857 * which will drop the mount lock
858 * and allow anyone blocked in vfs_busy
859 * to wakeup and see the LDEAD state
861 mp
->mnt_lflag
&= ~MNT_LWAIT
;
866 if (mp
->mnt_lflag
& MNT_LWAIT
) {
867 mp
->mnt_lflag
&= ~MNT_LWAIT
;
871 lck_rw_done(&mp
->mnt_rwlock
);
876 if ((coveredvp
!= NULLVP
)) {
877 vnode_getwithref(coveredvp
);
878 vnode_rele(coveredvp
);
879 vnode_lock(coveredvp
);
880 if(mp
->mnt_crossref
== 0) {
881 vnode_unlock(coveredvp
);
882 mount_lock_destroy(mp
);
883 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
885 coveredvp
->v_lflag
|= VL_MOUNTDEAD
;
886 vnode_unlock(coveredvp
);
888 vnode_put(coveredvp
);
889 } else if (mp
->mnt_flag
& MNT_ROOTFS
) {
890 mount_lock_destroy(mp
);
891 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
893 panic("dounmount: no coveredvp");
899 mount_dropcrossref(mount_t mp
, vnode_t dp
, int need_put
)
903 if (mp
->mnt_crossref
< 0)
904 panic("mount cross refs -ve");
905 if (((dp
->v_lflag
& VL_MOUNTDEAD
) == VL_MOUNTDEAD
) && (mp
->mnt_crossref
== 0)) {
906 dp
->v_lflag
&= ~VL_MOUNTDEAD
;
908 vnode_put_locked(dp
);
910 mount_lock_destroy(mp
);
911 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
915 vnode_put_locked(dp
);
921 * Sync each mounted filesystem.
925 struct ctldebug debug0
= { "syncprt", &syncprt
};
928 int print_vmpage_stat
=0;
931 sync_callback(mount_t mp
, __unused
void * arg
)
933 struct proc
* p
= current_proc();
935 struct vfs_context context
;
938 context
.vc_ucred
= kauth_cred_get();
940 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
941 asyncflag
= mp
->mnt_flag
& MNT_ASYNC
;
942 mp
->mnt_flag
&= ~MNT_ASYNC
;
943 VFS_SYNC(mp
, MNT_NOWAIT
, &context
);
945 mp
->mnt_flag
|= MNT_ASYNC
;
947 return(VFS_RETURNED
);
951 extern unsigned int vp_pagein
, vp_pgodirty
, vp_pgoclean
;
952 extern unsigned int dp_pgins
, dp_pgouts
;
956 sync(__unused
struct proc
*p
, __unused
struct sync_args
*uap
, __unused register_t
*retval
)
959 vfs_iterate(LK_NOWAIT
, sync_callback
, (void *)0);
961 if(print_vmpage_stat
) {
962 vm_countdirtypages();
963 printf("VP: %d: %d: %d: %d: %d\n", vp_pgodirty
, vp_pgoclean
, vp_pagein
,
964 dp_pgins
, dp_pgouts
);
970 #endif /* DIAGNOSTIC */
975 * Change filesystem quotas.
979 quotactl(struct proc
*p
, register struct quotactl_args
*uap
, __unused register_t
*retval
)
981 register struct mount
*mp
;
982 int error
, quota_cmd
, quota_status
;
986 struct vfs_context context
;
987 struct dqblk my_dqblk
;
990 context
.vc_ucred
= kauth_cred_get();
992 AUDIT_ARG(uid
, uap
->uid
, 0, 0, 0);
993 AUDIT_ARG(cmd
, uap
->cmd
);
994 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
995 UIO_USERSPACE
, uap
->path
, &context
);
999 mp
= nd
.ni_vp
->v_mount
;
1000 vnode_put(nd
.ni_vp
);
1003 /* copyin any data we will need for downstream code */
1004 quota_cmd
= uap
->cmd
>> SUBCMDSHIFT
;
1006 switch (quota_cmd
) {
1008 /* uap->arg specifies a file from which to take the quotas */
1009 fnamelen
= MAXPATHLEN
;
1010 datap
= kalloc(MAXPATHLEN
);
1011 error
= copyinstr(uap
->arg
, datap
, MAXPATHLEN
, &fnamelen
);
1014 /* uap->arg is a pointer to a dqblk structure. */
1015 datap
= (caddr_t
) &my_dqblk
;
1019 /* uap->arg is a pointer to a dqblk structure. */
1020 datap
= (caddr_t
) &my_dqblk
;
1021 if (proc_is64bit(p
)) {
1022 struct user_dqblk my_dqblk64
;
1023 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk64
, sizeof (my_dqblk64
));
1025 munge_dqblk(&my_dqblk
, &my_dqblk64
, FALSE
);
1029 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk
, sizeof (my_dqblk
));
1033 /* uap->arg is a pointer to an integer */
1034 datap
= (caddr_t
) "a_status
;
1042 error
= VFS_QUOTACTL(mp
, uap
->cmd
, uap
->uid
, datap
, &context
);
1045 switch (quota_cmd
) {
1048 kfree(datap
, MAXPATHLEN
);
1051 /* uap->arg is a pointer to a dqblk structure we need to copy out to */
1053 if (proc_is64bit(p
)) {
1054 struct user_dqblk my_dqblk64
;
1055 munge_dqblk(&my_dqblk
, &my_dqblk64
, TRUE
);
1056 error
= copyout((caddr_t
)&my_dqblk64
, uap
->arg
, sizeof (my_dqblk64
));
1059 error
= copyout(datap
, uap
->arg
, sizeof (struct dqblk
));
1064 /* uap->arg is a pointer to an integer */
1066 error
= copyout(datap
, uap
->arg
, sizeof(quota_status
));
1077 * Get filesystem statistics.
1081 statfs(struct proc
*p
, register struct statfs_args
*uap
, __unused register_t
*retval
)
1084 struct vfsstatfs
*sp
;
1086 struct nameidata nd
;
1087 struct vfs_context context
;
1090 context
.vc_proc
= p
;
1091 context
.vc_ucred
= kauth_cred_get();
1093 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1094 UIO_USERSPACE
, uap
->path
, &context
);
1100 sp
= &mp
->mnt_vfsstat
;
1103 error
= vfs_update_vfsstat(mp
, &context
);
1108 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1113 * Get filesystem statistics.
1117 fstatfs(struct proc
*p
, register struct fstatfs_args
*uap
, __unused register_t
*retval
)
1121 struct vfsstatfs
*sp
;
1123 struct vfs_context context
;
1125 context
.vc_proc
= p
;
1126 context
.vc_ucred
= kauth_cred_get();
1128 AUDIT_ARG(fd
, uap
->fd
);
1130 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1133 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
1140 sp
= &mp
->mnt_vfsstat
;
1141 if ((error
= vfs_update_vfsstat(mp
, &context
)) != 0) {
1147 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1153 struct getfsstat_struct
{
1163 getfsstat_callback(mount_t mp
, void * arg
)
1166 struct getfsstat_struct
*fstp
= (struct getfsstat_struct
*)arg
;
1167 struct vfsstatfs
*sp
;
1168 struct proc
* p
= current_proc();
1170 struct vfs_context context
;
1172 context
.vc_proc
= p
;
1173 context
.vc_ucred
= kauth_cred_get();
1175 if (fstp
->sfsp
&& fstp
->count
< fstp
->maxcount
) {
1176 sp
= &mp
->mnt_vfsstat
;
1178 * If MNT_NOWAIT is specified, do not refresh the
1179 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
1181 if (((fstp
->flags
& MNT_NOWAIT
) == 0 || (fstp
->flags
& MNT_WAIT
)) &&
1182 (error
= vfs_update_vfsstat(mp
, &context
))) {
1183 KAUTH_DEBUG("vfs_update_vfsstat returned %d", error
);
1184 return(VFS_RETURNED
);
1188 * Need to handle LP64 version of struct statfs
1190 error
= munge_statfs(mp
, sp
, fstp
->sfsp
, &my_size
, IS_64BIT_PROCESS(p
), FALSE
);
1192 fstp
->error
= error
;
1193 return(VFS_RETURNED_DONE
);
1195 fstp
->sfsp
+= my_size
;
1198 return(VFS_RETURNED
);
1202 * Get statistics on all filesystems.
1205 getfsstat(__unused proc_t p
, struct getfsstat_args
*uap
, int *retval
)
1208 int count
, maxcount
;
1209 struct getfsstat_struct fst
;
1211 if (IS_64BIT_PROCESS(p
)) {
1212 maxcount
= uap
->bufsize
/ sizeof(struct user_statfs
);
1215 maxcount
= uap
->bufsize
/ sizeof(struct statfs
);
1221 fst
.flags
= uap
->flags
;
1224 fst
.maxcount
= maxcount
;
1227 vfs_iterate(0, getfsstat_callback
, &fst
);
1230 KAUTH_DEBUG("ERROR - %s gets %d", p
->p_comm
, fst
.error
);
1234 if (fst
.sfsp
&& fst
.count
> fst
.maxcount
)
1235 *retval
= fst
.maxcount
;
1237 *retval
= fst
.count
;
1241 #if COMPAT_GETFSSTAT
1242 ogetfsstat(p
, uap
, retval
)
1244 register struct getfsstat_args
*uap
;
1252 * Change current working directory to a given file descriptor.
1256 fchdir(struct proc
*p
, struct fchdir_args
*uap
, __unused register_t
*retval
)
1258 register struct filedesc
*fdp
= p
->p_fd
;
1259 struct vnode
*vp
, *tdp
, *tvp
;
1262 struct vfs_context context
;
1264 context
.vc_proc
= p
;
1265 context
.vc_ucred
= kauth_cred_get();
1267 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1269 if ( (error
= vnode_getwithref(vp
)) ) {
1274 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
1276 if (vp
->v_type
!= VDIR
)
1279 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, &context
);
1280 while (!error
&& (mp
= vp
->v_mountedhere
) != NULL
) {
1281 if (vfs_busy(mp
, LK_NOWAIT
)) {
1285 error
= VFS_ROOT(mp
, &tdp
, &context
);
1294 if ( (error
= vnode_ref(vp
)) )
1316 * Change current working directory (``.'').
1320 chdir(struct proc
*p
, struct chdir_args
*uap
, __unused register_t
*retval
)
1322 register struct filedesc
*fdp
= p
->p_fd
;
1324 struct nameidata nd
;
1326 struct vfs_context context
;
1328 context
.vc_proc
= p
;
1329 context
.vc_ucred
= kauth_cred_get();
1331 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1332 UIO_USERSPACE
, uap
->path
, &context
);
1333 error
= change_dir(&nd
, &context
);
1336 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
1337 vnode_put(nd
.ni_vp
);
1341 * drop the iocount we picked up in change_dir
1343 vnode_put(nd
.ni_vp
);
1347 fdp
->fd_cdir
= nd
.ni_vp
;
1357 * Change notion of root (``/'') directory.
1361 chroot(struct proc
*p
, struct chroot_args
*uap
, __unused register_t
*retval
)
1363 register struct filedesc
*fdp
= p
->p_fd
;
1365 struct nameidata nd
;
1366 boolean_t shared_regions_active
;
1368 struct vfs_context context
;
1370 context
.vc_proc
= p
;
1371 context
.vc_ucred
= kauth_cred_get();
1373 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
1376 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1377 UIO_USERSPACE
, uap
->path
, &context
);
1378 error
= change_dir(&nd
, &context
);
1382 if(p
->p_flag
& P_NOSHLIB
) {
1383 shared_regions_active
= FALSE
;
1385 shared_regions_active
= TRUE
;
1387 if ((error
= clone_system_shared_regions(shared_regions_active
,
1388 TRUE
, /* chain_regions */
1390 vnode_put(nd
.ni_vp
);
1393 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
1394 vnode_put(nd
.ni_vp
);
1397 vnode_put(nd
.ni_vp
);
1401 fdp
->fd_rdir
= nd
.ni_vp
;
1402 fdp
->fd_flags
|= FD_CHROOT
;
1412 * Common routine for chroot and chdir.
1415 change_dir(struct nameidata
*ndp
, vfs_context_t ctx
)
1420 if ((error
= namei(ndp
)))
1424 if (vp
->v_type
!= VDIR
)
1427 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, ctx
);
1435 * Check permissions, allocate an open file structure,
1436 * and call the device open routine if any.
1439 #warning XXX implement uid, gid
1441 open1(vfs_context_t ctx
, user_addr_t upath
, int uflags
, struct vnode_attr
*vap
, register_t
*retval
)
1443 struct proc
*p
= vfs_context_proc(ctx
);
1444 register struct filedesc
*fdp
= p
->p_fd
;
1445 register struct fileproc
*fp
;
1446 register struct vnode
*vp
;
1448 struct fileproc
*nfp
;
1449 int type
, indx
, error
;
1451 struct nameidata nd
;
1455 if ((oflags
& O_ACCMODE
) == O_ACCMODE
)
1457 flags
= FFLAGS(uflags
);
1459 AUDIT_ARG(fflags
, oflags
);
1460 AUDIT_ARG(mode
, vap
->va_mode
);
1462 if ( (error
= falloc(p
, &nfp
, &indx
)) ) {
1466 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1467 UIO_USERSPACE
, upath
, ctx
);
1468 p
->p_dupfd
= -indx
- 1; /* XXX check for fdopen */
1470 if ((error
= vn_open_auth(&nd
, &flags
, vap
))) {
1471 if ((error
== ENODEV
|| error
== ENXIO
) && (p
->p_dupfd
>= 0)) { /* XXX from fdopen */
1472 if ((error
= dupfdopen(fdp
, indx
, p
->p_dupfd
, flags
, error
)) == 0) {
1473 fp_drop(p
, indx
, 0, 0);
1478 if (error
== ERESTART
)
1480 fp_free(p
, indx
, fp
);
1487 fp
->f_fglob
->fg_flag
= flags
& (FMASK
| O_EVTONLY
);
1488 fp
->f_fglob
->fg_type
= DTYPE_VNODE
;
1489 fp
->f_fglob
->fg_ops
= &vnops
;
1490 fp
->f_fglob
->fg_data
= (caddr_t
)vp
;
1492 if (flags
& (O_EXLOCK
| O_SHLOCK
)) {
1493 lf
.l_whence
= SEEK_SET
;
1496 if (flags
& O_EXLOCK
)
1497 lf
.l_type
= F_WRLCK
;
1499 lf
.l_type
= F_RDLCK
;
1501 if ((flags
& FNONBLOCK
) == 0)
1503 if ((error
= VNOP_ADVLOCK(vp
, (caddr_t
)fp
->f_fglob
, F_SETLK
, &lf
, type
, ctx
)))
1505 fp
->f_fglob
->fg_flag
|= FHASLOCK
;
1508 /* try to truncate by setting the size attribute */
1509 if ((flags
& O_TRUNC
) && ((error
= vnode_setsize(vp
, (off_t
)0, 0, ctx
)) != 0))
1515 *fdflags(p
, indx
) &= ~UF_RESERVED
;
1516 fp_drop(p
, indx
, fp
, 1);
1523 vn_close(vp
, fp
->f_fglob
->fg_flag
, fp
->f_fglob
->fg_cred
, p
);
1525 fp_free(p
, indx
, fp
);
1532 open_extended(struct proc
*p
, struct open_extended_args
*uap
, register_t
*retval
)
1534 struct vfs_context context
;
1535 register struct filedesc
*fdp
= p
->p_fd
;
1537 kauth_filesec_t xsecdst
;
1538 struct vnode_attr va
;
1542 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
1543 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
1546 context
.vc_proc
= p
;
1547 context
.vc_ucred
= kauth_cred_get();
1550 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
1551 VATTR_SET(&va
, va_mode
, cmode
);
1552 if (uap
->uid
!= KAUTH_UID_NONE
)
1553 VATTR_SET(&va
, va_uid
, uap
->uid
);
1554 if (uap
->gid
!= KAUTH_GID_NONE
)
1555 VATTR_SET(&va
, va_gid
, uap
->gid
);
1556 if (xsecdst
!= NULL
)
1557 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
1559 ciferror
= open1(&context
, uap
->path
, uap
->flags
, &va
, retval
);
1560 if (xsecdst
!= NULL
)
1561 kauth_filesec_free(xsecdst
);
1567 open(struct proc
*p
, struct open_args
*uap
, register_t
*retval
)
1569 struct vfs_context context
;
1570 register struct filedesc
*fdp
= p
->p_fd
;
1571 struct vnode_attr va
;
1574 context
.vc_proc
= p
;
1575 context
.vc_ucred
= kauth_cred_get();
1578 /* Mask off all but regular access permissions */
1579 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
1580 VATTR_SET(&va
, va_mode
, cmode
& ACCESSPERMS
);
1582 return(open1(&context
, uap
->path
, uap
->flags
, &va
, retval
));
1587 * Create a special file.
1589 static int mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
);
1592 mknod(struct proc
*p
, register struct mknod_args
*uap
, __unused register_t
*retval
)
1594 struct vnode_attr va
;
1595 struct vfs_context context
;
1598 struct nameidata nd
;
1601 context
.vc_proc
= p
;
1602 context
.vc_ucred
= kauth_cred_get();
1605 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1606 VATTR_SET(&va
, va_rdev
, uap
->dev
);
1608 /* If it's a mknod() of a FIFO, call mkfifo1() instead */
1609 if ((uap
->mode
& S_IFMT
) == S_IFIFO
)
1610 return(mkfifo1(&context
, uap
->path
, &va
));
1612 AUDIT_ARG(mode
, uap
->mode
);
1613 AUDIT_ARG(dev
, uap
->dev
);
1615 if ((error
= suser(context
.vc_ucred
, &p
->p_acflag
)))
1617 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1618 UIO_USERSPACE
, uap
->path
, &context
);
1630 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
1633 switch (uap
->mode
& S_IFMT
) {
1634 case S_IFMT
: /* used by badsect to flag bad sectors */
1635 VATTR_SET(&va
, va_type
, VBAD
);
1638 VATTR_SET(&va
, va_type
, VCHR
);
1641 VATTR_SET(&va
, va_type
, VBLK
);
1651 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, CREATE
, &context
);
1653 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, &va
, 0, &context
);
1659 int update_flags
= 0;
1661 // Make sure the name & parent pointers are hooked up
1662 if (vp
->v_name
== NULL
)
1663 update_flags
|= VNODE_UPDATE_NAME
;
1664 if (vp
->v_parent
== NULLVP
)
1665 update_flags
|= VNODE_UPDATE_PARENT
;
1668 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
1670 add_fsevent(FSE_CREATE_FILE
, &context
,
1677 * nameidone has to happen before we vnode_put(dvp)
1678 * since it may need to release the fs_nodelock on the dvp
1690 * Create a named pipe.
1693 mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
)
1697 struct nameidata nd
;
1699 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1700 UIO_USERSPACE
, upath
, ctx
);
1707 /* check that this is a new file and authorize addition */
1712 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
1715 VATTR_SET(vap
, va_type
, VFIFO
);
1717 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
);
1720 * nameidone has to happen before we vnode_put(dvp)
1721 * since it may need to release the fs_nodelock on the dvp
1733 mkfifo_extended(struct proc
*p
, struct mkfifo_extended_args
*uap
, __unused register_t
*retval
)
1736 kauth_filesec_t xsecdst
;
1737 struct vfs_context context
;
1738 struct vnode_attr va
;
1740 xsecdst
= KAUTH_FILESEC_NONE
;
1741 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
1742 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
1746 context
.vc_proc
= p
;
1747 context
.vc_ucred
= kauth_cred_get();
1750 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1751 if (uap
->uid
!= KAUTH_UID_NONE
)
1752 VATTR_SET(&va
, va_uid
, uap
->uid
);
1753 if (uap
->gid
!= KAUTH_GID_NONE
)
1754 VATTR_SET(&va
, va_gid
, uap
->gid
);
1755 if (xsecdst
!= KAUTH_FILESEC_NONE
)
1756 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
1758 ciferror
= mkfifo1(&context
, uap
->path
, &va
);
1760 if (xsecdst
!= KAUTH_FILESEC_NONE
)
1761 kauth_filesec_free(xsecdst
);
1767 mkfifo(struct proc
*p
, register struct mkfifo_args
*uap
, __unused register_t
*retval
)
1769 struct vfs_context context
;
1770 struct vnode_attr va
;
1772 context
.vc_proc
= p
;
1773 context
.vc_ucred
= kauth_cred_get();
1776 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1778 return(mkfifo1(&context
, uap
->path
, &va
));
1782 * Make a hard file link.
1786 link(struct proc
*p
, register struct link_args
*uap
, __unused register_t
*retval
)
1788 vnode_t vp
, dvp
, lvp
;
1789 struct nameidata nd
;
1790 struct vfs_context context
;
1793 int need_event
, has_listeners
;
1795 context
.vc_proc
= p
;
1796 context
.vc_ucred
= kauth_cred_get();
1797 vp
= dvp
= lvp
= NULLVP
;
1799 /* look up the object we are linking to */
1800 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1801 UIO_USERSPACE
, uap
->path
, &context
);
1809 /* we're not allowed to link to directories */
1810 if (vp
->v_type
== VDIR
) {
1811 error
= EPERM
; /* POSIX */
1815 /* or to anything that kauth doesn't want us to (eg. immutable items) */
1816 if ((error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_LINKTARGET
, &context
)) != 0)
1819 /* lookup the target node */
1820 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1821 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| AUDITVNPATH2
;
1822 nd
.ni_dirp
= uap
->link
;
1828 /* target node must not exist */
1829 if (lvp
!= NULLVP
) {
1833 /* cannot link across mountpoints */
1834 if (vnode_mount(vp
) != vnode_mount(dvp
)) {
1839 /* authorize creation of the target note */
1840 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
1843 /* and finally make the link */
1844 error
= VNOP_LINK(vp
, dvp
, &nd
.ni_cnd
, &context
);
1848 need_event
= need_fsevent(FSE_CREATE_FILE
, dvp
);
1849 has_listeners
= kauth_authorize_fileop_has_listeners();
1851 if (need_event
|| has_listeners
) {
1852 char *target_path
= NULL
;
1853 char *link_to_path
= NULL
;
1854 int len
, link_name_len
;
1856 /* build the path to the new link file */
1857 target_path
= get_pathbuff();
1859 vn_getpath(dvp
, target_path
, &len
);
1860 target_path
[len
-1] = '/';
1861 strcpy(&target_path
[len
], nd
.ni_cnd
.cn_nameptr
);
1862 len
+= nd
.ni_cnd
.cn_namelen
;
1864 if (has_listeners
) {
1865 /* build the path to file we are linking to */
1866 link_to_path
= get_pathbuff();
1867 link_name_len
= MAXPATHLEN
;
1868 vn_getpath(vp
, link_to_path
, &link_name_len
);
1870 /* call out to allow 3rd party notification of rename.
1871 * Ignore result of kauth_authorize_fileop call.
1873 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_LINK
,
1874 (uintptr_t)link_to_path
, (uintptr_t)target_path
);
1875 if (link_to_path
!= NULL
)
1876 release_pathbuff(link_to_path
);
1879 /* construct fsevent */
1880 if (get_fse_info(vp
, &finfo
, &context
) == 0) {
1881 // build the path to the destination of the link
1882 add_fsevent(FSE_CREATE_FILE
, &context
,
1883 FSE_ARG_STRING
, len
, target_path
,
1884 FSE_ARG_FINFO
, &finfo
,
1888 release_pathbuff(target_path
);
1892 * nameidone has to happen before we vnode_put(dvp)
1893 * since it may need to release the fs_nodelock on the dvp
1906 * Make a symbolic link.
1908 * We could add support for ACLs here too...
1912 symlink(struct proc
*p
, register struct symlink_args
*uap
, __unused register_t
*retval
)
1914 struct vnode_attr va
;
1917 struct nameidata nd
;
1918 struct vfs_context context
;
1922 context
.vc_proc
= p
;
1923 context
.vc_ucred
= kauth_cred_get();
1925 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1926 error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
);
1929 AUDIT_ARG(text
, path
); /* This is the link string */
1931 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1932 UIO_USERSPACE
, uap
->link
, &context
);
1941 VATTR_SET(&va
, va_type
, VLNK
);
1942 VATTR_SET(&va
, va_mode
, ACCESSPERMS
& ~p
->p_fd
->fd_cmask
);
1945 error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
);
1946 /* get default ownership, etc. */
1948 error
= vnode_authattr_new(dvp
, &va
, 0, &context
);
1950 error
= VNOP_SYMLINK(dvp
, &vp
, &nd
.ni_cnd
, &va
, path
, &context
);
1952 /* do fallback attribute handling */
1954 error
= vnode_setattr_fallback(vp
, &va
, &context
);
1957 int update_flags
= 0;
1960 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
1961 nd
.ni_cnd
.cn_flags
= 0;
1969 #if 0 /* XXX - kauth_todo - is KAUTH_FILEOP_SYMLINK needed? */
1970 /* call out to allow 3rd party notification of rename.
1971 * Ignore result of kauth_authorize_fileop call.
1973 if (kauth_authorize_fileop_has_listeners() &&
1975 char *new_link_path
= NULL
;
1978 /* build the path to the new link file */
1979 new_link_path
= get_pathbuff();
1981 vn_getpath(dvp
, new_link_path
, &len
);
1982 new_link_path
[len
- 1] = '/';
1983 strcpy(&new_link_path
[len
], nd
.ni_cnd
.cn_nameptr
);
1985 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_SYMLINK
,
1986 (uintptr_t)path
, (uintptr_t)new_link_path
);
1987 if (new_link_path
!= NULL
)
1988 release_pathbuff(new_link_path
);
1991 // Make sure the name & parent pointers are hooked up
1992 if (vp
->v_name
== NULL
)
1993 update_flags
|= VNODE_UPDATE_NAME
;
1994 if (vp
->v_parent
== NULLVP
)
1995 update_flags
|= VNODE_UPDATE_PARENT
;
1998 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
2000 add_fsevent(FSE_CREATE_FILE
, &context
,
2009 * nameidone has to happen before we vnode_put(dvp)
2010 * since it may need to release the fs_nodelock on the dvp
2018 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
2024 * Delete a whiteout from the filesystem.
2027 #warning XXX authorization not implmented for whiteouts
2029 undelete(struct proc
*p
, register struct undelete_args
*uap
, __unused register_t
*retval
)
2032 struct nameidata nd
;
2033 struct vfs_context context
;
2036 context
.vc_proc
= p
;
2037 context
.vc_ucred
= kauth_cred_get();
2039 NDINIT(&nd
, DELETE
, LOCKPARENT
|DOWHITEOUT
|AUDITVNPATH1
,
2040 UIO_USERSPACE
, uap
->path
, &context
);
2047 if (vp
== NULLVP
&& (nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
2048 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, DELETE
, &context
);
2053 * nameidone has to happen before we vnode_put(dvp)
2054 * since it may need to release the fs_nodelock on the dvp
2066 * Delete a name from the filesystem.
2070 _unlink(struct proc
*p
, struct unlink_args
*uap
, __unused register_t
*retval
, int nodelbusy
)
2074 struct nameidata nd
;
2075 struct vfs_context context
;
2076 struct componentname
*cnp
;
2079 context
.vc_proc
= p
;
2080 context
.vc_ucred
= kauth_cred_get();
2082 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
2083 UIO_USERSPACE
, uap
->path
, &context
);
2086 /* With Carbon delete semantics, busy files cannot be deleted */
2088 flags
|= VNODE_REMOVE_NODELETEBUSY
;
2096 if (vp
->v_type
== VDIR
) {
2097 error
= EPERM
; /* POSIX */
2100 * The root of a mounted filesystem cannot be deleted.
2102 if (vp
->v_flag
& VROOT
) {
2106 /* authorize the delete operation */
2108 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, &context
);
2115 if (need_fsevent(FSE_DELETE
, dvp
)) {
2116 path
= get_pathbuff();
2118 vn_getpath(vp
, path
, &len
);
2119 get_fse_info(vp
, &finfo
, &context
);
2121 error
= VNOP_REMOVE(dvp
, vp
, &nd
.ni_cnd
, flags
, &context
);
2123 if ( !error
&& path
!= NULL
) {
2124 add_fsevent(FSE_DELETE
, &context
,
2125 FSE_ARG_STRING
, len
, path
,
2126 FSE_ARG_FINFO
, &finfo
,
2130 release_pathbuff(path
);
2133 * nameidone has to happen before we vnode_put(dvp)
2134 * since it may need to release the fs_nodelock on the dvp
2143 * Delete a name from the filesystem using POSIX semantics.
2146 unlink(p
, uap
, retval
)
2148 struct unlink_args
*uap
;
2151 return _unlink(p
, uap
, retval
, 0);
2155 * Delete a name from the filesystem using Carbon semantics.
2158 delete(p
, uap
, retval
)
2160 struct delete_args
*uap
;
2163 return _unlink(p
, (struct unlink_args
*)uap
, retval
, 1);
2167 * Reposition read/write file offset.
2170 lseek(p
, uap
, retval
)
2172 register struct lseek_args
*uap
;
2175 struct fileproc
*fp
;
2177 struct vfs_context context
;
2178 off_t offset
= uap
->offset
, file_size
;
2181 if ( (error
= fp_getfvp(p
,uap
->fd
, &fp
, &vp
)) ) {
2182 if (error
== ENOTSUP
)
2186 if (vnode_isfifo(vp
)) {
2190 if ( (error
= vnode_getwithref(vp
)) ) {
2195 switch (uap
->whence
) {
2197 offset
+= fp
->f_fglob
->fg_offset
;
2200 context
.vc_proc
= p
;
2201 context
.vc_ucred
= kauth_cred_get();
2202 if ((error
= vnode_size(vp
, &file_size
, &context
)) != 0)
2204 offset
+= file_size
;
2212 if (uap
->offset
> 0 && offset
< 0) {
2213 /* Incremented/relative move past max size */
2217 * Allow negative offsets on character devices, per
2218 * POSIX 1003.1-2001. Most likely for writing disk
2221 if (offset
< 0 && vp
->v_type
!= VCHR
) {
2222 /* Decremented/relative move before start */
2226 fp
->f_fglob
->fg_offset
= offset
;
2227 *retval
= fp
->f_fglob
->fg_offset
;
2231 (void)vnode_put(vp
);
2238 * Check access permissions.
2241 access1(vnode_t vp
, vnode_t dvp
, int uflags
, vfs_context_t ctx
)
2243 kauth_action_t action
;
2247 * If just the regular access bits, convert them to something
2248 * that vnode_authorize will understand.
2250 if (!(uflags
& _ACCESS_EXTENDED_MASK
)) {
2253 action
|= KAUTH_VNODE_READ_DATA
; /* aka KAUTH_VNODE_LIST_DIRECTORY */
2254 if (uflags
& W_OK
) {
2255 if (vnode_isdir(vp
)) {
2256 action
|= KAUTH_VNODE_ADD_FILE
|
2257 KAUTH_VNODE_ADD_SUBDIRECTORY
;
2258 /* might want delete rights here too */
2260 action
|= KAUTH_VNODE_WRITE_DATA
;
2263 if (uflags
& X_OK
) {
2264 if (vnode_isdir(vp
)) {
2265 action
|= KAUTH_VNODE_SEARCH
;
2267 action
|= KAUTH_VNODE_EXECUTE
;
2271 /* take advantage of definition of uflags */
2272 action
= uflags
>> 8;
2275 /* action == 0 means only check for existence */
2277 error
= vnode_authorize(vp
, dvp
, action
| KAUTH_VNODE_ACCESS
, ctx
);
2287 /* XXX need to support the check-as uid argument */
2289 access_extended(__unused
struct proc
*p
, struct access_extended_args
*uap
, __unused register_t
*retval
)
2291 struct accessx_descriptor
*input
;
2293 int error
, limit
, nent
, i
, j
, wantdelete
;
2294 struct vfs_context context
;
2295 struct nameidata nd
;
2304 context
.vc_ucred
= NULL
;
2306 /* check input size and fetch descriptor array into allocated storage */
2307 if (uap
->size
> ACCESSX_MAX_TABLESIZE
)
2309 if (uap
->size
< sizeof(struct accessx_descriptor
))
2311 MALLOC(input
, struct accessx_descriptor
*, uap
->size
, M_TEMP
, M_WAITOK
);
2312 if (input
== NULL
) {
2316 error
= copyin(uap
->entries
, input
, uap
->size
);
2321 * Access is defined as checking against the process'
2322 * real identity, even if operations are checking the
2323 * effective identity. So we need to tweak the credential
2326 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
2327 context
.vc_proc
= current_proc();
2330 * Find out how many entries we have, so we can allocate the result array.
2332 limit
= uap
->size
/ sizeof(struct accessx_descriptor
);
2335 for (i
= 0; i
< nent
; i
++) {
2337 * Take the offset to the name string for this entry and convert to an
2338 * input array index, which would be one off the end of the array if this
2339 * was the lowest-addressed name string.
2341 j
= input
[i
].ad_name_offset
/ sizeof(struct accessx_descriptor
);
2347 /* implicit reference to previous name, not a real offset */
2349 /* first entry must have a name string */
2359 if (nent
> ACCESSX_MAX_DESCRIPTORS
) {
2363 MALLOC(result
, errno_t
*, nent
* sizeof(errno_t
), M_TEMP
, M_WAITOK
);
2364 if (result
== NULL
) {
2373 for (i
= 0; i
< nent
; i
++) {
2375 * Looking up a new name?
2377 if (input
[i
].ad_name_offset
!= 0) {
2378 /* discard old vnodes */
2388 /* scan forwards to see if we need the parent this time */
2389 wantdelete
= input
[i
].ad_flags
& _DELETE_OK
;
2390 for (j
= i
+ 1; (j
< nent
) && (input
[j
].ad_name_offset
== 0); j
++)
2391 if (input
[j
].ad_flags
& _DELETE_OK
)
2394 niopts
= FOLLOW
| AUDITVNPATH1
;
2395 /* need parent for vnode_authorize for deletion test */
2397 niopts
|= WANTPARENT
;
2400 NDINIT(&nd
, LOOKUP
, niopts
, UIO_SYSSPACE
, CAST_USER_ADDR_T((const char *)input
+ input
[i
].ad_name_offset
), &context
);
2411 * Handle lookup errors.
2421 /* run this access check */
2422 result
[i
] = access1(vp
, dvp
, input
[i
].ad_flags
, &context
);
2425 /* fatal lookup error */
2431 /* copy out results */
2432 error
= copyout(result
, uap
->results
, nent
* sizeof(errno_t
));
2436 FREE(input
, M_TEMP
);
2438 FREE(result
, M_TEMP
);
2443 if (context
.vc_ucred
)
2444 kauth_cred_rele(context
.vc_ucred
);
2449 access(__unused
struct proc
*p
, register struct access_args
*uap
, __unused register_t
*retval
)
2452 struct nameidata nd
;
2454 struct vfs_context context
;
2457 * Access is defined as checking against the process'
2458 * real identity, even if operations are checking the
2459 * effective identity. So we need to tweak the credential
2462 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
2463 context
.vc_proc
= current_proc();
2465 niopts
= FOLLOW
| AUDITVNPATH1
;
2466 /* need parent for vnode_authorize for deletion test */
2467 if (uap
->flags
& _DELETE_OK
)
2468 niopts
|= WANTPARENT
;
2469 NDINIT(&nd
, LOOKUP
, niopts
, UIO_USERSPACE
, uap
->path
, &context
);
2474 error
= access1(nd
.ni_vp
, nd
.ni_dvp
, uap
->flags
, &context
);
2476 vnode_put(nd
.ni_vp
);
2477 if (uap
->flags
& _DELETE_OK
)
2478 vnode_put(nd
.ni_dvp
);
2482 kauth_cred_rele(context
.vc_ucred
);
2488 stat2(vfs_context_t ctx
, struct nameidata
*ndp
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2491 struct user_stat user_sb
;
2494 kauth_filesec_t fsec
;
2495 size_t xsecurity_bufsize
;
2500 fsec
= KAUTH_FILESEC_NONE
;
2501 error
= vn_stat(ndp
->ni_vp
, &sb
, (xsecurity
!= USER_ADDR_NULL
? &fsec
: NULL
), ctx
);
2502 vnode_put(ndp
->ni_vp
);
2507 /* Zap spare fields */
2509 sb
.st_qspare
[0] = 0LL;
2510 sb
.st_qspare
[1] = 0LL;
2511 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
2512 munge_stat(&sb
, &user_sb
);
2513 my_size
= sizeof(user_sb
);
2514 sbp
= (caddr_t
)&user_sb
;
2517 my_size
= sizeof(sb
);
2520 if ((error
= copyout(sbp
, ub
, my_size
)) != 0)
2523 /* caller wants extended security information? */
2524 if (xsecurity
!= USER_ADDR_NULL
) {
2526 /* did we get any? */
2527 if (fsec
== KAUTH_FILESEC_NONE
) {
2528 if (susize(xsecurity_size
, 0) != 0) {
2533 /* find the user buffer size */
2534 xsecurity_bufsize
= fusize(xsecurity_size
);
2536 /* copy out the actual data size */
2537 if (susize(xsecurity_size
, KAUTH_FILESEC_COPYSIZE(fsec
)) != 0) {
2542 /* if the caller supplied enough room, copy out to it */
2543 if (xsecurity_bufsize
>= KAUTH_FILESEC_COPYSIZE(fsec
))
2544 error
= copyout(fsec
, xsecurity
, KAUTH_FILESEC_COPYSIZE(fsec
));
2548 if (fsec
!= KAUTH_FILESEC_NONE
)
2549 kauth_filesec_free(fsec
);
2554 * Get file status; this version follows links.
2557 stat1(struct proc
*p
, user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2559 struct nameidata nd
;
2560 struct vfs_context context
;
2562 context
.vc_proc
= p
;
2563 context
.vc_ucred
= kauth_cred_get();
2565 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2566 UIO_USERSPACE
, path
, &context
);
2567 return(stat2(&context
, &nd
, ub
, xsecurity
, xsecurity_size
));
2571 stat_extended(struct proc
*p
, struct stat_extended_args
*uap
, __unused register_t
*retval
)
2573 return (stat1(p
, uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
));
2577 stat(struct proc
*p
, struct stat_args
*uap
, __unused register_t
*retval
)
2579 return(stat1(p
, uap
->path
, uap
->ub
, 0, 0));
2583 * Get file status; this version does not follow links.
2586 lstat1(struct proc
*p
, user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2588 struct nameidata nd
;
2589 struct vfs_context context
;
2591 context
.vc_proc
= p
;
2592 context
.vc_ucred
= kauth_cred_get();
2594 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
2595 UIO_USERSPACE
, path
, &context
);
2597 return(stat2(&context
, &nd
, ub
, xsecurity
, xsecurity_size
));
2601 lstat_extended(struct proc
*p
, struct lstat_extended_args
*uap
, __unused register_t
*retval
)
2603 return (lstat1(p
, uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
));
2607 lstat(struct proc
*p
, struct lstat_args
*uap
, __unused register_t
*retval
)
2609 return(lstat1(p
, uap
->path
, uap
->ub
, 0, 0));
2613 * Get configurable pathname variables.
2617 pathconf(p
, uap
, retval
)
2619 register struct pathconf_args
*uap
;
2623 struct nameidata nd
;
2624 struct vfs_context context
;
2626 context
.vc_proc
= p
;
2627 context
.vc_ucred
= kauth_cred_get();
2629 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2630 UIO_USERSPACE
, uap
->path
, &context
);
2635 error
= vn_pathconf(nd
.ni_vp
, uap
->name
, retval
, &context
);
2637 vnode_put(nd
.ni_vp
);
2643 * Return target name of a symbolic link.
2647 readlink(p
, uap
, retval
)
2649 register struct readlink_args
*uap
;
2652 register struct vnode
*vp
;
2654 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
2656 struct nameidata nd
;
2657 struct vfs_context context
;
2658 char uio_buf
[ UIO_SIZEOF(1) ];
2660 context
.vc_proc
= p
;
2661 context
.vc_ucred
= kauth_cred_get();
2663 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
2664 UIO_USERSPACE
, uap
->path
, &context
);
2672 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
2673 &uio_buf
[0], sizeof(uio_buf
));
2674 uio_addiov(auio
, uap
->buf
, uap
->count
);
2675 if (vp
->v_type
!= VLNK
)
2678 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, &context
);
2680 error
= VNOP_READLINK(vp
, auio
, &context
);
2683 // LP64todo - fix this
2684 *retval
= uap
->count
- (int)uio_resid(auio
);
2689 * Change file flags.
2692 chflags1(vnode_t vp
, int flags
, vfs_context_t ctx
)
2694 struct vnode_attr va
;
2695 kauth_action_t action
;
2699 VATTR_SET(&va
, va_flags
, flags
);
2701 /* request authorisation, disregard immutability */
2702 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
2705 * Request that the auth layer disregard those file flags it's allowed to when
2706 * authorizing this operation; we need to do this in order to be able to
2707 * clear immutable flags.
2709 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
| KAUTH_VNODE_NOIMMUTABLE
, ctx
)) != 0))
2711 error
= vnode_setattr(vp
, &va
, ctx
);
2719 * Change flags of a file given a path name.
2723 chflags(struct proc
*p
, register struct chflags_args
*uap
, __unused register_t
*retval
)
2725 register struct vnode
*vp
;
2726 struct vfs_context context
;
2728 struct nameidata nd
;
2730 context
.vc_proc
= p
;
2731 context
.vc_ucred
= kauth_cred_get();
2733 AUDIT_ARG(fflags
, uap
->flags
);
2734 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2735 UIO_USERSPACE
, uap
->path
, &context
);
2742 error
= chflags1(vp
, uap
->flags
, &context
);
2748 * Change flags of a file given a file descriptor.
2752 fchflags(struct proc
*p
, register struct fchflags_args
*uap
, __unused register_t
*retval
)
2754 struct vfs_context context
;
2758 AUDIT_ARG(fd
, uap
->fd
);
2759 AUDIT_ARG(fflags
, uap
->flags
);
2760 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
2763 if ((error
= vnode_getwithref(vp
))) {
2768 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2770 context
.vc_proc
= p
;
2771 context
.vc_ucred
= kauth_cred_get();
2773 error
= chflags1(vp
, uap
->flags
, &context
);
2780 * Change security information on a filesystem object.
2783 chmod2(vfs_context_t ctx
, struct vnode
*vp
, struct vnode_attr
*vap
)
2785 kauth_action_t action
;
2788 AUDIT_ARG(mode
, (mode_t
)vap
->va_mode
);
2789 #warning XXX audit new args
2791 /* make sure that the caller is allowed to set this security information */
2792 if (((error
= vnode_authattr(vp
, vap
, &action
, ctx
)) != 0) ||
2793 ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
2794 if (error
== EACCES
)
2799 error
= vnode_setattr(vp
, vap
, ctx
);
2806 * Change mode of a file given path name.
2809 chmod1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
2811 struct nameidata nd
;
2814 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2815 UIO_USERSPACE
, path
, ctx
);
2816 if ((error
= namei(&nd
)))
2818 error
= chmod2(ctx
, nd
.ni_vp
, vap
);
2819 vnode_put(nd
.ni_vp
);
2825 chmod_extended(struct proc
*p
, struct chmod_extended_args
*uap
, __unused register_t
*retval
)
2827 struct vfs_context context
;
2829 struct vnode_attr va
;
2830 kauth_filesec_t xsecdst
;
2833 if (uap
->mode
!= -1)
2834 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2835 if (uap
->uid
!= KAUTH_UID_NONE
)
2836 VATTR_SET(&va
, va_uid
, uap
->uid
);
2837 if (uap
->gid
!= KAUTH_GID_NONE
)
2838 VATTR_SET(&va
, va_gid
, uap
->gid
);
2841 switch(uap
->xsecurity
) {
2842 /* explicit remove request */
2843 case CAST_USER_ADDR_T((void *)1): /* _FILESEC_REMOVE_ACL */
2844 VATTR_SET(&va
, va_acl
, NULL
);
2847 case USER_ADDR_NULL
:
2850 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
2852 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2853 KAUTH_DEBUG("CHMOD - setting ACL with %d entries", va
.va_acl
->acl_entrycount
);
2855 context
.vc_proc
= p
;
2856 context
.vc_ucred
= kauth_cred_get();
2858 error
= chmod1(&context
, uap
->path
, &va
);
2860 if (xsecdst
!= NULL
)
2861 kauth_filesec_free(xsecdst
);
2866 chmod(struct proc
*p
, register struct chmod_args
*uap
, __unused register_t
*retval
)
2868 struct vfs_context context
;
2869 struct vnode_attr va
;
2872 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2874 context
.vc_proc
= p
;
2875 context
.vc_ucred
= kauth_cred_get();
2877 return(chmod1(&context
, uap
->path
, &va
));
2881 * Change mode of a file given a file descriptor.
2884 fchmod1(struct proc
*p
, int fd
, struct vnode_attr
*vap
)
2888 struct vfs_context context
;
2890 context
.vc_proc
= p
;
2891 context
.vc_ucred
= kauth_cred_get();
2895 if ((error
= file_vnode(fd
, &vp
)) != 0)
2897 if ((error
= vnode_getwithref(vp
)) != 0) {
2901 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2903 error
= chmod2(&context
, vp
, vap
);
2904 (void)vnode_put(vp
);
2911 fchmod_extended(struct proc
*p
, struct fchmod_extended_args
*uap
, __unused register_t
*retval
)
2914 struct vnode_attr va
;
2915 kauth_filesec_t xsecdst
;
2918 if (uap
->mode
!= -1)
2919 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2920 if (uap
->uid
!= KAUTH_UID_NONE
)
2921 VATTR_SET(&va
, va_uid
, uap
->uid
);
2922 if (uap
->gid
!= KAUTH_GID_NONE
)
2923 VATTR_SET(&va
, va_gid
, uap
->gid
);
2926 switch(uap
->xsecurity
) {
2927 case USER_ADDR_NULL
:
2928 VATTR_SET(&va
, va_acl
, NULL
);
2930 case CAST_USER_ADDR_T(-1):
2933 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
2935 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2938 error
= fchmod1(p
, uap
->fd
, &va
);
2941 switch(uap
->xsecurity
) {
2942 case USER_ADDR_NULL
:
2943 case CAST_USER_ADDR_T(-1):
2946 if (xsecdst
!= NULL
)
2947 kauth_filesec_free(xsecdst
);
2953 fchmod(struct proc
*p
, register struct fchmod_args
*uap
, __unused register_t
*retval
)
2955 struct vnode_attr va
;
2958 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2960 return(fchmod1(p
, uap
->fd
, &va
));
2965 * Set ownership given a path name.
2969 chown1(vfs_context_t ctx
, register struct chown_args
*uap
, __unused register_t
*retval
, int follow
)
2971 register struct vnode
*vp
;
2972 struct vnode_attr va
;
2974 struct nameidata nd
;
2975 kauth_action_t action
;
2977 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
2979 NDINIT(&nd
, LOOKUP
, (follow
? FOLLOW
: 0) | AUDITVNPATH1
,
2980 UIO_USERSPACE
, uap
->path
, ctx
);
2989 * XXX A TEMPORARY HACK FOR NOW: Try to track console_user
2990 * by looking for chown() calls on /dev/console from a console process.
2992 if ((vp
) && (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
) && (vp
->v_specinfo
) &&
2993 (major(vp
->v_specinfo
->si_rdev
) == CONSMAJOR
) &&
2994 (minor(vp
->v_specinfo
->si_rdev
) == 0)) {
2995 console_user
= uap
->uid
;
2998 if (uap
->uid
!= VNOVAL
)
2999 VATTR_SET(&va
, va_uid
, uap
->uid
);
3000 if (uap
->gid
!= VNOVAL
)
3001 VATTR_SET(&va
, va_gid
, uap
->gid
);
3003 /* preflight and authorize attribute changes */
3004 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
3006 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
3008 error
= vnode_setattr(vp
, &va
, ctx
);
3012 * EACCES is only allowed from namei(); permissions failure should
3013 * return EPERM, so we need to translate the error code.
3015 if (error
== EACCES
)
3023 chown(struct proc
*p
, register struct chown_args
*uap
, register_t
*retval
)
3025 struct vfs_context context
;
3027 context
.vc_proc
= p
;
3028 context
.vc_ucred
= kauth_cred_get();
3030 return chown1(&context
, uap
, retval
, 1);
3034 lchown(struct proc
*p
, register struct lchown_args
*uap
, register_t
*retval
)
3036 struct vfs_context context
;
3038 context
.vc_proc
= p
;
3039 context
.vc_ucred
= kauth_cred_get();
3041 /* Argument list identical, but machine generated; cast for chown1() */
3042 return chown1(&context
, (struct chown_args
*)uap
, retval
, 0);
3046 * Set ownership given a file descriptor.
3050 fchown(struct proc
*p
, register struct fchown_args
*uap
, __unused register_t
*retval
)
3052 struct vnode_attr va
;
3053 struct vfs_context context
;
3056 kauth_action_t action
;
3058 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
3059 AUDIT_ARG(fd
, uap
->fd
);
3061 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
3064 if ( (error
= vnode_getwithref(vp
)) ) {
3068 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3071 if (uap
->uid
!= VNOVAL
)
3072 VATTR_SET(&va
, va_uid
, uap
->uid
);
3073 if (uap
->gid
!= VNOVAL
)
3074 VATTR_SET(&va
, va_gid
, uap
->gid
);
3076 context
.vc_proc
= p
;
3077 context
.vc_ucred
= kauth_cred_get();
3079 /* preflight and authorize attribute changes */
3080 if ((error
= vnode_authattr(vp
, &va
, &action
, &context
)) != 0)
3082 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0)) {
3083 if (error
== EACCES
)
3087 error
= vnode_setattr(vp
, &va
, &context
);
3090 (void)vnode_put(vp
);
3096 getutimes(usrtvp
, tsp
)
3098 struct timespec
*tsp
;
3100 struct user_timeval tv
[2];
3103 if (usrtvp
== USER_ADDR_NULL
) {
3104 struct timeval old_tv
;
3105 /* XXX Y2038 bug because of microtime argument */
3107 TIMEVAL_TO_TIMESPEC(&old_tv
, &tsp
[0]);
3110 if (IS_64BIT_PROCESS(current_proc())) {
3111 error
= copyin(usrtvp
, (void *)tv
, sizeof(tv
));
3113 struct timeval old_tv
[2];
3114 error
= copyin(usrtvp
, (void *)old_tv
, sizeof(old_tv
));
3115 tv
[0].tv_sec
= old_tv
[0].tv_sec
;
3116 tv
[0].tv_usec
= old_tv
[0].tv_usec
;
3117 tv
[1].tv_sec
= old_tv
[1].tv_sec
;
3118 tv
[1].tv_usec
= old_tv
[1].tv_usec
;
3122 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
3123 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
3129 setutimes(vfs_context_t ctx
, struct vnode
*vp
, const struct timespec
*ts
,
3133 struct vnode_attr va
;
3134 kauth_action_t action
;
3136 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3139 VATTR_SET(&va
, va_access_time
, ts
[0]);
3140 VATTR_SET(&va
, va_modify_time
, ts
[1]);
3142 va
.va_vaflags
|= VA_UTIMES_NULL
;
3144 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
3146 /* since we may not need to auth anything, check here */
3147 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
3149 error
= vnode_setattr(vp
, &va
, ctx
);
3156 * Set the access and modification times of a file.
3160 utimes(struct proc
*p
, register struct utimes_args
*uap
, __unused register_t
*retval
)
3162 struct timespec ts
[2];
3165 struct nameidata nd
;
3166 struct vfs_context context
;
3168 context
.vc_proc
= p
;
3169 context
.vc_ucred
= kauth_cred_get();
3171 /* AUDIT: Needed to change the order of operations to do the
3172 * name lookup first because auditing wants the path.
3174 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3175 UIO_USERSPACE
, uap
->path
, &context
);
3182 * Fetch the user-supplied time. If usrtvp is USER_ADDR_NULL, we fetch
3183 * the current time instead.
3186 if ((error
= getutimes(usrtvp
, ts
)) != 0)
3189 error
= setutimes(&context
, nd
.ni_vp
, ts
, usrtvp
== USER_ADDR_NULL
);
3192 vnode_put(nd
.ni_vp
);
3197 * Set the access and modification times of a file.
3201 futimes(struct proc
*p
, register struct futimes_args
*uap
, __unused register_t
*retval
)
3203 struct timespec ts
[2];
3207 struct vfs_context context
;
3209 context
.vc_proc
= p
;
3210 context
.vc_ucred
= kauth_cred_get();
3212 AUDIT_ARG(fd
, uap
->fd
);
3214 if ((error
= getutimes(usrtvp
, ts
)) != 0)
3216 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
3218 if((error
= vnode_getwithref(vp
))) {
3223 error
= setutimes(&context
, vp
, ts
, usrtvp
== 0);
3230 * Truncate a file given its path name.
3234 truncate(struct proc
*p
, register struct truncate_args
*uap
, __unused register_t
*retval
)
3236 register struct vnode
*vp
;
3237 struct vnode_attr va
;
3238 struct vfs_context context
;
3240 struct nameidata nd
;
3241 kauth_action_t action
;
3243 context
.vc_proc
= p
;
3244 context
.vc_ucred
= kauth_cred_get();
3246 if (uap
->length
< 0)
3248 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3249 UIO_USERSPACE
, uap
->path
, &context
);
3250 if ((error
= namei(&nd
)))
3257 VATTR_SET(&va
, va_data_size
, uap
->length
);
3258 if ((error
= vnode_authattr(vp
, &va
, &action
, &context
)) != 0)
3260 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0))
3262 error
= vnode_setattr(vp
, &va
, &context
);
3269 * Truncate a file given a file descriptor.
3273 ftruncate(p
, uap
, retval
)
3275 register struct ftruncate_args
*uap
;
3278 struct vfs_context context
;
3279 struct vnode_attr va
;
3281 struct fileproc
*fp
;
3285 context
.vc_proc
= current_proc();
3286 context
.vc_ucred
= kauth_cred_get();
3288 AUDIT_ARG(fd
, uap
->fd
);
3289 if (uap
->length
< 0)
3292 if ( (error
= fp_lookup(p
,fd
,&fp
,0)) ) {
3296 if (fp
->f_fglob
->fg_type
== DTYPE_PSXSHM
) {
3297 error
= pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
);
3300 if (fp
->f_fglob
->fg_type
!= DTYPE_VNODE
) {
3305 vp
= (struct vnode
*)fp
->f_fglob
->fg_data
;
3307 if ((fp
->f_fglob
->fg_flag
& FWRITE
) == 0) {
3308 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
3313 if ((error
= vnode_getwithref(vp
)) != 0) {
3317 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3320 VATTR_SET(&va
, va_data_size
, uap
->length
);
3321 error
= vnode_setattr(vp
, &va
, &context
);
3322 (void)vnode_put(vp
);
3330 * Sync an open file.
3334 fsync(struct proc
*p
, struct fsync_args
*uap
, __unused register_t
*retval
)
3337 struct fileproc
*fp
;
3338 struct vfs_context context
;
3341 if ( (error
= fp_getfvp(p
, uap
->fd
, &fp
, &vp
)) )
3343 if ( (error
= vnode_getwithref(vp
)) ) {
3347 context
.vc_proc
= p
;
3348 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
3350 error
= VNOP_FSYNC(vp
, MNT_WAIT
, &context
);
3352 (void)vnode_put(vp
);
3358 * Duplicate files. Source must be a file, target must be a file or
3361 * XXX Copyfile authorisation checking is woefully inadequate, and will not
3362 * perform inheritance correctly.
3366 copyfile(struct proc
*p
, register struct copyfile_args
*uap
, __unused register_t
*retval
)
3368 vnode_t tvp
, fvp
, tdvp
, sdvp
;
3369 struct nameidata fromnd
, tond
;
3371 struct vfs_context context
;
3373 context
.vc_proc
= p
;
3374 context
.vc_ucred
= kauth_cred_get();
3376 /* Check that the flags are valid. */
3378 if (uap
->flags
& ~CPF_MASK
) {
3382 NDINIT(&fromnd
, LOOKUP
, SAVESTART
| AUDITVNPATH1
,
3383 UIO_USERSPACE
, uap
->from
, &context
);
3384 if ((error
= namei(&fromnd
)))
3388 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
| AUDITVNPATH2
,
3389 UIO_USERSPACE
, uap
->to
, &context
);
3390 if ((error
= namei(&tond
))) {
3397 if (!(uap
->flags
& CPF_OVERWRITE
)) {
3402 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
3407 if ((error
= vnode_authorize(tdvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
3413 * If source is the same as the destination (that is the
3414 * same inode number) then there is nothing to do.
3415 * (fixed to have POSIX semantics - CSM 3/2/98)
3420 error
= VNOP_COPYFILE(fvp
,tdvp
,tvp
,&tond
.ni_cnd
,uap
->mode
,uap
->flags
,&context
);
3422 sdvp
= tond
.ni_startdir
;
3424 * nameidone has to happen before we vnode_put(tdvp)
3425 * since it may need to release the fs_nodelock on the tdvp
3436 if (fromnd
.ni_startdir
)
3437 vnode_put(fromnd
.ni_startdir
);
3447 * Rename files. Source and destination must either both be directories,
3448 * or both not be directories. If target is a directory, it must be empty.
3452 rename(proc_t p
, register struct rename_args
*uap
, __unused register_t
*retval
)
3456 struct nameidata fromnd
, tond
;
3457 struct vfs_context context
;
3460 char *oname
, *from_name
, *to_name
;
3461 int from_len
, to_len
;
3462 int holding_mntlock
;
3463 mount_t locked_mp
= NULL
;
3465 fse_info from_finfo
, to_finfo
;
3467 context
.vc_proc
= p
;
3468 context
.vc_ucred
= kauth_cred_get();
3469 holding_mntlock
= 0;
3475 NDINIT(&fromnd
, DELETE
, WANTPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->from
, &context
);
3477 if ( (error
= namei(&fromnd
)) )
3479 fdvp
= fromnd
.ni_dvp
;
3482 NDINIT(&tond
, RENAME
, WANTPARENT
| AUDITVNPATH2
, UIO_USERSPACE
, uap
->to
, &context
);
3483 if (fvp
->v_type
== VDIR
)
3484 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
3486 if ( (error
= namei(&tond
)) ) {
3488 * Translate error code for rename("dir1", "dir2/.").
3490 if (error
== EISDIR
&& fvp
->v_type
== VDIR
)
3498 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
3501 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
3514 * If tvp is a directory and not the same as fdvp, or tdvp is not the same as fdvp,
3515 * the node is moving between directories and we need rights to remove from the
3516 * old and add to the new.
3518 * If tvp already exists and is not a directory, we need to be allowed to delete it.
3520 * Note that we do not inherit when renaming. XXX this needs to be revisited to
3521 * implement the deferred-inherit bit.
3527 if ((tvp
!= NULL
) && vnode_isdir(tvp
)) {
3530 } else if (tdvp
!= fdvp
) {
3534 * must have delete rights to remove the old name even in the simple case of
3537 if ((error
= vnode_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
, &context
)) != 0)
3540 /* moving into tdvp or tvp, must have rights to add */
3541 if ((error
= vnode_authorize(((tvp
!= NULL
) && vnode_isdir(tvp
)) ? tvp
: tdvp
,
3543 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
3547 /* node staying in same directory, must be allowed to add new name */
3548 if ((error
= vnode_authorize(fdvp
, NULL
,
3549 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
3552 /* overwriting tvp */
3553 if ((tvp
!= NULL
) && !vnode_isdir(tvp
) &&
3554 ((error
= vnode_authorize(tvp
, tdvp
, KAUTH_VNODE_DELETE
, &context
)) != 0))
3557 /* XXX more checks? */
3560 /* authorization denied */
3565 * Allow the renaming of mount points.
3566 * - target must not exist
3567 * - target must reside in the same directory as source
3568 * - union mounts cannot be renamed
3569 * - "/" cannot be renamed
3571 if ((fvp
->v_flag
& VROOT
) &&
3572 (fvp
->v_type
== VDIR
) &&
3574 (fvp
->v_mountedhere
== NULL
) &&
3576 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
3577 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
3578 struct vnode
*coveredvp
;
3580 /* switch fvp to the covered vnode */
3581 coveredvp
= fvp
->v_mount
->mnt_vnodecovered
;
3582 if ( (vnode_getwithref(coveredvp
)) ) {
3592 * Check for cross-device rename.
3594 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
3595 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
3600 * Avoid renaming "." and "..".
3602 if (fvp
->v_type
== VDIR
&&
3604 (fromnd
.ni_cnd
.cn_namelen
== 1 && fromnd
.ni_cnd
.cn_nameptr
[0] == '.') ||
3605 ((fromnd
.ni_cnd
.cn_flags
| tond
.ni_cnd
.cn_flags
) & ISDOTDOT
)) ) {
3610 * The following edge case is caught here:
3611 * (to cannot be a descendent of from)
3624 if (tdvp
->v_parent
== fvp
) {
3630 * If source is the same as the destination (that is the
3631 * same inode number) then there is nothing to do...
3632 * EXCEPT if the underlying file system supports case
3633 * insensitivity and is case preserving. In this case
3634 * the file system needs to handle the special case of
3635 * getting the same vnode as target (fvp) and source (tvp).
3637 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
3638 * and _PC_CASE_PRESERVING can have this exception, and they need to
3639 * handle the special case of getting the same vnode as target and
3640 * source. NOTE: Then the target is unlocked going into vnop_rename,
3641 * so not to cause locking problems. There is a single reference on tvp.
3643 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
3644 * that correct behaviour then is just to remove the source (link)
3646 if (fvp
== tvp
&& fdvp
== tdvp
) {
3647 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
3648 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
3649 fromnd
.ni_cnd
.cn_namelen
)) {
3654 if (holding_mntlock
&& fvp
->v_mount
!= locked_mp
) {
3656 * we're holding a reference and lock
3657 * on locked_mp, but it no longer matches
3658 * what we want to do... so drop our hold
3660 mount_unlock_renames(locked_mp
);
3661 mount_drop(locked_mp
, 0);
3662 holding_mntlock
= 0;
3664 if (tdvp
!= fdvp
&& fvp
->v_type
== VDIR
) {
3666 * serialize renames that re-shape
3667 * the tree... if holding_mntlock is
3668 * set, then we're ready to go...
3670 * first need to drop the iocounts
3671 * we picked up, second take the
3672 * lock to serialize the access,
3673 * then finally start the lookup
3674 * process over with the lock held
3676 if (!holding_mntlock
) {
3678 * need to grab a reference on
3679 * the mount point before we
3680 * drop all the iocounts... once
3681 * the iocounts are gone, the mount
3684 locked_mp
= fvp
->v_mount
;
3685 mount_ref(locked_mp
, 0);
3688 * nameidone has to happen before we vnode_put(tvp)
3689 * since it may need to release the fs_nodelock on the tvp
3698 * nameidone has to happen before we vnode_put(fdvp)
3699 * since it may need to release the fs_nodelock on the fvp
3706 mount_lock_renames(locked_mp
);
3707 holding_mntlock
= 1;
3713 * when we dropped the iocounts to take
3714 * the lock, we allowed the identity of
3715 * the various vnodes to change... if they did,
3716 * we may no longer be dealing with a rename
3717 * that reshapes the tree... once we're holding
3718 * the iocounts, the vnodes can't change type
3719 * so we're free to drop the lock at this point
3722 if (holding_mntlock
) {
3723 mount_unlock_renames(locked_mp
);
3724 mount_drop(locked_mp
, 0);
3725 holding_mntlock
= 0;
3728 // save these off so we can later verify that fvp is the same
3729 oname
= fvp
->v_name
;
3730 oparent
= fvp
->v_parent
;
3732 if (need_fsevent(FSE_RENAME
, fvp
)) {
3733 get_fse_info(fvp
, &from_finfo
, &context
);
3736 get_fse_info(tvp
, &to_finfo
, &context
);
3738 from_name
= get_pathbuff();
3739 from_len
= MAXPATHLEN
;
3740 vn_getpath(fvp
, from_name
, &from_len
);
3742 to_name
= get_pathbuff();
3743 to_len
= MAXPATHLEN
;
3745 if (tvp
&& tvp
->v_type
!= VDIR
) {
3746 vn_getpath(tvp
, to_name
, &to_len
);
3748 vn_getpath(tdvp
, to_name
, &to_len
);
3749 // if the path is not just "/", then append a "/"
3751 to_name
[to_len
-1] = '/';
3755 strcpy(&to_name
[to_len
], tond
.ni_cnd
.cn_nameptr
);
3756 to_len
+= tond
.ni_cnd
.cn_namelen
+ 1;
3757 to_name
[to_len
] = '\0';
3763 error
= VNOP_RENAME(fdvp
, fvp
, &fromnd
.ni_cnd
,
3764 tdvp
, tvp
, &tond
.ni_cnd
,
3767 if (holding_mntlock
) {
3769 * we can drop our serialization
3772 mount_unlock_renames(locked_mp
);
3773 mount_drop(locked_mp
, 0);
3774 holding_mntlock
= 0;
3777 if (to_name
!= NULL
)
3778 release_pathbuff(to_name
);
3779 if (from_name
!= NULL
)
3780 release_pathbuff(from_name
);
3781 from_name
= to_name
= NULL
;
3786 /* call out to allow 3rd party notification of rename.
3787 * Ignore result of kauth_authorize_fileop call.
3789 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_RENAME
,
3790 (uintptr_t)from_name
, (uintptr_t)to_name
);
3792 if (from_name
!= NULL
&& to_name
!= NULL
) {
3794 add_fsevent(FSE_RENAME
, &context
,
3795 FSE_ARG_STRING
, from_len
, from_name
,
3796 FSE_ARG_FINFO
, &from_finfo
,
3797 FSE_ARG_STRING
, to_len
, to_name
,
3798 FSE_ARG_FINFO
, &to_finfo
,
3801 add_fsevent(FSE_RENAME
, &context
,
3802 FSE_ARG_STRING
, from_len
, from_name
,
3803 FSE_ARG_FINFO
, &from_finfo
,
3804 FSE_ARG_STRING
, to_len
, to_name
,
3808 if (to_name
!= NULL
)
3809 release_pathbuff(to_name
);
3810 if (from_name
!= NULL
)
3811 release_pathbuff(from_name
);
3812 from_name
= to_name
= NULL
;
3815 * update filesystem's mount point data
3818 char *cp
, *pathend
, *mpname
;
3824 mp
= fvp
->v_mountedhere
;
3826 if (vfs_busy(mp
, LK_NOWAIT
)) {
3830 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
3832 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
3834 /* find current mount point prefix */
3835 pathend
= &mp
->mnt_vfsstat
.f_mntonname
[0];
3836 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
3840 /* find last component of target name */
3841 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
3845 /* append name to prefix */
3846 maxlen
= MAXPATHLEN
- (pathend
- mp
->mnt_vfsstat
.f_mntonname
);
3847 bzero(pathend
, maxlen
);
3848 strncpy(pathend
, mpname
, maxlen
- 1);
3850 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
3855 * fix up name & parent pointers. note that we first
3856 * check that fvp has the same name/parent pointers it
3857 * had before the rename call... this is a 'weak' check
3860 if (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
) {
3863 update_flags
= VNODE_UPDATE_NAME
;
3866 update_flags
|= VNODE_UPDATE_PARENT
;
3868 vnode_update_identity(fvp
, tdvp
, tond
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_namelen
, tond
.ni_cnd
.cn_hash
, update_flags
);
3871 if (holding_mntlock
) {
3872 mount_unlock_renames(locked_mp
);
3873 mount_drop(locked_mp
, 0);
3877 * nameidone has to happen before we vnode_put(tdvp)
3878 * since it may need to release the fs_nodelock on the tdvp
3888 * nameidone has to happen before we vnode_put(fdvp)
3889 * since it may need to release the fs_nodelock on the fdvp
3901 * Make a directory file.
3905 mkdir1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
3909 int update_flags
= 0;
3910 struct nameidata nd
;
3912 AUDIT_ARG(mode
, vap
->va_mode
);
3913 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
3914 UIO_USERSPACE
, path
, ctx
);
3915 nd
.ni_cnd
.cn_flags
|= WILLBEDIR
;
3927 /* authorize addition of a directory to the parent */
3928 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
)) != 0)
3931 VATTR_SET(vap
, va_type
, VDIR
);
3933 /* make the directory */
3934 if ((error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
)) != 0)
3937 // Make sure the name & parent pointers are hooked up
3938 if (vp
->v_name
== NULL
)
3939 update_flags
|= VNODE_UPDATE_NAME
;
3940 if (vp
->v_parent
== NULLVP
)
3941 update_flags
|= VNODE_UPDATE_PARENT
;
3944 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
3946 add_fsevent(FSE_CREATE_DIR
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
3950 * nameidone has to happen before we vnode_put(dvp)
3951 * since it may need to release the fs_nodelock on the dvp
3964 mkdir_extended(struct proc
*p
, register struct mkdir_extended_args
*uap
, __unused register_t
*retval
)
3966 struct vfs_context context
;
3968 kauth_filesec_t xsecdst
;
3969 struct vnode_attr va
;
3972 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
3973 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
3976 context
.vc_proc
= p
;
3977 context
.vc_ucred
= kauth_cred_get();
3980 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
3981 if (xsecdst
!= NULL
)
3982 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
3984 ciferror
= mkdir1(&context
, uap
->path
, &va
);
3985 if (xsecdst
!= NULL
)
3986 kauth_filesec_free(xsecdst
);
3991 mkdir(struct proc
*p
, register struct mkdir_args
*uap
, __unused register_t
*retval
)
3993 struct vfs_context context
;
3994 struct vnode_attr va
;
3996 context
.vc_proc
= p
;
3997 context
.vc_ucred
= kauth_cred_get();
4000 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
4002 return(mkdir1(&context
, uap
->path
, &va
));
4006 * Remove a directory file.
4010 rmdir(struct proc
*p
, struct rmdir_args
*uap
, __unused register_t
*retval
)
4014 struct nameidata nd
;
4015 struct vfs_context context
;
4017 context
.vc_proc
= p
;
4018 context
.vc_ucred
= kauth_cred_get();
4020 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
4021 UIO_USERSPACE
, uap
->path
, &context
);
4028 if (vp
->v_type
!= VDIR
) {
4030 * rmdir only deals with directories
4033 } else if (dvp
== vp
) {
4035 * No rmdir "." please.
4038 } else if (vp
->v_flag
& VROOT
) {
4040 * The root of a mounted filesystem cannot be deleted.
4044 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, &context
);
4051 if (need_fsevent(FSE_DELETE
, dvp
)) {
4052 path
= get_pathbuff();
4054 vn_getpath(vp
, path
, &len
);
4055 get_fse_info(vp
, &finfo
, &context
);
4057 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, &context
);
4059 if (!error
&& path
!= NULL
) {
4060 add_fsevent(FSE_DELETE
, &context
,
4061 FSE_ARG_STRING
, len
, path
,
4062 FSE_ARG_FINFO
, &finfo
,
4066 release_pathbuff(path
);
4069 * nameidone has to happen before we vnode_put(dvp)
4070 * since it may need to release the fs_nodelock on the dvp
4082 * Read a block of directory entries in a file system independent format.
4085 getdirentries(p
, uap
, retval
)
4087 register struct getdirentries_args
*uap
;
4091 struct vfs_context context
;
4092 struct fileproc
*fp
;
4094 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4098 char uio_buf
[ UIO_SIZEOF(1) ];
4100 AUDIT_ARG(fd
, uap
->fd
);
4101 error
= fp_getfvp(p
, fd
, &fp
, &vp
);
4105 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
4106 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4110 if ( (error
= vnode_getwithref(vp
)) ) {
4114 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4117 if (vp
->v_type
!= VDIR
) {
4118 (void)vnode_put(vp
);
4122 context
.vc_proc
= p
;
4123 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
4125 loff
= fp
->f_fglob
->fg_offset
;
4126 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
4127 &uio_buf
[0], sizeof(uio_buf
));
4128 uio_addiov(auio
, uap
->buf
, uap
->count
);
4130 error
= VNOP_READDIR(vp
, auio
, 0, &eofflag
, (int *)NULL
, &context
);
4131 fp
->f_fglob
->fg_offset
= uio_offset(auio
);
4133 (void)vnode_put(vp
);
4139 if ((uap
->count
== uio_resid(auio
)) &&
4140 (vp
->v_op
== union_vnodeop_p
)) {
4143 lvp
= union_dircache(vp
, p
);
4144 if (lvp
!= NULLVP
) {
4145 struct vnode_attr va
;
4147 * If the directory is opaque,
4148 * then don't show lower entries
4151 VATTR_WANTED(&va
, va_flags
);
4152 error
= vnode_getattr(vp
, &va
, &context
);
4153 if (va
.va_flags
& OPAQUE
) {
4159 if (lvp
!= NULLVP
) {
4160 error
= VNOP_OPEN(lvp
, FREAD
, &context
);
4166 fp
->f_fglob
->fg_data
= (caddr_t
) lvp
;
4167 fp
->f_fglob
->fg_offset
= 0;
4168 error
= VNOP_CLOSE(vp
, FREAD
, &context
);
4180 if (((user_ssize_t
)uap
->count
== uio_resid(auio
)) &&
4181 (vp
->v_flag
& VROOT
) &&
4182 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
4183 struct vnode
*tvp
= vp
;
4184 vp
= vp
->v_mount
->mnt_vnodecovered
;
4185 vnode_getwithref(vp
);
4187 fp
->f_fglob
->fg_data
= (caddr_t
) vp
;
4188 fp
->f_fglob
->fg_offset
= 0;
4194 error
= copyout((caddr_t
)&loff
, uap
->basep
, sizeof(long));
4195 // LP64todo - fix this
4196 *retval
= uap
->count
- uio_resid(auio
);
4203 * Set the mode mask for creation of filesystem nodes.
4205 #warning XXX implement xsecurity
4207 #define UMASK_NOXSECURITY (void *)1 /* leave existing xsecurity alone */
4209 umask1(struct proc
*p
, int newmask
, __unused kauth_filesec_t fsec
, register_t
*retval
)
4211 register struct filedesc
*fdp
;
4213 AUDIT_ARG(mask
, newmask
);
4215 *retval
= fdp
->fd_cmask
;
4216 fdp
->fd_cmask
= newmask
& ALLPERMS
;
4222 umask_extended(struct proc
*p
, struct umask_extended_args
*uap
, register_t
*retval
)
4225 kauth_filesec_t xsecdst
;
4227 xsecdst
= KAUTH_FILESEC_NONE
;
4228 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
4229 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
4232 xsecdst
= KAUTH_FILESEC_NONE
;
4235 ciferror
= umask1(p
, uap
->newmask
, xsecdst
, retval
);
4237 if (xsecdst
!= KAUTH_FILESEC_NONE
)
4238 kauth_filesec_free(xsecdst
);
4243 umask(struct proc
*p
, struct umask_args
*uap
, register_t
*retval
)
4245 return(umask1(p
, uap
->newmask
, UMASK_NOXSECURITY
, retval
));
4249 * Void all references to file by ripping underlying filesystem
4254 revoke(struct proc
*p
, register struct revoke_args
*uap
, __unused register_t
*retval
)
4256 register struct vnode
*vp
;
4257 struct vnode_attr va
;
4258 struct vfs_context context
;
4260 struct nameidata nd
;
4262 context
.vc_proc
= p
;
4263 context
.vc_ucred
= kauth_cred_get();
4265 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4266 UIO_USERSPACE
, uap
->path
, &context
);
4275 VATTR_WANTED(&va
, va_uid
);
4276 if ((error
= vnode_getattr(vp
, &va
, &context
)))
4278 if (kauth_cred_getuid(context
.vc_ucred
) != va
.va_uid
&&
4279 (error
= suser(context
.vc_ucred
, &p
->p_acflag
)))
4281 if (vp
->v_usecount
> 1 || (vp
->v_flag
& VALIASED
))
4282 VNOP_REVOKE(vp
, REVOKEALL
, &context
);
4290 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
4291 * The following system calls are designed to support features
4292 * which are specific to the HFS & HFS Plus volume formats
4295 #ifdef __APPLE_API_OBSOLETE
4297 /************************************************/
4298 /* *** Following calls will be deleted soon *** */
4299 /************************************************/
4302 * Make a complex file. A complex file is one with multiple forks (data streams)
4306 mkcomplex(__unused
struct proc
*p
, __unused
struct mkcomplex_args
*uap
, __unused register_t
*retval
)
4312 * Extended stat call which returns volumeid and vnodeid as well as other info
4316 statv(__unused
struct proc
*p
,
4317 __unused
struct statv_args
*uap
,
4318 __unused register_t
*retval
)
4320 return (ENOTSUP
); /* We'll just return an error for now */
4322 } /* end of statv system call */
4325 * Extended lstat call which returns volumeid and vnodeid as well as other info
4329 lstatv(__unused
struct proc
*p
,
4330 __unused
struct lstatv_args
*uap
,
4331 __unused register_t
*retval
)
4333 return (ENOTSUP
); /* We'll just return an error for now */
4334 } /* end of lstatv system call */
4337 * Extended fstat call which returns volumeid and vnodeid as well as other info
4341 fstatv(__unused
struct proc
*p
,
4342 __unused
struct fstatv_args
*uap
,
4343 __unused register_t
*retval
)
4345 return (ENOTSUP
); /* We'll just return an error for now */
4346 } /* end of fstatv system call */
4349 /************************************************/
4350 /* *** Preceding calls will be deleted soon *** */
4351 /************************************************/
4353 #endif /* __APPLE_API_OBSOLETE */
4356 * Obtain attribute information on objects in a directory while enumerating
4357 * the directory. This call does not yet support union mounted directories.
4359 * 1.union mounted directories.
4364 getdirentriesattr (struct proc
*p
, struct getdirentriesattr_args
*uap
, register_t
*retval
)
4367 struct fileproc
*fp
;
4369 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4370 uint64_t actualcount
;
4375 struct attrlist attributelist
;
4376 struct vfs_context context
;
4378 char uio_buf
[ UIO_SIZEOF(1) ];
4379 kauth_action_t action
;
4383 /* Get the attributes into kernel space */
4384 if ((error
= copyin(uap
->alist
, (caddr_t
) &attributelist
, sizeof (attributelist
))))
4386 actualcount
= fuulong(uap
->count
);
4387 if (actualcount
== -1ULL)
4390 if ( (error
= fp_getfvp(p
, fd
, &fp
, &vp
)) )
4393 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
4394 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4398 if ( (error
= vnode_getwithref(vp
)) )
4401 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4403 if (vp
->v_type
!= VDIR
) {
4404 (void)vnode_put(vp
);
4409 /* set up the uio structure which will contain the users return buffer */
4410 loff
= fp
->f_fglob
->fg_offset
;
4411 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
4412 &uio_buf
[0], sizeof(uio_buf
));
4413 uio_addiov(auio
, uap
->buffer
, uap
->buffersize
);
4415 context
.vc_proc
= p
;
4416 context
.vc_ucred
= kauth_cred_get();
4417 tmpcount
= (u_long
) actualcount
;
4420 * If the only item requested is file names, we can let that past with
4421 * just LIST_DIRECTORY. If they want any other attributes, that means
4422 * they need SEARCH as well.
4424 action
= KAUTH_VNODE_LIST_DIRECTORY
;
4425 if ((attributelist
.commonattr
& ~ATTR_CMN_NAME
) ||
4426 attributelist
.fileattr
|| attributelist
.dirattr
)
4427 action
|= KAUTH_VNODE_SEARCH
;
4429 if ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) == 0)
4430 error
= VNOP_READDIRATTR(vp
, &attributelist
, auio
,
4431 tmpcount
, uap
->options
, &newstate
, &eofflag
,
4432 &tmpcount
, &context
);
4433 (void)vnode_put(vp
);
4434 actualcount
= tmpcount
;
4438 fp
->f_fglob
->fg_offset
= uio_offset(auio
); /* should be multiple of dirent, not variable */
4440 if ((error
= suulong(uap
->count
, actualcount
)) != 0)
4442 if ((error
= suulong(uap
->newstate
, (uint64_t)newstate
)) != 0)
4444 if ((error
= suulong(uap
->basep
, (uint64_t)loff
)) != 0)
4447 *retval
= eofflag
; /* similar to getdirentries */
4451 return (error
); /* return error earlier, an retval of 0 or 1 now */
4453 } /* end of getdirentryattr system call */
4456 * Exchange data between two files
4461 exchangedata (struct proc
*p
, register struct exchangedata_args
*uap
, __unused register_t
*retval
)
4464 struct nameidata fnd
, snd
;
4465 struct vfs_context context
;
4466 struct vnode
*fvp
, *svp
;
4472 fse_info f_finfo
, s_finfo
;
4474 context
.vc_proc
= p
;
4475 context
.vc_ucred
= kauth_cred_get();
4478 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4480 NDINIT(&fnd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4481 UIO_USERSPACE
, uap
->path1
, &context
);
4483 error
= namei(&fnd
);
4490 NDINIT(&snd
, LOOKUP
, nameiflags
| AUDITVNPATH2
,
4491 UIO_USERSPACE
, uap
->path2
, &context
);
4493 error
= namei(&snd
);
4502 * if the files are the same, return an inval error
4510 * if the files are on different volumes, return an error
4512 if (svp
->v_mount
!= fvp
->v_mount
) {
4516 if (((error
= vnode_authorize(fvp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0) ||
4517 ((error
= vnode_authorize(svp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0))
4520 if (need_fsevent(FSE_EXCHANGE
, fvp
) || kauth_authorize_fileop_has_listeners()) {
4521 fpath
= get_pathbuff();
4522 spath
= get_pathbuff();
4525 if (vn_getpath(fvp
, fpath
, &flen
) != 0 || fpath
[0] == '\0') {
4526 printf("exchange: vn_getpath(fvp=0x%x) failed <<%s>>\n",
4529 if (vn_getpath(svp
, spath
, &slen
) != 0 || spath
[0] == '\0') {
4530 printf("exchange: vn_getpath(svp=0x%x) failed <<%s>>\n",
4533 get_fse_info(fvp
, &f_finfo
, &context
);
4534 get_fse_info(svp
, &s_finfo
, &context
);
4536 /* Ok, make the call */
4537 error
= VNOP_EXCHANGE(fvp
, svp
, 0, &context
);
4542 if (fpath
!= NULL
&& spath
!= NULL
) {
4543 /* call out to allow 3rd party notification of exchangedata.
4544 * Ignore result of kauth_authorize_fileop call.
4546 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_EXCHANGE
,
4547 (uintptr_t)fpath
, (uintptr_t)spath
);
4551 tmpname
= fvp
->v_name
;
4552 fvp
->v_name
= svp
->v_name
;
4553 svp
->v_name
= tmpname
;
4555 if (fvp
->v_parent
!= svp
->v_parent
) {
4558 tmp
= fvp
->v_parent
;
4559 fvp
->v_parent
= svp
->v_parent
;
4560 svp
->v_parent
= tmp
;
4562 name_cache_unlock();
4564 if (fpath
!= NULL
&& spath
!= NULL
) {
4565 add_fsevent(FSE_EXCHANGE
, &context
,
4566 FSE_ARG_STRING
, flen
, fpath
,
4567 FSE_ARG_FINFO
, &f_finfo
,
4568 FSE_ARG_STRING
, slen
, spath
,
4569 FSE_ARG_FINFO
, &s_finfo
,
4574 release_pathbuff(spath
);
4576 release_pathbuff(fpath
);
4586 #ifdef __APPLE_API_OBSOLETE
4588 /************************************************/
4589 /* *** Following calls will be deleted soon *** */
4590 /************************************************/
4593 * Check users access to a file
4597 #warning "checkuseraccess copies a cred in from user space but"
4598 #warning "user space has no way of knowing what one looks like"
4599 #warning "this code should use the access_extended spoof-as functionality"
4601 checkuseraccess (struct proc
*p
, register struct checkuseraccess_args
*uap
, __unused register_t
*retval
)
4603 register struct vnode
*vp
;
4605 struct nameidata nd
;
4606 struct ucred cred
; /* XXX ILLEGAL */
4607 int flags
; /*what will actually get passed to access*/
4609 struct vfs_context context
;
4611 /* Make sure that the number of groups is correct before we do anything */
4613 if ((uap
->ngroups
<= 0) || (uap
->ngroups
> NGROUPS
))
4616 /* Verify that the caller is root */
4618 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
4621 /* Fill in the credential structure */
4624 cred
.cr_uid
= uap
->userid
;
4625 cred
.cr_ngroups
= uap
->ngroups
;
4626 if ((error
= copyin(CAST_USER_ADDR_T(uap
->groups
), (caddr_t
) &(cred
.cr_groups
), (sizeof(gid_t
))*uap
->ngroups
)))
4629 context
.vc_proc
= p
;
4630 context
.vc_ucred
= &cred
;
4632 /* Get our hands on the file */
4634 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4635 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4636 UIO_USERSPACE
, CAST_USER_ADDR_T(uap
->path
), &context
);
4638 if ((error
= namei(&nd
)))
4643 /* Flags == 0 means only check for existence. */
4647 if (uap
->accessrequired
) {
4648 if (uap
->accessrequired
& R_OK
)
4649 flags
|= KAUTH_VNODE_READ_DATA
;
4650 if (uap
->accessrequired
& W_OK
)
4651 flags
|= KAUTH_VNODE_WRITE_DATA
;
4652 if (uap
->accessrequired
& X_OK
)
4653 flags
|= KAUTH_VNODE_EXECUTE
;
4655 error
= vnode_authorize(vp
, NULL
, flags
, &context
);
4664 } /* end of checkuseraccess system call */
4666 /************************************************/
4667 /* *** Preceding calls will be deleted soon *** */
4668 /************************************************/
4670 #endif /* __APPLE_API_OBSOLETE */
4677 searchfs (struct proc
*p
, register struct searchfs_args
*uap
, __unused register_t
*retval
)
4679 register struct vnode
*vp
;
4682 struct nameidata nd
;
4683 struct user_fssearchblock searchblock
;
4684 struct searchstate
*state
;
4685 struct attrlist
*returnattrs
;
4686 void *searchparams1
,*searchparams2
;
4688 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4692 struct vfs_context context
;
4693 char uio_buf
[ UIO_SIZEOF(1) ];
4695 context
.vc_proc
= p
;
4696 context
.vc_ucred
= kauth_cred_get();
4698 /* Start by copying in fsearchblock paramater list */
4699 if (IS_64BIT_PROCESS(p
)) {
4700 error
= copyin(uap
->searchblock
, (caddr_t
) &searchblock
, sizeof(searchblock
));
4703 struct fssearchblock tmp_searchblock
;
4704 error
= copyin(uap
->searchblock
, (caddr_t
) &tmp_searchblock
, sizeof(tmp_searchblock
));
4705 // munge into 64-bit version
4706 searchblock
.returnattrs
= CAST_USER_ADDR_T(tmp_searchblock
.returnattrs
);
4707 searchblock
.returnbuffer
= CAST_USER_ADDR_T(tmp_searchblock
.returnbuffer
);
4708 searchblock
.returnbuffersize
= tmp_searchblock
.returnbuffersize
;
4709 searchblock
.maxmatches
= tmp_searchblock
.maxmatches
;
4710 searchblock
.timelimit
= tmp_searchblock
.timelimit
;
4711 searchblock
.searchparams1
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams1
);
4712 searchblock
.sizeofsearchparams1
= tmp_searchblock
.sizeofsearchparams1
;
4713 searchblock
.searchparams2
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams2
);
4714 searchblock
.sizeofsearchparams2
= tmp_searchblock
.sizeofsearchparams2
;
4715 searchblock
.searchattrs
= tmp_searchblock
.searchattrs
;
4720 /* Do a sanity check on sizeofsearchparams1 and sizeofsearchparams2.
4722 if (searchblock
.sizeofsearchparams1
> SEARCHFS_MAX_SEARCHPARMS
||
4723 searchblock
.sizeofsearchparams2
> SEARCHFS_MAX_SEARCHPARMS
)
4726 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
4727 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
4728 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
4731 mallocsize
= searchblock
.sizeofsearchparams1
+ searchblock
.sizeofsearchparams2
+
4732 sizeof(struct attrlist
) + sizeof(struct searchstate
);
4734 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
4736 /* Now set up the various pointers to the correct place in our newly allocated memory */
4738 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
4739 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
4740 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
4742 /* Now copy in the stuff given our local variables. */
4744 if ((error
= copyin(searchblock
.searchparams1
, searchparams1
, searchblock
.sizeofsearchparams1
)))
4747 if ((error
= copyin(searchblock
.searchparams2
, searchparams2
, searchblock
.sizeofsearchparams2
)))
4750 if ((error
= copyin(searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
))))
4753 if ((error
= copyin(uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
))))
4756 /* set up the uio structure which will contain the users return buffer */
4758 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
4759 &uio_buf
[0], sizeof(uio_buf
));
4760 uio_addiov(auio
, searchblock
.returnbuffer
, searchblock
.returnbuffersize
);
4763 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4764 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4765 UIO_USERSPACE
, uap
->path
, &context
);
4776 * If searchblock.maxmatches == 0, then skip the search. This has happened
4777 * before and sometimes the underlyning code doesnt deal with it well.
4779 if (searchblock
.maxmatches
== 0) {
4785 Allright, we have everything we need, so lets make that call.
4787 We keep special track of the return value from the file system:
4788 EAGAIN is an acceptable error condition that shouldn't keep us
4789 from copying out any results...
4792 fserror
= VNOP_SEARCHFS(vp
,
4795 &searchblock
.searchattrs
,
4796 searchblock
.maxmatches
,
4797 &searchblock
.timelimit
,
4810 /* Now copy out the stuff that needs copying out. That means the number of matches, the
4811 search state. Everything was already put into he return buffer by the vop call. */
4813 if ((error
= copyout((caddr_t
) state
, uap
->state
, sizeof(struct searchstate
))) != 0)
4816 if ((error
= suulong(uap
->nummatches
, (uint64_t)nummatches
)) != 0)
4823 FREE(searchparams1
,M_TEMP
);
4828 } /* end of searchfs system call */
4832 * Make a filesystem-specific control call:
4836 fsctl (struct proc
*p
, struct fsctl_args
*uap
, __unused register_t
*retval
)
4840 struct nameidata nd
;
4842 u_long cmd
= uap
->cmd
;
4843 register u_int size
;
4844 #define STK_PARAMS 128
4845 char stkbuf
[STK_PARAMS
];
4847 struct vfs_context context
;
4849 context
.vc_proc
= p
;
4850 context
.vc_ucred
= kauth_cred_get();
4852 size
= IOCPARM_LEN(cmd
);
4853 if (size
> IOCPARM_MAX
) return (EINVAL
);
4855 is64bit
= proc_is64bit(p
);
4858 if (size
> sizeof (stkbuf
)) {
4859 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
4867 error
= copyin(uap
->data
, data
, size
);
4868 if (error
) goto FSCtl_Exit
;
4871 *(user_addr_t
*)data
= uap
->data
;
4874 *(uint32_t *)data
= (uint32_t)uap
->data
;
4877 } else if ((cmd
& IOC_OUT
) && size
) {
4879 * Zero the buffer so the user always
4880 * gets back something deterministic.
4883 } else if (cmd
& IOC_VOID
) {
4885 *(user_addr_t
*)data
= uap
->data
;
4888 *(uint32_t *)data
= (uint32_t)uap
->data
;
4892 /* Get the vnode for the file we are getting info on: */
4894 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4895 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, uap
->path
, &context
);
4896 if ((error
= namei(&nd
))) goto FSCtl_Exit
;
4898 /* Invoke the filesystem-specific code */
4899 error
= VNOP_IOCTL(nd
.ni_vp
, IOCBASECMD(cmd
), data
, uap
->options
, &context
);
4901 vnode_put(nd
.ni_vp
);
4905 * Copy any data to user, size was
4906 * already set and checked above.
4908 if (error
== 0 && (cmd
& IOC_OUT
) && size
)
4909 error
= copyout(data
, uap
->data
, size
);
4912 if (memp
) kfree(memp
, size
);
4916 /* end of fsctl system call */
4919 * An in-kernel sync for power management to call.
4921 __private_extern__
int
4926 struct sync_args data
;
4931 error
= sync(current_proc(), &data
, &retval
[0]);
4935 } /* end of sync_internal call */
4939 * Retrieve the data of an extended attribute.
4942 getxattr(struct proc
*p
, struct getxattr_args
*uap
, user_ssize_t
*retval
)
4945 struct nameidata nd
;
4946 char attrname
[XATTR_MAXNAMELEN
+1];
4947 struct vfs_context context
;
4949 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4950 size_t attrsize
= 0;
4954 char uio_buf
[ UIO_SIZEOF(1) ];
4956 context
.vc_proc
= p
;
4957 context
.vc_ucred
= kauth_cred_get();
4959 if (uap
->options
& XATTR_NOSECURITY
)
4962 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
4963 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
4964 if ((error
= namei(&nd
))) {
4970 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
4973 if (xattr_protected(attrname
)) {
4977 if (uap
->value
&& uap
->size
> 0) {
4978 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
4979 &uio_buf
[0], sizeof(uio_buf
));
4980 uio_addiov(auio
, uap
->value
, uap
->size
);
4983 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, &context
);
4988 *retval
= uap
->size
- uio_resid(auio
);
4990 *retval
= (user_ssize_t
)attrsize
;
4997 * Retrieve the data of an extended attribute.
5000 fgetxattr(struct proc
*p
, struct fgetxattr_args
*uap
, user_ssize_t
*retval
)
5003 char attrname
[XATTR_MAXNAMELEN
+1];
5004 struct vfs_context context
;
5006 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5007 size_t attrsize
= 0;
5010 char uio_buf
[ UIO_SIZEOF(1) ];
5012 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5015 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5018 if ( (error
= vnode_getwithref(vp
)) ) {
5022 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5025 if (xattr_protected(attrname
)) {
5029 if (uap
->value
&& uap
->size
> 0) {
5030 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
5031 &uio_buf
[0], sizeof(uio_buf
));
5032 uio_addiov(auio
, uap
->value
, uap
->size
);
5034 context
.vc_proc
= p
;
5035 context
.vc_ucred
= kauth_cred_get();
5037 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, &context
);
5039 (void)vnode_put(vp
);
5043 *retval
= uap
->size
- uio_resid(auio
);
5045 *retval
= (user_ssize_t
)attrsize
;
5051 * Set the data of an extended attribute.
5054 setxattr(struct proc
*p
, struct setxattr_args
*uap
, int *retval
)
5057 struct nameidata nd
;
5058 char attrname
[XATTR_MAXNAMELEN
+1];
5059 struct vfs_context context
;
5061 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5065 char uio_buf
[ UIO_SIZEOF(1) ];
5067 context
.vc_proc
= p
;
5068 context
.vc_ucred
= kauth_cred_get();
5070 if (uap
->options
& XATTR_NOSECURITY
)
5073 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5076 if (xattr_protected(attrname
))
5078 if (uap
->value
== 0 || uap
->size
== 0) {
5082 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5083 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5084 if ((error
= namei(&nd
))) {
5090 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
5091 &uio_buf
[0], sizeof(uio_buf
));
5092 uio_addiov(auio
, uap
->value
, uap
->size
);
5094 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, &context
);
5101 * Set the data of an extended attribute.
5104 fsetxattr(struct proc
*p
, struct fsetxattr_args
*uap
, int *retval
)
5107 char attrname
[XATTR_MAXNAMELEN
+1];
5108 struct vfs_context context
;
5110 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5113 char uio_buf
[ UIO_SIZEOF(1) ];
5115 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5118 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5121 if (xattr_protected(attrname
))
5123 if (uap
->value
== 0 || uap
->size
== 0) {
5126 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5129 if ( (error
= vnode_getwithref(vp
)) ) {
5133 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
5134 &uio_buf
[0], sizeof(uio_buf
));
5135 uio_addiov(auio
, uap
->value
, uap
->size
);
5136 context
.vc_proc
= p
;
5137 context
.vc_ucred
= kauth_cred_get();
5139 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, &context
);
5147 * Remove an extended attribute.
5149 #warning "code duplication"
5151 removexattr(struct proc
*p
, struct removexattr_args
*uap
, int *retval
)
5154 struct nameidata nd
;
5155 char attrname
[XATTR_MAXNAMELEN
+1];
5156 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5157 struct vfs_context context
;
5162 context
.vc_proc
= p
;
5163 context
.vc_ucred
= kauth_cred_get();
5165 if (uap
->options
& XATTR_NOSECURITY
)
5168 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
5172 if (xattr_protected(attrname
))
5174 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5175 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5176 if ((error
= namei(&nd
))) {
5182 error
= vn_removexattr(vp
, attrname
, uap
->options
, &context
);
5189 * Remove an extended attribute.
5191 #warning "code duplication"
5193 fremovexattr(struct proc
*p
, struct fremovexattr_args
*uap
, int *retval
)
5196 char attrname
[XATTR_MAXNAMELEN
+1];
5197 struct vfs_context context
;
5201 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5204 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
5208 if (xattr_protected(attrname
))
5210 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5213 if ( (error
= vnode_getwithref(vp
)) ) {
5217 context
.vc_proc
= p
;
5218 context
.vc_ucred
= kauth_cred_get();
5220 error
= vn_removexattr(vp
, attrname
, uap
->options
, &context
);
5228 * Retrieve the list of extended attribute names.
5230 #warning "code duplication"
5232 listxattr(struct proc
*p
, struct listxattr_args
*uap
, user_ssize_t
*retval
)
5235 struct nameidata nd
;
5236 struct vfs_context context
;
5238 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5239 size_t attrsize
= 0;
5242 char uio_buf
[ UIO_SIZEOF(1) ];
5244 context
.vc_proc
= p
;
5245 context
.vc_ucred
= kauth_cred_get();
5247 if (uap
->options
& XATTR_NOSECURITY
)
5250 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5251 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5252 if ((error
= namei(&nd
))) {
5257 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
5258 // LP64todo - fix this!
5259 auio
= uio_createwithbuffer(1, 0, spacetype
,
5260 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
5261 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
5264 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, &context
);
5268 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
5270 *retval
= (user_ssize_t
)attrsize
;
5276 * Retrieve the list of extended attribute names.
5278 #warning "code duplication"
5280 flistxattr(struct proc
*p
, struct flistxattr_args
*uap
, user_ssize_t
*retval
)
5283 struct vfs_context context
;
5285 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5286 size_t attrsize
= 0;
5288 char uio_buf
[ UIO_SIZEOF(1) ];
5290 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5293 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5296 if ( (error
= vnode_getwithref(vp
)) ) {
5300 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
5301 // LP64todo - fix this!
5302 auio
= uio_createwithbuffer(1, 0, spacetype
,
5303 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
5304 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
5306 context
.vc_proc
= p
;
5307 context
.vc_ucred
= kauth_cred_get();
5309 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, &context
);
5314 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
5316 *retval
= (user_ssize_t
)attrsize
;
5322 * Common routine to handle various flavors of statfs data heading out
5326 munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
5327 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
5328 boolean_t partial_copy
)
5331 int my_size
, copy_size
;
5334 struct user_statfs sfs
;
5335 my_size
= copy_size
= sizeof(sfs
);
5336 bzero(&sfs
, my_size
);
5337 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
5338 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
5339 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
5340 sfs
.f_bsize
= (user_long_t
)sfsp
->f_bsize
;
5341 sfs
.f_iosize
= (user_long_t
)sfsp
->f_iosize
;
5342 sfs
.f_blocks
= (user_long_t
)sfsp
->f_blocks
;
5343 sfs
.f_bfree
= (user_long_t
)sfsp
->f_bfree
;
5344 sfs
.f_bavail
= (user_long_t
)sfsp
->f_bavail
;
5345 sfs
.f_files
= (user_long_t
)sfsp
->f_files
;
5346 sfs
.f_ffree
= (user_long_t
)sfsp
->f_ffree
;
5347 sfs
.f_fsid
= sfsp
->f_fsid
;
5348 sfs
.f_owner
= sfsp
->f_owner
;
5349 strncpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
-1);
5350 strncpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
-1);
5351 strncpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
-1);
5354 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
5356 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
5360 my_size
= copy_size
= sizeof(sfs
);
5361 bzero(&sfs
, my_size
);
5363 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
5364 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
5365 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
5368 * It's possible for there to be more than 2^^31 blocks in the filesystem, so we
5369 * have to fudge the numbers here in that case. We inflate the blocksize in order
5370 * to reflect the filesystem size as best we can.
5372 if ((sfsp
->f_blocks
> LONG_MAX
)
5373 /* Hack for 4061702 . I think the real fix is for Carbon to
5374 * look for some volume capability and not depend on hidden
5375 * semantics agreed between a FS and carbon.
5376 * f_blocks, f_bfree, and f_bavail set to -1 is the trigger
5377 * for Carbon to set bNoVolumeSizes volume attribute.
5378 * Without this the webdavfs files cannot be copied onto
5379 * disk as they look huge. This change should not affect
5380 * XSAN as they should not setting these to -1..
5382 && (sfsp
->f_blocks
!= 0xffffffffffffffff)
5383 && (sfsp
->f_bfree
!= 0xffffffffffffffff)
5384 && (sfsp
->f_bavail
!= 0xffffffffffffffff)) {
5388 * Work out how far we have to shift the block count down to make it fit.
5389 * Note that it's possible to have to shift so far that the resulting
5390 * blocksize would be unreportably large. At that point, we will clip
5391 * any values that don't fit.
5393 * For safety's sake, we also ensure that f_iosize is never reported as
5394 * being smaller than f_bsize.
5396 for (shift
= 0; shift
< 32; shift
++) {
5397 if ((sfsp
->f_blocks
>> shift
) <= LONG_MAX
)
5399 if ((sfsp
->f_bsize
<< (shift
+ 1)) > LONG_MAX
)
5402 #define __SHIFT_OR_CLIP(x, s) ((((x) >> (s)) > LONG_MAX) ? LONG_MAX : ((x) >> (s)))
5403 sfs
.f_blocks
= (long)__SHIFT_OR_CLIP(sfsp
->f_blocks
, shift
);
5404 sfs
.f_bfree
= (long)__SHIFT_OR_CLIP(sfsp
->f_bfree
, shift
);
5405 sfs
.f_bavail
= (long)__SHIFT_OR_CLIP(sfsp
->f_bavail
, shift
);
5406 #undef __SHIFT_OR_CLIP
5407 sfs
.f_bsize
= (long)(sfsp
->f_bsize
<< shift
);
5408 sfs
.f_iosize
= lmax(sfsp
->f_iosize
, sfsp
->f_bsize
);
5410 /* filesystem is small enough to be reported honestly */
5411 sfs
.f_bsize
= (long)sfsp
->f_bsize
;
5412 sfs
.f_iosize
= (long)sfsp
->f_iosize
;
5413 sfs
.f_blocks
= (long)sfsp
->f_blocks
;
5414 sfs
.f_bfree
= (long)sfsp
->f_bfree
;
5415 sfs
.f_bavail
= (long)sfsp
->f_bavail
;
5417 sfs
.f_files
= (long)sfsp
->f_files
;
5418 sfs
.f_ffree
= (long)sfsp
->f_ffree
;
5419 sfs
.f_fsid
= sfsp
->f_fsid
;
5420 sfs
.f_owner
= sfsp
->f_owner
;
5421 strncpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
-1);
5422 strncpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
-1);
5423 strncpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
-1);
5426 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
5428 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
5431 if (sizep
!= NULL
) {
5438 * copy stat structure into user_stat structure.
5440 void munge_stat(struct stat
*sbp
, struct user_stat
*usbp
)
5442 usbp
->st_dev
= sbp
->st_dev
;
5443 usbp
->st_ino
= sbp
->st_ino
;
5444 usbp
->st_mode
= sbp
->st_mode
;
5445 usbp
->st_nlink
= sbp
->st_nlink
;
5446 usbp
->st_uid
= sbp
->st_uid
;
5447 usbp
->st_gid
= sbp
->st_gid
;
5448 usbp
->st_rdev
= sbp
->st_rdev
;
5449 #ifndef _POSIX_SOURCE
5450 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
5451 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
5452 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
5453 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
5454 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
5455 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
5457 usbp
->st_atime
= sbp
->st_atime
;
5458 usbp
->st_atimensec
= sbp
->st_atimensec
;
5459 usbp
->st_mtime
= sbp
->st_mtime
;
5460 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
5461 usbp
->st_ctime
= sbp
->st_ctime
;
5462 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
5464 usbp
->st_size
= sbp
->st_size
;
5465 usbp
->st_blocks
= sbp
->st_blocks
;
5466 usbp
->st_blksize
= sbp
->st_blksize
;
5467 usbp
->st_flags
= sbp
->st_flags
;
5468 usbp
->st_gen
= sbp
->st_gen
;
5469 usbp
->st_lspare
= sbp
->st_lspare
;
5470 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
5471 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];