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 <libkern/OSAtomic.h>
109 * The currently logged-in user, for ownership of files/directories whose on-disk
110 * permissions are ignored:
114 static int change_dir(struct nameidata
*ndp
, vfs_context_t ctx
);
115 static void checkdirs(struct vnode
*olddp
, vfs_context_t ctx
);
116 void enablequotas(struct mount
*mp
, vfs_context_t ctx
);
117 static int getfsstat_callback(mount_t mp
, void * arg
);
118 static int getutimes(user_addr_t usrtvp
, struct timespec
*tsp
);
119 static int setutimes(vfs_context_t ctx
, struct vnode
*vp
, const struct timespec
*ts
, int nullflag
);
120 static int sync_callback(mount_t
, void *);
121 static int munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
122 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
123 boolean_t partial_copy
);
125 __private_extern__
int sync_internal(void);
127 #ifdef __APPLE_API_OBSOLETE
129 int fd
; /* file descriptor of the target file */
130 struct vstat
*vsb
; /* vstat structure for returned info */
133 const char *path
; /* pathname of the target file */
134 struct vstat
*vsb
; /* vstat structure for returned info */
136 struct mkcomplex_args
{
137 const char *path
; /* pathname of the file to be created */
138 mode_t mode
; /* access mode for the newly created file */
139 u_long type
; /* format of the complex file */
142 const char *path
; /* pathname of the target file */
143 struct vstat
*vsb
; /* vstat structure for returned info */
146 int fstatv(struct proc
*p
, struct fstatv_args
*uap
, register_t
*retval
);
147 int lstatv(struct proc
*p
, struct lstatv_args
*uap
, register_t
*retval
);
148 int mkcomplex(struct proc
*p
, struct mkcomplex_args
*uap
, register_t
*retval
);
149 int statv(struct proc
*p
, struct statv_args
*uap
, register_t
*retval
);
151 #endif /* __APPLE_API_OBSOLETE */
154 extern int (**union_vnodeop_p
)(void *);
155 extern struct vnode
*union_dircache(struct vnode
*, struct proc
*);
158 /* counts number of mount and unmount operations */
159 unsigned int vfs_nummntops
=0;
161 extern struct fileops vnops
;
163 extern void mount_list_add(mount_t mp
);
164 extern void mount_list_remove(mount_t mp
);
165 extern int mount_refdrain(mount_t mp
);
166 extern int vcount(struct vnode
*vp
);
170 * Virtual File System System Calls
174 * Mount a file system.
178 mount(struct proc
*p
, register struct mount_args
*uap
, __unused register_t
*retval
)
181 struct vnode
*devvp
= NULLVP
;
182 struct vnode
*device_vnode
= NULLVP
;
184 struct vfstable
*vfsp
;
186 struct vnode_attr va
;
187 struct vfs_context context
;
189 struct nameidata nd1
;
190 char fstypename
[MFSNAMELEN
];
192 user_addr_t devpath
= USER_ADDR_NULL
;
193 user_addr_t fsmountargs
= uap
->data
;
198 boolean_t is_rwlock_locked
= FALSE
;
200 AUDIT_ARG(fflags
, uap
->flags
);
203 context
.vc_ucred
= kauth_cred_get();
204 is_64bit
= proc_is64bit(p
);
207 * Get vnode to be covered
209 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
210 UIO_USERSPACE
, uap
->path
, &context
);
216 if ((vp
->v_flag
& VROOT
) &&
217 (vp
->v_mount
->mnt_flag
& MNT_ROOTFS
))
218 uap
->flags
|= MNT_UPDATE
;
220 if (uap
->flags
& MNT_UPDATE
) {
221 if ((vp
->v_flag
& VROOT
) == 0) {
227 /* unmount in progress return error */
229 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
235 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
236 is_rwlock_locked
= TRUE
;
238 * We only allow the filesystem to be reloaded if it
239 * is currently mounted read-only.
241 if ((uap
->flags
& MNT_RELOAD
) &&
242 ((mp
->mnt_flag
& MNT_RDONLY
) == 0)) {
247 * Only root, or the user that did the original mount is
248 * permitted to update it.
250 if (mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(context
.vc_ucred
) &&
251 (error
= suser(context
.vc_ucred
, &p
->p_acflag
))) {
255 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV,
256 * and MNT_NOEXEC if mount point is already MNT_NOEXEC.
258 if (suser(context
.vc_ucred
, NULL
)) {
259 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
260 if (mp
->mnt_flag
& MNT_NOEXEC
)
261 uap
->flags
|= MNT_NOEXEC
;
266 uap
->flags
& (MNT_RELOAD
| MNT_FORCE
| MNT_UPDATE
);
268 vfsp
= mp
->mnt_vtable
;
272 * If the user is not root, ensure that they own the directory
273 * onto which we are attempting to mount.
276 VATTR_WANTED(&va
, va_uid
);
277 if ((error
= vnode_getattr(vp
, &va
, &context
)) ||
278 (va
.va_uid
!= kauth_cred_getuid(context
.vc_ucred
) &&
279 (error
= suser(context
.vc_ucred
, &p
->p_acflag
)))) {
283 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV, and
284 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
286 if (suser(context
.vc_ucred
, NULL
)) {
287 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
288 if (vp
->v_mount
->mnt_flag
& MNT_NOEXEC
)
289 uap
->flags
|= MNT_NOEXEC
;
291 if ( (error
= VNOP_FSYNC(vp
, MNT_WAIT
, &context
)) )
294 if ( (error
= buf_invalidateblks(vp
, BUF_WRITE_DATA
, 0, 0)) )
297 if (vp
->v_type
!= VDIR
) {
301 if ( (error
= copyinstr(uap
->type
, fstypename
, MFSNAMELEN
, &dummy
)) )
304 /* XXXAUDIT: Should we capture the type on the error path as well? */
305 AUDIT_ARG(text
, fstypename
);
307 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
308 if (!strcmp(vfsp
->vfc_name
, fstypename
))
315 if (ISSET(vp
->v_flag
, VMOUNT
) && (vp
->v_mountedhere
!= NULL
)) {
319 SET(vp
->v_flag
, VMOUNT
);
322 * Allocate and initialize the filesystem.
324 MALLOC_ZONE(mp
, struct mount
*, (u_long
)sizeof(struct mount
),
326 bzero((char *)mp
, (u_long
)sizeof(struct mount
));
329 /* Initialize the default IO constraints */
330 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
331 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
332 mp
->mnt_maxsegreadsize
= mp
->mnt_maxreadcnt
;
333 mp
->mnt_maxsegwritesize
= mp
->mnt_maxwritecnt
;
334 mp
->mnt_devblocksize
= DEV_BSIZE
;
336 TAILQ_INIT(&mp
->mnt_vnodelist
);
337 TAILQ_INIT(&mp
->mnt_workerqueue
);
338 TAILQ_INIT(&mp
->mnt_newvnodes
);
340 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
341 is_rwlock_locked
= TRUE
;
342 mp
->mnt_op
= vfsp
->vfc_vfsops
;
343 mp
->mnt_vtable
= vfsp
;
345 vfsp
->vfc_refcount
++;
347 //mp->mnt_stat.f_type = vfsp->vfc_typenum;
348 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
349 strncpy(mp
->mnt_vfsstat
.f_fstypename
, vfsp
->vfc_name
, MFSTYPENAMELEN
);
350 strncpy(mp
->mnt_vfsstat
.f_mntonname
, nd
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
351 mp
->mnt_vnodecovered
= vp
;
352 mp
->mnt_vfsstat
.f_owner
= kauth_cred_getuid(context
.vc_ucred
);
354 /* XXX 3762912 hack to support HFS filesystem 'owner' - filesystem may update later */
355 vfs_setowner(mp
, KAUTH_UID_NONE
, KAUTH_GID_NONE
);
359 * Set the mount level flags.
361 if (uap
->flags
& MNT_RDONLY
)
362 mp
->mnt_flag
|= MNT_RDONLY
;
363 else if (mp
->mnt_flag
& MNT_RDONLY
)
364 mp
->mnt_kern_flag
|= MNTK_WANTRDWR
;
365 mp
->mnt_flag
&= ~(MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
366 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
367 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
);
368 mp
->mnt_flag
|= uap
->flags
& (MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
369 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
370 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
|
373 if (vfsp
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
375 if ( (error
= copyin(fsmountargs
, (caddr_t
)&devpath
, sizeof(devpath
))) )
377 fsmountargs
+= sizeof(devpath
);
380 if ( (error
= copyin(fsmountargs
, (caddr_t
)&tmp
, sizeof(tmp
))) )
382 /* munge into LP64 addr */
383 devpath
= CAST_USER_ADDR_T(tmp
);
384 fsmountargs
+= sizeof(tmp
);
387 /* if it is not update and device name needs to be parsed */
389 NDINIT(&nd1
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, devpath
, &context
);
390 if ( (error
= namei(&nd1
)) )
393 strncpy(mp
->mnt_vfsstat
.f_mntfromname
, nd1
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
398 if (devvp
->v_type
!= VBLK
) {
402 if (major(devvp
->v_rdev
) >= nblkdev
) {
407 * If mount by non-root, then verify that user has necessary
408 * permissions on the device.
410 if (suser(context
.vc_ucred
, NULL
) != 0) {
411 accessmode
= KAUTH_VNODE_READ_DATA
;
412 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
413 accessmode
|= KAUTH_VNODE_WRITE_DATA
;
414 if ((error
= vnode_authorize(devvp
, NULL
, accessmode
, &context
)) != 0)
418 if (devpath
&& ((uap
->flags
& MNT_UPDATE
) == 0)) {
419 if ( (error
= vnode_ref(devvp
)) )
422 * Disallow multiple mounts of the same device.
423 * Disallow mounting of a device that is currently in use
424 * (except for root, which might share swap device for miniroot).
425 * Flush out any old buffers remaining from a previous use.
427 if ( (error
= vfs_mountedon(devvp
)) )
430 if (vcount(devvp
) > 1 && !(vfs_flags(mp
) & MNT_ROOTFS
)) {
434 if ( (error
= VNOP_FSYNC(devvp
, MNT_WAIT
, &context
)) ) {
438 if ( (error
= buf_invalidateblks(devvp
, BUF_WRITE_DATA
, 0, 0)) )
441 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
442 if ( (error
= VNOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, &context
)) )
445 mp
->mnt_devvp
= devvp
;
446 device_vnode
= devvp
;
448 if ((mp
->mnt_flag
& MNT_RDONLY
) && (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)) {
450 * If upgrade to read-write by non-root, then verify
451 * that user has necessary permissions on the device.
453 device_vnode
= mp
->mnt_devvp
;
454 if (device_vnode
&& suser(context
.vc_ucred
, NULL
)) {
455 if ((error
= vnode_authorize(device_vnode
, NULL
,
456 KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0)
460 device_vnode
= NULLVP
;
466 * Mount the filesystem.
468 error
= VFS_MOUNT(mp
, device_vnode
, fsmountargs
, &context
);
470 if (uap
->flags
& MNT_UPDATE
) {
471 if (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)
472 mp
->mnt_flag
&= ~MNT_RDONLY
;
474 (MNT_UPDATE
| MNT_RELOAD
| MNT_FORCE
);
475 mp
->mnt_kern_flag
&=~ MNTK_WANTRDWR
;
478 vfs_event_signal(NULL
, VQ_UPDATE
, (intptr_t)NULL
);
479 lck_rw_done(&mp
->mnt_rwlock
);
480 is_rwlock_locked
= FALSE
;
482 enablequotas(mp
,&context
);
486 * Put the new filesystem on the mount list after root.
489 CLR(vp
->v_flag
, VMOUNT
);
492 vp
->v_mountedhere
= mp
;
497 vfs_event_signal(NULL
, VQ_MOUNT
, (intptr_t)NULL
);
498 checkdirs(vp
, &context
);
499 lck_rw_done(&mp
->mnt_rwlock
);
500 is_rwlock_locked
= FALSE
;
503 * there is no cleanup code here so I have made it void
504 * we need to revisit this
506 (void)VFS_START(mp
, 0, &context
);
508 /* increment the operations count */
509 OSAddAtomic(1, (SInt32
*)&vfs_nummntops
);
510 enablequotas(mp
,&context
);
513 device_vnode
->v_specflags
|= SI_MOUNTEDON
;
516 * cache the IO attributes for the underlying physical media...
517 * an error return indicates the underlying driver doesn't
518 * support all the queries necessary... however, reasonable
519 * defaults will have been set, so no reason to bail or care
521 vfs_init_io_attributes(device_vnode
, mp
);
524 CLR(vp
->v_flag
, VMOUNT
);
526 mp
->mnt_vtable
->vfc_refcount
--;
530 VNOP_CLOSE(device_vnode
, ronly
? FREAD
: FREAD
|FWRITE
, &context
);
531 vnode_rele(device_vnode
);
533 lck_rw_done(&mp
->mnt_rwlock
);
534 is_rwlock_locked
= FALSE
;
535 mount_lock_destroy(mp
);
536 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
541 * drop I/O count on covered 'vp' and
542 * on the device vp if there was one
544 if (devpath
&& devvp
)
553 if (devpath
&& devvp
)
556 /* Release mnt_rwlock only when it was taken */
557 if (is_rwlock_locked
== TRUE
) {
558 lck_rw_done(&mp
->mnt_rwlock
);
561 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
570 enablequotas(struct mount
*mp
, vfs_context_t context
)
572 struct nameidata qnd
;
574 char qfpath
[MAXPATHLEN
];
575 const char *qfname
= QUOTAFILENAME
;
576 const char *qfopsname
= QUOTAOPSNAME
;
577 const char *qfextension
[] = INITQFNAMES
;
579 if ((strcmp(mp
->mnt_vfsstat
.f_fstypename
, "hfs") != 0 )
580 && (strcmp( mp
->mnt_vfsstat
.f_fstypename
, "ufs") != 0))
584 * Enable filesystem disk quotas if necessary.
585 * We ignore errors as this should not interfere with final mount
587 for (type
=0; type
< MAXQUOTAS
; type
++) {
588 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfopsname
, qfextension
[type
]);
589 NDINIT(&qnd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE32
, CAST_USER_ADDR_T(qfpath
), context
);
590 if (namei(&qnd
) != 0)
591 continue; /* option file to trigger quotas is not present */
592 vnode_put(qnd
.ni_vp
);
594 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfname
, qfextension
[type
]);
596 (void) VFS_QUOTACTL(mp
, QCMD(Q_QUOTAON
, type
), 0, qfpath
, context
);
602 * Scan all active processes to see if any of them have a current
603 * or root directory onto which the new filesystem has just been
604 * mounted. If so, replace them with the new mount point.
607 checkdirs(olddp
, context
)
609 vfs_context_t context
;
611 struct filedesc
*fdp
;
615 struct vnode
*fdp_cvp
;
616 struct vnode
*fdp_rvp
;
617 int cdir_changed
= 0;
618 int rdir_changed
= 0;
619 boolean_t funnel_state
;
621 if (olddp
->v_usecount
== 1)
623 if (VFS_ROOT(olddp
->v_mountedhere
, &newdp
, context
))
624 panic("mount: lost mount");
625 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
627 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
630 if (fdp
== (struct filedesc
*)0) {
634 fdp_cvp
= fdp
->fd_cdir
;
635 fdp_rvp
= fdp
->fd_rdir
;
638 if (fdp_cvp
== olddp
) {
645 if (fdp_rvp
== olddp
) {
652 if (cdir_changed
|| rdir_changed
) {
654 fdp
->fd_cdir
= fdp_cvp
;
655 fdp
->fd_rdir
= fdp_rvp
;
659 if (rootvnode
== olddp
) {
665 thread_funnel_set(kernel_flock
, funnel_state
);
671 * Unmount a file system.
673 * Note: unmount takes a path to the vnode mounted on as argument,
674 * not special file (as before).
678 unmount(struct proc
*p
, register struct unmount_args
*uap
, __unused register_t
*retval
)
680 register struct vnode
*vp
;
684 struct vfs_context context
;
687 context
.vc_ucred
= kauth_cred_get();
689 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
690 UIO_USERSPACE
, uap
->path
, &context
);
699 * Must be the root of the filesystem
701 if ((vp
->v_flag
& VROOT
) == 0) {
706 return (safedounmount(mp
, uap
->flags
, p
));
710 * Do the actual file system unmount, prevent some common foot shooting.
712 * XXX Should take a "vfs_context_t" instead of a "struct proc *"
715 safedounmount(mp
, flags
, p
)
723 * Only root, or the user that did the original mount is
724 * permitted to unmount this filesystem.
726 if ((mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(kauth_cred_get())) &&
727 (error
= suser(kauth_cred_get(), &p
->p_acflag
)))
731 * Don't allow unmounting the root file system.
733 if (mp
->mnt_flag
& MNT_ROOTFS
)
734 return (EBUSY
); /* the root is always busy */
736 return (dounmount(mp
, flags
, NULL
, p
));
740 * Do the actual file system unmount.
743 dounmount(mp
, flags
, skiplistrmp
, p
)
744 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.
774 if (skiplistrmp
!= NULL
)
778 mp
->mnt_kern_flag
|= MNTK_UNMOUNT
;
779 mp
->mnt_lflag
|= MNT_LUNMOUNT
;
780 mp
->mnt_flag
&=~ MNT_ASYNC
;
782 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
783 fsevent_unmount(mp
); /* has to come first! */
785 if (forcedunmount
== 0) {
786 ubc_umount(mp
); /* release cached vnodes */
787 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
788 error
= VFS_SYNC(mp
, MNT_WAIT
, &context
);
791 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
792 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
793 mp
->mnt_lflag
&= ~MNT_LFORCE
;
800 lflags
|= FORCECLOSE
;
801 error
= vflush(mp
, NULLVP
, SKIPSWAP
| SKIPSYSTEM
| SKIPROOT
| lflags
);
802 if ((forcedunmount
== 0) && error
) {
804 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
805 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
806 mp
->mnt_lflag
&= ~MNT_LFORCE
;
810 /* make sure there are no one in the mount iterations or lookup */
813 error
= VFS_UNMOUNT(mp
, flags
, &context
);
817 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
818 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
819 mp
->mnt_lflag
&= ~MNT_LFORCE
;
823 /* increment the operations count */
825 OSAddAtomic(1, (SInt32
*)&vfs_nummntops
);
827 if ( mp
->mnt_devvp
&& mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
828 mp
->mnt_devvp
->v_specflags
&= ~SI_MOUNTEDON
;
829 VNOP_CLOSE(mp
->mnt_devvp
, mp
->mnt_flag
& MNT_RDONLY
? FREAD
: FREAD
|FWRITE
,
831 vnode_rele(mp
->mnt_devvp
);
833 lck_rw_done(&mp
->mnt_rwlock
);
834 mount_list_remove(mp
);
835 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
837 /* mark the mount point hook in the vp but not drop the ref yet */
838 if ((coveredvp
= mp
->mnt_vnodecovered
) != NULLVP
) {
839 vnode_getwithref(coveredvp
);
840 vnode_lock(coveredvp
);
841 coveredvp
->v_mountedhere
= (struct mount
*)0;
842 vnode_unlock(coveredvp
);
843 vnode_put(coveredvp
);
847 mp
->mnt_vtable
->vfc_refcount
--;
850 cache_purgevfs(mp
); /* remove cache entries for this file sys */
851 vfs_event_signal(NULL
, VQ_UNMOUNT
, (intptr_t)NULL
);
853 mp
->mnt_lflag
|= MNT_LDEAD
;
855 if (mp
->mnt_lflag
& MNT_LWAIT
) {
858 * in case we block in mount_refdrain
859 * which will drop the mount lock
860 * and allow anyone blocked in vfs_busy
861 * to wakeup and see the LDEAD state
863 mp
->mnt_lflag
&= ~MNT_LWAIT
;
868 if (mp
->mnt_lflag
& MNT_LWAIT
) {
869 mp
->mnt_lflag
&= ~MNT_LWAIT
;
873 lck_rw_done(&mp
->mnt_rwlock
);
878 if ((coveredvp
!= NULLVP
)) {
879 vnode_getwithref(coveredvp
);
880 vnode_rele(coveredvp
);
881 vnode_lock(coveredvp
);
882 if(mp
->mnt_crossref
== 0) {
883 vnode_unlock(coveredvp
);
884 mount_lock_destroy(mp
);
885 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
887 coveredvp
->v_lflag
|= VL_MOUNTDEAD
;
888 vnode_unlock(coveredvp
);
890 vnode_put(coveredvp
);
891 } else if (mp
->mnt_flag
& MNT_ROOTFS
) {
892 mount_lock_destroy(mp
);
893 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
895 panic("dounmount: no coveredvp");
901 mount_dropcrossref(mount_t mp
, vnode_t dp
, int need_put
)
905 if (mp
->mnt_crossref
< 0)
906 panic("mount cross refs -ve");
907 if (((dp
->v_lflag
& VL_MOUNTDEAD
) == VL_MOUNTDEAD
) && (mp
->mnt_crossref
== 0)) {
908 dp
->v_lflag
&= ~VL_MOUNTDEAD
;
910 vnode_put_locked(dp
);
912 mount_lock_destroy(mp
);
913 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
917 vnode_put_locked(dp
);
923 * Sync each mounted filesystem.
927 struct ctldebug debug0
= { "syncprt", &syncprt
};
930 int print_vmpage_stat
=0;
933 sync_callback(mount_t mp
, __unused
void * arg
)
935 struct proc
* p
= current_proc();
937 struct vfs_context context
;
940 context
.vc_ucred
= kauth_cred_get();
942 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
943 asyncflag
= mp
->mnt_flag
& MNT_ASYNC
;
944 mp
->mnt_flag
&= ~MNT_ASYNC
;
945 VFS_SYNC(mp
, MNT_NOWAIT
, &context
);
947 mp
->mnt_flag
|= MNT_ASYNC
;
949 return(VFS_RETURNED
);
953 extern unsigned int vp_pagein
, vp_pgodirty
, vp_pgoclean
;
954 extern unsigned int dp_pgins
, dp_pgouts
;
958 sync(__unused
struct proc
*p
, __unused
struct sync_args
*uap
, __unused register_t
*retval
)
961 vfs_iterate(LK_NOWAIT
, sync_callback
, (void *)0);
963 if(print_vmpage_stat
) {
964 vm_countdirtypages();
965 printf("VP: %d: %d: %d: %d: %d\n", vp_pgodirty
, vp_pgoclean
, vp_pagein
,
966 dp_pgins
, dp_pgouts
);
972 #endif /* DIAGNOSTIC */
977 * Change filesystem quotas.
981 quotactl(struct proc
*p
, register struct quotactl_args
*uap
, __unused register_t
*retval
)
983 register struct mount
*mp
;
984 int error
, quota_cmd
, quota_status
;
988 struct vfs_context context
;
989 struct dqblk my_dqblk
;
992 context
.vc_ucred
= kauth_cred_get();
994 AUDIT_ARG(uid
, uap
->uid
, 0, 0, 0);
995 AUDIT_ARG(cmd
, uap
->cmd
);
996 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
997 UIO_USERSPACE
, uap
->path
, &context
);
1001 mp
= nd
.ni_vp
->v_mount
;
1002 vnode_put(nd
.ni_vp
);
1005 /* copyin any data we will need for downstream code */
1006 quota_cmd
= uap
->cmd
>> SUBCMDSHIFT
;
1008 switch (quota_cmd
) {
1010 /* uap->arg specifies a file from which to take the quotas */
1011 fnamelen
= MAXPATHLEN
;
1012 datap
= kalloc(MAXPATHLEN
);
1013 error
= copyinstr(uap
->arg
, datap
, MAXPATHLEN
, &fnamelen
);
1016 /* uap->arg is a pointer to a dqblk structure. */
1017 datap
= (caddr_t
) &my_dqblk
;
1021 /* uap->arg is a pointer to a dqblk structure. */
1022 datap
= (caddr_t
) &my_dqblk
;
1023 if (proc_is64bit(p
)) {
1024 struct user_dqblk my_dqblk64
;
1025 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk64
, sizeof (my_dqblk64
));
1027 munge_dqblk(&my_dqblk
, &my_dqblk64
, FALSE
);
1031 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk
, sizeof (my_dqblk
));
1035 /* uap->arg is a pointer to an integer */
1036 datap
= (caddr_t
) "a_status
;
1044 error
= VFS_QUOTACTL(mp
, uap
->cmd
, uap
->uid
, datap
, &context
);
1047 switch (quota_cmd
) {
1050 kfree(datap
, MAXPATHLEN
);
1053 /* uap->arg is a pointer to a dqblk structure we need to copy out to */
1055 if (proc_is64bit(p
)) {
1056 struct user_dqblk my_dqblk64
;
1057 munge_dqblk(&my_dqblk
, &my_dqblk64
, TRUE
);
1058 error
= copyout((caddr_t
)&my_dqblk64
, uap
->arg
, sizeof (my_dqblk64
));
1061 error
= copyout(datap
, uap
->arg
, sizeof (struct dqblk
));
1066 /* uap->arg is a pointer to an integer */
1068 error
= copyout(datap
, uap
->arg
, sizeof(quota_status
));
1079 * Get filesystem statistics.
1083 statfs(struct proc
*p
, register struct statfs_args
*uap
, __unused register_t
*retval
)
1086 struct vfsstatfs
*sp
;
1088 struct nameidata nd
;
1089 struct vfs_context context
;
1092 context
.vc_proc
= p
;
1093 context
.vc_ucred
= kauth_cred_get();
1095 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1096 UIO_USERSPACE
, uap
->path
, &context
);
1102 sp
= &mp
->mnt_vfsstat
;
1105 error
= vfs_update_vfsstat(mp
, &context
);
1110 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1115 * Get filesystem statistics.
1119 fstatfs(struct proc
*p
, register struct fstatfs_args
*uap
, __unused register_t
*retval
)
1123 struct vfsstatfs
*sp
;
1125 struct vfs_context context
;
1127 context
.vc_proc
= p
;
1128 context
.vc_ucred
= kauth_cred_get();
1130 AUDIT_ARG(fd
, uap
->fd
);
1132 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1135 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
1142 sp
= &mp
->mnt_vfsstat
;
1143 if ((error
= vfs_update_vfsstat(mp
, &context
)) != 0) {
1149 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1155 struct getfsstat_struct
{
1165 getfsstat_callback(mount_t mp
, void * arg
)
1168 struct getfsstat_struct
*fstp
= (struct getfsstat_struct
*)arg
;
1169 struct vfsstatfs
*sp
;
1170 struct proc
* p
= current_proc();
1172 struct vfs_context context
;
1174 context
.vc_proc
= p
;
1175 context
.vc_ucred
= kauth_cred_get();
1177 if (fstp
->sfsp
&& fstp
->count
< fstp
->maxcount
) {
1178 sp
= &mp
->mnt_vfsstat
;
1180 * If MNT_NOWAIT is specified, do not refresh the
1181 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
1183 if (((fstp
->flags
& MNT_NOWAIT
) == 0 || (fstp
->flags
& MNT_WAIT
)) &&
1184 (error
= vfs_update_vfsstat(mp
, &context
))) {
1185 KAUTH_DEBUG("vfs_update_vfsstat returned %d", error
);
1186 return(VFS_RETURNED
);
1190 * Need to handle LP64 version of struct statfs
1192 error
= munge_statfs(mp
, sp
, fstp
->sfsp
, &my_size
, IS_64BIT_PROCESS(p
), FALSE
);
1194 fstp
->error
= error
;
1195 return(VFS_RETURNED_DONE
);
1197 fstp
->sfsp
+= my_size
;
1200 return(VFS_RETURNED
);
1204 * Get statistics on all filesystems.
1207 getfsstat(__unused proc_t p
, struct getfsstat_args
*uap
, int *retval
)
1210 int count
, maxcount
;
1211 struct getfsstat_struct fst
;
1213 if (IS_64BIT_PROCESS(p
)) {
1214 maxcount
= uap
->bufsize
/ sizeof(struct user_statfs
);
1217 maxcount
= uap
->bufsize
/ sizeof(struct statfs
);
1223 fst
.flags
= uap
->flags
;
1226 fst
.maxcount
= maxcount
;
1229 vfs_iterate(0, getfsstat_callback
, &fst
);
1232 KAUTH_DEBUG("ERROR - %s gets %d", p
->p_comm
, fst
.error
);
1236 if (fst
.sfsp
&& fst
.count
> fst
.maxcount
)
1237 *retval
= fst
.maxcount
;
1239 *retval
= fst
.count
;
1243 #if COMPAT_GETFSSTAT
1244 ogetfsstat(p
, uap
, retval
)
1246 register struct getfsstat_args
*uap
;
1254 * Change current working directory to a given file descriptor.
1258 fchdir(struct proc
*p
, struct fchdir_args
*uap
, __unused register_t
*retval
)
1260 register struct filedesc
*fdp
= p
->p_fd
;
1261 struct vnode
*vp
, *tdp
, *tvp
;
1264 struct vfs_context context
;
1266 context
.vc_proc
= p
;
1267 context
.vc_ucred
= kauth_cred_get();
1269 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1271 if ( (error
= vnode_getwithref(vp
)) ) {
1276 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
1278 if (vp
->v_type
!= VDIR
)
1281 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, &context
);
1282 while (!error
&& (mp
= vp
->v_mountedhere
) != NULL
) {
1283 if (vfs_busy(mp
, LK_NOWAIT
)) {
1287 error
= VFS_ROOT(mp
, &tdp
, &context
);
1296 if ( (error
= vnode_ref(vp
)) )
1318 * Change current working directory (``.'').
1322 chdir(struct proc
*p
, struct chdir_args
*uap
, __unused register_t
*retval
)
1324 register struct filedesc
*fdp
= p
->p_fd
;
1326 struct nameidata nd
;
1328 struct vfs_context context
;
1330 context
.vc_proc
= p
;
1331 context
.vc_ucred
= kauth_cred_get();
1333 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1334 UIO_USERSPACE
, uap
->path
, &context
);
1335 error
= change_dir(&nd
, &context
);
1338 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
1339 vnode_put(nd
.ni_vp
);
1343 * drop the iocount we picked up in change_dir
1345 vnode_put(nd
.ni_vp
);
1349 fdp
->fd_cdir
= nd
.ni_vp
;
1359 * Change notion of root (``/'') directory.
1363 chroot(struct proc
*p
, struct chroot_args
*uap
, __unused register_t
*retval
)
1365 register struct filedesc
*fdp
= p
->p_fd
;
1367 struct nameidata nd
;
1368 boolean_t shared_regions_active
;
1370 struct vfs_context context
;
1372 context
.vc_proc
= p
;
1373 context
.vc_ucred
= kauth_cred_get();
1375 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
1378 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1379 UIO_USERSPACE
, uap
->path
, &context
);
1380 error
= change_dir(&nd
, &context
);
1384 if(p
->p_flag
& P_NOSHLIB
) {
1385 shared_regions_active
= FALSE
;
1387 shared_regions_active
= TRUE
;
1389 if ((error
= clone_system_shared_regions(shared_regions_active
,
1390 TRUE
, /* chain_regions */
1392 vnode_put(nd
.ni_vp
);
1395 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
1396 vnode_put(nd
.ni_vp
);
1399 vnode_put(nd
.ni_vp
);
1403 fdp
->fd_rdir
= nd
.ni_vp
;
1404 fdp
->fd_flags
|= FD_CHROOT
;
1414 * Common routine for chroot and chdir.
1417 change_dir(struct nameidata
*ndp
, vfs_context_t ctx
)
1422 if ((error
= namei(ndp
)))
1426 if (vp
->v_type
!= VDIR
)
1429 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, ctx
);
1437 * Check permissions, allocate an open file structure,
1438 * and call the device open routine if any.
1441 #warning XXX implement uid, gid
1443 open1(vfs_context_t ctx
, user_addr_t upath
, int uflags
, struct vnode_attr
*vap
, register_t
*retval
)
1445 struct proc
*p
= vfs_context_proc(ctx
);
1446 register struct filedesc
*fdp
= p
->p_fd
;
1447 register struct fileproc
*fp
;
1448 register struct vnode
*vp
;
1450 struct fileproc
*nfp
;
1451 int type
, indx
, error
;
1453 struct nameidata nd
;
1457 if ((oflags
& O_ACCMODE
) == O_ACCMODE
)
1459 flags
= FFLAGS(uflags
);
1461 AUDIT_ARG(fflags
, oflags
);
1462 AUDIT_ARG(mode
, vap
->va_mode
);
1464 if ( (error
= falloc(p
, &nfp
, &indx
)) ) {
1468 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1469 UIO_USERSPACE
, upath
, ctx
);
1470 p
->p_dupfd
= -indx
- 1; /* XXX check for fdopen */
1472 if ((error
= vn_open_auth(&nd
, &flags
, vap
))) {
1473 if ((error
== ENODEV
|| error
== ENXIO
) && (p
->p_dupfd
>= 0)) { /* XXX from fdopen */
1474 if ((error
= dupfdopen(fdp
, indx
, p
->p_dupfd
, flags
, error
)) == 0) {
1475 fp_drop(p
, indx
, 0, 0);
1480 if (error
== ERESTART
)
1482 fp_free(p
, indx
, fp
);
1489 fp
->f_fglob
->fg_flag
= flags
& (FMASK
| O_EVTONLY
);
1490 fp
->f_fglob
->fg_type
= DTYPE_VNODE
;
1491 fp
->f_fglob
->fg_ops
= &vnops
;
1492 fp
->f_fglob
->fg_data
= (caddr_t
)vp
;
1494 if (flags
& (O_EXLOCK
| O_SHLOCK
)) {
1495 lf
.l_whence
= SEEK_SET
;
1498 if (flags
& O_EXLOCK
)
1499 lf
.l_type
= F_WRLCK
;
1501 lf
.l_type
= F_RDLCK
;
1503 if ((flags
& FNONBLOCK
) == 0)
1505 if ((error
= VNOP_ADVLOCK(vp
, (caddr_t
)fp
->f_fglob
, F_SETLK
, &lf
, type
, ctx
)))
1507 fp
->f_fglob
->fg_flag
|= FHASLOCK
;
1510 /* try to truncate by setting the size attribute */
1511 if ((flags
& O_TRUNC
) && ((error
= vnode_setsize(vp
, (off_t
)0, 0, ctx
)) != 0))
1517 *fdflags(p
, indx
) &= ~UF_RESERVED
;
1518 fp_drop(p
, indx
, fp
, 1);
1525 vn_close(vp
, fp
->f_fglob
->fg_flag
, fp
->f_fglob
->fg_cred
, p
);
1527 fp_free(p
, indx
, fp
);
1534 * An open system call using an extended argument list compared to the regular
1535 * system call 'open'.
1537 * Parameters: p Process requesting the open
1538 * uap User argument descriptor (see below)
1539 * retval Pointer to an area to receive the
1540 * return calue from the system call
1542 * Indirect: uap->path Path to open (same as 'open')
1543 * uap->flags Flags to open (same as 'open'
1544 * uap->uid UID to set, if creating
1545 * uap->gid GID to set, if creating
1546 * uap->mode File mode, if creating (same as 'open')
1547 * uap->xsecurity ACL to set, if creating
1549 * Returns: 0 Success
1552 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
1554 * XXX: We should enummerate the possible errno values here, and where
1555 * in the code they originated.
1558 open_extended(struct proc
*p
, struct open_extended_args
*uap
, register_t
*retval
)
1560 struct vfs_context context
;
1561 register struct filedesc
*fdp
= p
->p_fd
;
1563 kauth_filesec_t xsecdst
;
1564 struct vnode_attr va
;
1568 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
1569 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
1572 context
.vc_proc
= p
;
1573 context
.vc_ucred
= kauth_cred_get();
1576 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
1577 VATTR_SET(&va
, va_mode
, cmode
);
1578 if (uap
->uid
!= KAUTH_UID_NONE
)
1579 VATTR_SET(&va
, va_uid
, uap
->uid
);
1580 if (uap
->gid
!= KAUTH_GID_NONE
)
1581 VATTR_SET(&va
, va_gid
, uap
->gid
);
1582 if (xsecdst
!= NULL
)
1583 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
1585 ciferror
= open1(&context
, uap
->path
, uap
->flags
, &va
, retval
);
1586 if (xsecdst
!= NULL
)
1587 kauth_filesec_free(xsecdst
);
1593 open(struct proc
*p
, struct open_args
*uap
, register_t
*retval
)
1595 struct vfs_context context
;
1596 register struct filedesc
*fdp
= p
->p_fd
;
1597 struct vnode_attr va
;
1600 context
.vc_proc
= p
;
1601 context
.vc_ucred
= kauth_cred_get();
1604 /* Mask off all but regular access permissions */
1605 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
1606 VATTR_SET(&va
, va_mode
, cmode
& ACCESSPERMS
);
1608 return(open1(&context
, uap
->path
, uap
->flags
, &va
, retval
));
1613 * Create a special file.
1615 static int mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
);
1618 mknod(struct proc
*p
, register struct mknod_args
*uap
, __unused register_t
*retval
)
1620 struct vnode_attr va
;
1621 struct vfs_context context
;
1624 struct nameidata nd
;
1627 context
.vc_proc
= p
;
1628 context
.vc_ucred
= kauth_cred_get();
1631 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1632 VATTR_SET(&va
, va_rdev
, uap
->dev
);
1634 /* If it's a mknod() of a FIFO, call mkfifo1() instead */
1635 if ((uap
->mode
& S_IFMT
) == S_IFIFO
)
1636 return(mkfifo1(&context
, uap
->path
, &va
));
1638 AUDIT_ARG(mode
, uap
->mode
);
1639 AUDIT_ARG(dev
, uap
->dev
);
1641 if ((error
= suser(context
.vc_ucred
, &p
->p_acflag
)))
1643 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1644 UIO_USERSPACE
, uap
->path
, &context
);
1656 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
1659 switch (uap
->mode
& S_IFMT
) {
1660 case S_IFMT
: /* used by badsect to flag bad sectors */
1661 VATTR_SET(&va
, va_type
, VBAD
);
1664 VATTR_SET(&va
, va_type
, VCHR
);
1667 VATTR_SET(&va
, va_type
, VBLK
);
1677 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, CREATE
, &context
);
1679 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, &va
, 0, &context
);
1685 int update_flags
= 0;
1687 // Make sure the name & parent pointers are hooked up
1688 if (vp
->v_name
== NULL
)
1689 update_flags
|= VNODE_UPDATE_NAME
;
1690 if (vp
->v_parent
== NULLVP
)
1691 update_flags
|= VNODE_UPDATE_PARENT
;
1694 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
1696 add_fsevent(FSE_CREATE_FILE
, &context
,
1703 * nameidone has to happen before we vnode_put(dvp)
1704 * since it may need to release the fs_nodelock on the dvp
1716 * Create a named pipe.
1719 mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
)
1723 struct nameidata nd
;
1725 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1726 UIO_USERSPACE
, upath
, ctx
);
1733 /* check that this is a new file and authorize addition */
1738 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
1741 VATTR_SET(vap
, va_type
, VFIFO
);
1743 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
);
1746 * nameidone has to happen before we vnode_put(dvp)
1747 * since it may need to release the fs_nodelock on the dvp
1760 * A mkfifo system call using an extended argument list compared to the regular
1761 * system call 'mkfifo'.
1763 * Parameters: p Process requesting the open
1764 * uap User argument descriptor (see below)
1767 * Indirect: uap->path Path to fifo (same as 'mkfifo')
1768 * uap->uid UID to set
1769 * uap->gid GID to set
1770 * uap->mode File mode to set (same as 'mkfifo')
1771 * uap->xsecurity ACL to set, if creating
1773 * Returns: 0 Success
1776 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
1778 * XXX: We should enummerate the possible errno values here, and where
1779 * in the code they originated.
1782 mkfifo_extended(struct proc
*p
, struct mkfifo_extended_args
*uap
, __unused register_t
*retval
)
1785 kauth_filesec_t xsecdst
;
1786 struct vfs_context context
;
1787 struct vnode_attr va
;
1789 xsecdst
= KAUTH_FILESEC_NONE
;
1790 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
1791 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
1795 context
.vc_proc
= p
;
1796 context
.vc_ucred
= kauth_cred_get();
1799 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1800 if (uap
->uid
!= KAUTH_UID_NONE
)
1801 VATTR_SET(&va
, va_uid
, uap
->uid
);
1802 if (uap
->gid
!= KAUTH_GID_NONE
)
1803 VATTR_SET(&va
, va_gid
, uap
->gid
);
1804 if (xsecdst
!= KAUTH_FILESEC_NONE
)
1805 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
1807 ciferror
= mkfifo1(&context
, uap
->path
, &va
);
1809 if (xsecdst
!= KAUTH_FILESEC_NONE
)
1810 kauth_filesec_free(xsecdst
);
1816 mkfifo(struct proc
*p
, register struct mkfifo_args
*uap
, __unused register_t
*retval
)
1818 struct vfs_context context
;
1819 struct vnode_attr va
;
1821 context
.vc_proc
= p
;
1822 context
.vc_ucred
= kauth_cred_get();
1825 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1827 return(mkfifo1(&context
, uap
->path
, &va
));
1831 * Make a hard file link.
1835 link(struct proc
*p
, register struct link_args
*uap
, __unused register_t
*retval
)
1837 vnode_t vp
, dvp
, lvp
;
1838 struct nameidata nd
;
1839 struct vfs_context context
;
1842 int need_event
, has_listeners
;
1844 context
.vc_proc
= p
;
1845 context
.vc_ucred
= kauth_cred_get();
1846 vp
= dvp
= lvp
= NULLVP
;
1848 /* look up the object we are linking to */
1849 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1850 UIO_USERSPACE
, uap
->path
, &context
);
1858 /* we're not allowed to link to directories */
1859 if (vp
->v_type
== VDIR
) {
1860 error
= EPERM
; /* POSIX */
1864 /* or to anything that kauth doesn't want us to (eg. immutable items) */
1865 if ((error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_LINKTARGET
, &context
)) != 0)
1868 /* lookup the target node */
1869 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1870 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| AUDITVNPATH2
;
1871 nd
.ni_dirp
= uap
->link
;
1877 /* target node must not exist */
1878 if (lvp
!= NULLVP
) {
1882 /* cannot link across mountpoints */
1883 if (vnode_mount(vp
) != vnode_mount(dvp
)) {
1888 /* authorize creation of the target note */
1889 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
1892 /* and finally make the link */
1893 error
= VNOP_LINK(vp
, dvp
, &nd
.ni_cnd
, &context
);
1897 need_event
= need_fsevent(FSE_CREATE_FILE
, dvp
);
1898 has_listeners
= kauth_authorize_fileop_has_listeners();
1900 if (need_event
|| has_listeners
) {
1901 char *target_path
= NULL
;
1902 char *link_to_path
= NULL
;
1903 int len
, link_name_len
;
1905 /* build the path to the new link file */
1906 target_path
= get_pathbuff();
1908 vn_getpath(dvp
, target_path
, &len
);
1909 target_path
[len
-1] = '/';
1910 strcpy(&target_path
[len
], nd
.ni_cnd
.cn_nameptr
);
1911 len
+= nd
.ni_cnd
.cn_namelen
;
1913 if (has_listeners
) {
1914 /* build the path to file we are linking to */
1915 link_to_path
= get_pathbuff();
1916 link_name_len
= MAXPATHLEN
;
1917 vn_getpath(vp
, link_to_path
, &link_name_len
);
1919 /* call out to allow 3rd party notification of rename.
1920 * Ignore result of kauth_authorize_fileop call.
1922 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_LINK
,
1923 (uintptr_t)link_to_path
, (uintptr_t)target_path
);
1924 if (link_to_path
!= NULL
)
1925 release_pathbuff(link_to_path
);
1928 /* construct fsevent */
1929 if (get_fse_info(vp
, &finfo
, &context
) == 0) {
1930 // build the path to the destination of the link
1931 add_fsevent(FSE_CREATE_FILE
, &context
,
1932 FSE_ARG_STRING
, len
, target_path
,
1933 FSE_ARG_FINFO
, &finfo
,
1937 release_pathbuff(target_path
);
1941 * nameidone has to happen before we vnode_put(dvp)
1942 * since it may need to release the fs_nodelock on the dvp
1955 * Make a symbolic link.
1957 * We could add support for ACLs here too...
1961 symlink(struct proc
*p
, register struct symlink_args
*uap
, __unused register_t
*retval
)
1963 struct vnode_attr va
;
1966 struct nameidata nd
;
1967 struct vfs_context context
;
1971 context
.vc_proc
= p
;
1972 context
.vc_ucred
= kauth_cred_get();
1974 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1975 error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
);
1978 AUDIT_ARG(text
, path
); /* This is the link string */
1980 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1981 UIO_USERSPACE
, uap
->link
, &context
);
1990 VATTR_SET(&va
, va_type
, VLNK
);
1991 VATTR_SET(&va
, va_mode
, ACCESSPERMS
& ~p
->p_fd
->fd_cmask
);
1994 error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
);
1995 /* get default ownership, etc. */
1997 error
= vnode_authattr_new(dvp
, &va
, 0, &context
);
1999 error
= VNOP_SYMLINK(dvp
, &vp
, &nd
.ni_cnd
, &va
, path
, &context
);
2001 /* do fallback attribute handling */
2003 error
= vnode_setattr_fallback(vp
, &va
, &context
);
2006 int update_flags
= 0;
2009 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
2010 nd
.ni_cnd
.cn_flags
= 0;
2018 #if 0 /* XXX - kauth_todo - is KAUTH_FILEOP_SYMLINK needed? */
2019 /* call out to allow 3rd party notification of rename.
2020 * Ignore result of kauth_authorize_fileop call.
2022 if (kauth_authorize_fileop_has_listeners() &&
2024 char *new_link_path
= NULL
;
2027 /* build the path to the new link file */
2028 new_link_path
= get_pathbuff();
2030 vn_getpath(dvp
, new_link_path
, &len
);
2031 new_link_path
[len
- 1] = '/';
2032 strcpy(&new_link_path
[len
], nd
.ni_cnd
.cn_nameptr
);
2034 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_SYMLINK
,
2035 (uintptr_t)path
, (uintptr_t)new_link_path
);
2036 if (new_link_path
!= NULL
)
2037 release_pathbuff(new_link_path
);
2040 // Make sure the name & parent pointers are hooked up
2041 if (vp
->v_name
== NULL
)
2042 update_flags
|= VNODE_UPDATE_NAME
;
2043 if (vp
->v_parent
== NULLVP
)
2044 update_flags
|= VNODE_UPDATE_PARENT
;
2047 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
2049 add_fsevent(FSE_CREATE_FILE
, &context
,
2058 * nameidone has to happen before we vnode_put(dvp)
2059 * since it may need to release the fs_nodelock on the dvp
2067 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
2073 * Delete a whiteout from the filesystem.
2076 #warning XXX authorization not implmented for whiteouts
2078 undelete(struct proc
*p
, register struct undelete_args
*uap
, __unused register_t
*retval
)
2081 struct nameidata nd
;
2082 struct vfs_context context
;
2085 context
.vc_proc
= p
;
2086 context
.vc_ucred
= kauth_cred_get();
2088 NDINIT(&nd
, DELETE
, LOCKPARENT
|DOWHITEOUT
|AUDITVNPATH1
,
2089 UIO_USERSPACE
, uap
->path
, &context
);
2096 if (vp
== NULLVP
&& (nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
2097 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, DELETE
, &context
);
2102 * nameidone has to happen before we vnode_put(dvp)
2103 * since it may need to release the fs_nodelock on the dvp
2115 * Delete a name from the filesystem.
2119 _unlink(struct proc
*p
, struct unlink_args
*uap
, __unused register_t
*retval
, int nodelbusy
)
2123 struct nameidata nd
;
2124 struct vfs_context context
;
2125 struct componentname
*cnp
;
2128 context
.vc_proc
= p
;
2129 context
.vc_ucred
= kauth_cred_get();
2131 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
2132 UIO_USERSPACE
, uap
->path
, &context
);
2135 /* With Carbon delete semantics, busy files cannot be deleted */
2137 flags
|= VNODE_REMOVE_NODELETEBUSY
;
2145 if (vp
->v_type
== VDIR
) {
2146 error
= EPERM
; /* POSIX */
2149 * The root of a mounted filesystem cannot be deleted.
2151 if (vp
->v_flag
& VROOT
) {
2155 /* authorize the delete operation */
2157 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, &context
);
2164 if (need_fsevent(FSE_DELETE
, dvp
)) {
2165 path
= get_pathbuff();
2167 vn_getpath(vp
, path
, &len
);
2168 get_fse_info(vp
, &finfo
, &context
);
2170 error
= VNOP_REMOVE(dvp
, vp
, &nd
.ni_cnd
, flags
, &context
);
2172 if ( !error
&& path
!= NULL
) {
2173 add_fsevent(FSE_DELETE
, &context
,
2174 FSE_ARG_STRING
, len
, path
,
2175 FSE_ARG_FINFO
, &finfo
,
2179 release_pathbuff(path
);
2182 * nameidone has to happen before we vnode_put(dvp)
2183 * since it may need to release the fs_nodelock on the dvp
2192 * Delete a name from the filesystem using POSIX semantics.
2195 unlink(p
, uap
, retval
)
2197 struct unlink_args
*uap
;
2200 return _unlink(p
, uap
, retval
, 0);
2204 * Delete a name from the filesystem using Carbon semantics.
2207 delete(p
, uap
, retval
)
2209 struct delete_args
*uap
;
2212 return _unlink(p
, (struct unlink_args
*)uap
, retval
, 1);
2216 * Reposition read/write file offset.
2219 lseek(p
, uap
, retval
)
2221 register struct lseek_args
*uap
;
2224 struct fileproc
*fp
;
2226 struct vfs_context context
;
2227 off_t offset
= uap
->offset
, file_size
;
2230 if ( (error
= fp_getfvp(p
,uap
->fd
, &fp
, &vp
)) ) {
2231 if (error
== ENOTSUP
)
2235 if (vnode_isfifo(vp
)) {
2239 if ( (error
= vnode_getwithref(vp
)) ) {
2244 switch (uap
->whence
) {
2246 offset
+= fp
->f_fglob
->fg_offset
;
2249 context
.vc_proc
= p
;
2250 context
.vc_ucred
= kauth_cred_get();
2251 if ((error
= vnode_size(vp
, &file_size
, &context
)) != 0)
2253 offset
+= file_size
;
2261 if (uap
->offset
> 0 && offset
< 0) {
2262 /* Incremented/relative move past max size */
2266 * Allow negative offsets on character devices, per
2267 * POSIX 1003.1-2001. Most likely for writing disk
2270 if (offset
< 0 && vp
->v_type
!= VCHR
) {
2271 /* Decremented/relative move before start */
2275 fp
->f_fglob
->fg_offset
= offset
;
2276 *retval
= fp
->f_fglob
->fg_offset
;
2280 (void)vnode_put(vp
);
2287 * Check access permissions.
2290 access1(vnode_t vp
, vnode_t dvp
, int uflags
, vfs_context_t ctx
)
2292 kauth_action_t action
;
2296 * If just the regular access bits, convert them to something
2297 * that vnode_authorize will understand.
2299 if (!(uflags
& _ACCESS_EXTENDED_MASK
)) {
2302 action
|= KAUTH_VNODE_READ_DATA
; /* aka KAUTH_VNODE_LIST_DIRECTORY */
2303 if (uflags
& W_OK
) {
2304 if (vnode_isdir(vp
)) {
2305 action
|= KAUTH_VNODE_ADD_FILE
|
2306 KAUTH_VNODE_ADD_SUBDIRECTORY
;
2307 /* might want delete rights here too */
2309 action
|= KAUTH_VNODE_WRITE_DATA
;
2312 if (uflags
& X_OK
) {
2313 if (vnode_isdir(vp
)) {
2314 action
|= KAUTH_VNODE_SEARCH
;
2316 action
|= KAUTH_VNODE_EXECUTE
;
2320 /* take advantage of definition of uflags */
2321 action
= uflags
>> 8;
2324 /* action == 0 means only check for existence */
2326 error
= vnode_authorize(vp
, dvp
, action
| KAUTH_VNODE_ACCESS
, ctx
);
2336 /* XXX need to support the check-as uid argument */
2338 access_extended(__unused
struct proc
*p
, struct access_extended_args
*uap
, __unused register_t
*retval
)
2340 struct accessx_descriptor
*input
;
2342 int error
, limit
, nent
, i
, j
, wantdelete
;
2343 struct vfs_context context
;
2344 struct nameidata nd
;
2353 context
.vc_ucred
= NULL
;
2355 /* check input size and fetch descriptor array into allocated storage */
2356 if (uap
->size
> ACCESSX_MAX_TABLESIZE
)
2358 if (uap
->size
< sizeof(struct accessx_descriptor
))
2360 MALLOC(input
, struct accessx_descriptor
*, uap
->size
, M_TEMP
, M_WAITOK
);
2361 if (input
== NULL
) {
2365 error
= copyin(uap
->entries
, input
, uap
->size
);
2370 * Access is defined as checking against the process'
2371 * real identity, even if operations are checking the
2372 * effective identity. So we need to tweak the credential
2375 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
2376 context
.vc_proc
= current_proc();
2379 * Find out how many entries we have, so we can allocate the result array.
2381 limit
= uap
->size
/ sizeof(struct accessx_descriptor
);
2384 for (i
= 0; i
< nent
; i
++) {
2386 * Take the offset to the name string for this entry and convert to an
2387 * input array index, which would be one off the end of the array if this
2388 * was the lowest-addressed name string.
2390 j
= input
[i
].ad_name_offset
/ sizeof(struct accessx_descriptor
);
2396 /* implicit reference to previous name, not a real offset */
2398 /* first entry must have a name string */
2408 if (nent
> ACCESSX_MAX_DESCRIPTORS
) {
2412 MALLOC(result
, errno_t
*, nent
* sizeof(errno_t
), M_TEMP
, M_WAITOK
);
2413 if (result
== NULL
) {
2422 for (i
= 0; i
< nent
; i
++) {
2424 * Looking up a new name?
2426 if (input
[i
].ad_name_offset
!= 0) {
2427 /* discard old vnodes */
2437 /* scan forwards to see if we need the parent this time */
2438 wantdelete
= input
[i
].ad_flags
& _DELETE_OK
;
2439 for (j
= i
+ 1; (j
< nent
) && (input
[j
].ad_name_offset
== 0); j
++)
2440 if (input
[j
].ad_flags
& _DELETE_OK
)
2443 niopts
= FOLLOW
| AUDITVNPATH1
;
2444 /* need parent for vnode_authorize for deletion test */
2446 niopts
|= WANTPARENT
;
2449 NDINIT(&nd
, LOOKUP
, niopts
, UIO_SYSSPACE
, CAST_USER_ADDR_T((const char *)input
+ input
[i
].ad_name_offset
), &context
);
2460 * Handle lookup errors.
2470 /* run this access check */
2471 result
[i
] = access1(vp
, dvp
, input
[i
].ad_flags
, &context
);
2474 /* fatal lookup error */
2480 /* copy out results */
2481 error
= copyout(result
, uap
->results
, nent
* sizeof(errno_t
));
2485 FREE(input
, M_TEMP
);
2487 FREE(result
, M_TEMP
);
2492 if (IS_VALID_CRED(context
.vc_ucred
))
2493 kauth_cred_unref(&context
.vc_ucred
);
2498 access(__unused
struct proc
*p
, register struct access_args
*uap
, __unused register_t
*retval
)
2501 struct nameidata nd
;
2503 struct vfs_context context
;
2506 * Access is defined as checking against the process'
2507 * real identity, even if operations are checking the
2508 * effective identity. So we need to tweak the credential
2511 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
2512 context
.vc_proc
= current_proc();
2514 niopts
= FOLLOW
| AUDITVNPATH1
;
2515 /* need parent for vnode_authorize for deletion test */
2516 if (uap
->flags
& _DELETE_OK
)
2517 niopts
|= WANTPARENT
;
2518 NDINIT(&nd
, LOOKUP
, niopts
, UIO_USERSPACE
, uap
->path
, &context
);
2523 error
= access1(nd
.ni_vp
, nd
.ni_dvp
, uap
->flags
, &context
);
2525 vnode_put(nd
.ni_vp
);
2526 if (uap
->flags
& _DELETE_OK
)
2527 vnode_put(nd
.ni_dvp
);
2531 kauth_cred_unref(&context
.vc_ucred
);
2537 stat2(vfs_context_t ctx
, struct nameidata
*ndp
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2540 struct user_stat user_sb
;
2543 kauth_filesec_t fsec
;
2544 size_t xsecurity_bufsize
;
2549 fsec
= KAUTH_FILESEC_NONE
;
2550 error
= vn_stat(ndp
->ni_vp
, &sb
, (xsecurity
!= USER_ADDR_NULL
? &fsec
: NULL
), ctx
);
2551 vnode_put(ndp
->ni_vp
);
2556 /* Zap spare fields */
2558 sb
.st_qspare
[0] = 0LL;
2559 sb
.st_qspare
[1] = 0LL;
2560 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
2561 munge_stat(&sb
, &user_sb
);
2562 my_size
= sizeof(user_sb
);
2563 sbp
= (caddr_t
)&user_sb
;
2566 my_size
= sizeof(sb
);
2569 if ((error
= copyout(sbp
, ub
, my_size
)) != 0)
2572 /* caller wants extended security information? */
2573 if (xsecurity
!= USER_ADDR_NULL
) {
2575 /* did we get any? */
2576 if (fsec
== KAUTH_FILESEC_NONE
) {
2577 if (susize(xsecurity_size
, 0) != 0) {
2582 /* find the user buffer size */
2583 xsecurity_bufsize
= fusize(xsecurity_size
);
2585 /* copy out the actual data size */
2586 if (susize(xsecurity_size
, KAUTH_FILESEC_COPYSIZE(fsec
)) != 0) {
2591 /* if the caller supplied enough room, copy out to it */
2592 if (xsecurity_bufsize
>= KAUTH_FILESEC_COPYSIZE(fsec
))
2593 error
= copyout(fsec
, xsecurity
, KAUTH_FILESEC_COPYSIZE(fsec
));
2597 if (fsec
!= KAUTH_FILESEC_NONE
)
2598 kauth_filesec_free(fsec
);
2603 * Get file status; this version follows links.
2606 stat1(struct proc
*p
, user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2608 struct nameidata nd
;
2609 struct vfs_context context
;
2611 context
.vc_proc
= p
;
2612 context
.vc_ucred
= kauth_cred_get();
2614 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2615 UIO_USERSPACE
, path
, &context
);
2616 return(stat2(&context
, &nd
, ub
, xsecurity
, xsecurity_size
));
2620 stat_extended(struct proc
*p
, struct stat_extended_args
*uap
, __unused register_t
*retval
)
2622 return (stat1(p
, uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
));
2626 stat(struct proc
*p
, struct stat_args
*uap
, __unused register_t
*retval
)
2628 return(stat1(p
, uap
->path
, uap
->ub
, 0, 0));
2632 * Get file status; this version does not follow links.
2635 lstat1(struct proc
*p
, user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2637 struct nameidata nd
;
2638 struct vfs_context context
;
2640 context
.vc_proc
= p
;
2641 context
.vc_ucred
= kauth_cred_get();
2643 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
2644 UIO_USERSPACE
, path
, &context
);
2646 return(stat2(&context
, &nd
, ub
, xsecurity
, xsecurity_size
));
2650 lstat_extended(struct proc
*p
, struct lstat_extended_args
*uap
, __unused register_t
*retval
)
2652 return (lstat1(p
, uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
));
2656 lstat(struct proc
*p
, struct lstat_args
*uap
, __unused register_t
*retval
)
2658 return(lstat1(p
, uap
->path
, uap
->ub
, 0, 0));
2662 * Get configurable pathname variables.
2666 pathconf(p
, uap
, retval
)
2668 register struct pathconf_args
*uap
;
2672 struct nameidata nd
;
2673 struct vfs_context context
;
2675 context
.vc_proc
= p
;
2676 context
.vc_ucred
= kauth_cred_get();
2678 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2679 UIO_USERSPACE
, uap
->path
, &context
);
2684 error
= vn_pathconf(nd
.ni_vp
, uap
->name
, retval
, &context
);
2686 vnode_put(nd
.ni_vp
);
2692 * Return target name of a symbolic link.
2696 readlink(p
, uap
, retval
)
2698 register struct readlink_args
*uap
;
2701 register struct vnode
*vp
;
2703 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
2705 struct nameidata nd
;
2706 struct vfs_context context
;
2707 char uio_buf
[ UIO_SIZEOF(1) ];
2709 context
.vc_proc
= p
;
2710 context
.vc_ucred
= kauth_cred_get();
2712 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
2713 UIO_USERSPACE
, uap
->path
, &context
);
2721 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
2722 &uio_buf
[0], sizeof(uio_buf
));
2723 uio_addiov(auio
, uap
->buf
, uap
->count
);
2724 if (vp
->v_type
!= VLNK
)
2727 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, &context
);
2729 error
= VNOP_READLINK(vp
, auio
, &context
);
2732 // LP64todo - fix this
2733 *retval
= uap
->count
- (int)uio_resid(auio
);
2738 * Change file flags.
2741 chflags1(vnode_t vp
, int flags
, vfs_context_t ctx
)
2743 struct vnode_attr va
;
2744 kauth_action_t action
;
2748 VATTR_SET(&va
, va_flags
, flags
);
2750 /* request authorisation, disregard immutability */
2751 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
2754 * Request that the auth layer disregard those file flags it's allowed to when
2755 * authorizing this operation; we need to do this in order to be able to
2756 * clear immutable flags.
2758 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
| KAUTH_VNODE_NOIMMUTABLE
, ctx
)) != 0))
2760 error
= vnode_setattr(vp
, &va
, ctx
);
2768 * Change flags of a file given a path name.
2772 chflags(struct proc
*p
, register struct chflags_args
*uap
, __unused register_t
*retval
)
2774 register struct vnode
*vp
;
2775 struct vfs_context context
;
2777 struct nameidata nd
;
2779 context
.vc_proc
= p
;
2780 context
.vc_ucred
= kauth_cred_get();
2782 AUDIT_ARG(fflags
, uap
->flags
);
2783 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2784 UIO_USERSPACE
, uap
->path
, &context
);
2791 error
= chflags1(vp
, uap
->flags
, &context
);
2797 * Change flags of a file given a file descriptor.
2801 fchflags(struct proc
*p
, register struct fchflags_args
*uap
, __unused register_t
*retval
)
2803 struct vfs_context context
;
2807 AUDIT_ARG(fd
, uap
->fd
);
2808 AUDIT_ARG(fflags
, uap
->flags
);
2809 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
2812 if ((error
= vnode_getwithref(vp
))) {
2817 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2819 context
.vc_proc
= p
;
2820 context
.vc_ucred
= kauth_cred_get();
2822 error
= chflags1(vp
, uap
->flags
, &context
);
2829 * Change security information on a filesystem object.
2832 chmod2(vfs_context_t ctx
, struct vnode
*vp
, struct vnode_attr
*vap
)
2834 kauth_action_t action
;
2837 AUDIT_ARG(mode
, (mode_t
)vap
->va_mode
);
2838 #warning XXX audit new args
2840 /* make sure that the caller is allowed to set this security information */
2841 if (((error
= vnode_authattr(vp
, vap
, &action
, ctx
)) != 0) ||
2842 ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
2843 if (error
== EACCES
)
2848 error
= vnode_setattr(vp
, vap
, ctx
);
2855 * Change mode of a file given path name.
2858 chmod1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
2860 struct nameidata nd
;
2863 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2864 UIO_USERSPACE
, path
, ctx
);
2865 if ((error
= namei(&nd
)))
2867 error
= chmod2(ctx
, nd
.ni_vp
, vap
);
2868 vnode_put(nd
.ni_vp
);
2874 * A chmod system call using an extended argument list compared to the regular
2875 * system call 'mkfifo'.
2877 * Parameters: p Process requesting the open
2878 * uap User argument descriptor (see below)
2881 * Indirect: uap->path Path to object (same as 'chmod')
2882 * uap->uid UID to set
2883 * uap->gid GID to set
2884 * uap->mode File mode to set (same as 'chmod')
2885 * uap->xsecurity ACL to set (or delete)
2887 * Returns: 0 Success
2890 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
2892 * XXX: We should enummerate the possible errno values here, and where
2893 * in the code they originated.
2896 chmod_extended(struct proc
*p
, struct chmod_extended_args
*uap
, __unused register_t
*retval
)
2898 struct vfs_context context
;
2900 struct vnode_attr va
;
2901 kauth_filesec_t xsecdst
;
2904 if (uap
->mode
!= -1)
2905 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2906 if (uap
->uid
!= KAUTH_UID_NONE
)
2907 VATTR_SET(&va
, va_uid
, uap
->uid
);
2908 if (uap
->gid
!= KAUTH_GID_NONE
)
2909 VATTR_SET(&va
, va_gid
, uap
->gid
);
2912 switch(uap
->xsecurity
) {
2913 /* explicit remove request */
2914 case CAST_USER_ADDR_T((void *)1): /* _FILESEC_REMOVE_ACL */
2915 VATTR_SET(&va
, va_acl
, NULL
);
2918 case USER_ADDR_NULL
:
2921 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
2923 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2924 KAUTH_DEBUG("CHMOD - setting ACL with %d entries", va
.va_acl
->acl_entrycount
);
2926 context
.vc_proc
= p
;
2927 context
.vc_ucred
= kauth_cred_get();
2929 error
= chmod1(&context
, uap
->path
, &va
);
2931 if (xsecdst
!= NULL
)
2932 kauth_filesec_free(xsecdst
);
2937 chmod(struct proc
*p
, register struct chmod_args
*uap
, __unused register_t
*retval
)
2939 struct vfs_context context
;
2940 struct vnode_attr va
;
2943 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2945 context
.vc_proc
= p
;
2946 context
.vc_ucred
= kauth_cred_get();
2948 return(chmod1(&context
, uap
->path
, &va
));
2952 * Change mode of a file given a file descriptor.
2955 fchmod1(struct proc
*p
, int fd
, struct vnode_attr
*vap
)
2959 struct vfs_context context
;
2961 context
.vc_proc
= p
;
2962 context
.vc_ucred
= kauth_cred_get();
2966 if ((error
= file_vnode(fd
, &vp
)) != 0)
2968 if ((error
= vnode_getwithref(vp
)) != 0) {
2972 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2974 error
= chmod2(&context
, vp
, vap
);
2975 (void)vnode_put(vp
);
2982 fchmod_extended(struct proc
*p
, struct fchmod_extended_args
*uap
, __unused register_t
*retval
)
2985 struct vnode_attr va
;
2986 kauth_filesec_t xsecdst
;
2989 if (uap
->mode
!= -1)
2990 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2991 if (uap
->uid
!= KAUTH_UID_NONE
)
2992 VATTR_SET(&va
, va_uid
, uap
->uid
);
2993 if (uap
->gid
!= KAUTH_GID_NONE
)
2994 VATTR_SET(&va
, va_gid
, uap
->gid
);
2997 switch(uap
->xsecurity
) {
2998 case USER_ADDR_NULL
:
2999 VATTR_SET(&va
, va_acl
, NULL
);
3001 case CAST_USER_ADDR_T(-1):
3004 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
3006 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
3009 error
= fchmod1(p
, uap
->fd
, &va
);
3012 switch(uap
->xsecurity
) {
3013 case USER_ADDR_NULL
:
3014 case CAST_USER_ADDR_T(-1):
3017 if (xsecdst
!= NULL
)
3018 kauth_filesec_free(xsecdst
);
3024 fchmod(struct proc
*p
, register struct fchmod_args
*uap
, __unused register_t
*retval
)
3026 struct vnode_attr va
;
3029 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
3031 return(fchmod1(p
, uap
->fd
, &va
));
3036 * Set ownership given a path name.
3040 chown1(vfs_context_t ctx
, register struct chown_args
*uap
, __unused register_t
*retval
, int follow
)
3042 register struct vnode
*vp
;
3043 struct vnode_attr va
;
3045 struct nameidata nd
;
3046 kauth_action_t action
;
3048 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
3050 NDINIT(&nd
, LOOKUP
, (follow
? FOLLOW
: 0) | AUDITVNPATH1
,
3051 UIO_USERSPACE
, uap
->path
, ctx
);
3060 * XXX A TEMPORARY HACK FOR NOW: Try to track console_user
3061 * by looking for chown() calls on /dev/console from a console process.
3063 if ((vp
) && (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
) && (vp
->v_specinfo
) &&
3064 (major(vp
->v_specinfo
->si_rdev
) == CONSMAJOR
) &&
3065 (minor(vp
->v_specinfo
->si_rdev
) == 0)) {
3066 console_user
= uap
->uid
;
3069 if (uap
->uid
!= VNOVAL
)
3070 VATTR_SET(&va
, va_uid
, uap
->uid
);
3071 if (uap
->gid
!= VNOVAL
)
3072 VATTR_SET(&va
, va_gid
, uap
->gid
);
3074 /* preflight and authorize attribute changes */
3075 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
3077 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
3079 error
= vnode_setattr(vp
, &va
, ctx
);
3083 * EACCES is only allowed from namei(); permissions failure should
3084 * return EPERM, so we need to translate the error code.
3086 if (error
== EACCES
)
3094 chown(struct proc
*p
, register struct chown_args
*uap
, register_t
*retval
)
3096 struct vfs_context context
;
3098 context
.vc_proc
= p
;
3099 context
.vc_ucred
= kauth_cred_get();
3101 return chown1(&context
, uap
, retval
, 1);
3105 lchown(struct proc
*p
, register struct lchown_args
*uap
, register_t
*retval
)
3107 struct vfs_context context
;
3109 context
.vc_proc
= p
;
3110 context
.vc_ucred
= kauth_cred_get();
3112 /* Argument list identical, but machine generated; cast for chown1() */
3113 return chown1(&context
, (struct chown_args
*)uap
, retval
, 0);
3117 * Set ownership given a file descriptor.
3121 fchown(struct proc
*p
, register struct fchown_args
*uap
, __unused register_t
*retval
)
3123 struct vnode_attr va
;
3124 struct vfs_context context
;
3127 kauth_action_t action
;
3129 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
3130 AUDIT_ARG(fd
, uap
->fd
);
3132 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
3135 if ( (error
= vnode_getwithref(vp
)) ) {
3139 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3142 if (uap
->uid
!= VNOVAL
)
3143 VATTR_SET(&va
, va_uid
, uap
->uid
);
3144 if (uap
->gid
!= VNOVAL
)
3145 VATTR_SET(&va
, va_gid
, uap
->gid
);
3147 context
.vc_proc
= p
;
3148 context
.vc_ucred
= kauth_cred_get();
3150 /* preflight and authorize attribute changes */
3151 if ((error
= vnode_authattr(vp
, &va
, &action
, &context
)) != 0)
3153 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0)) {
3154 if (error
== EACCES
)
3158 error
= vnode_setattr(vp
, &va
, &context
);
3161 (void)vnode_put(vp
);
3167 getutimes(usrtvp
, tsp
)
3169 struct timespec
*tsp
;
3171 struct user_timeval tv
[2];
3174 if (usrtvp
== USER_ADDR_NULL
) {
3175 struct timeval old_tv
;
3176 /* XXX Y2038 bug because of microtime argument */
3178 TIMEVAL_TO_TIMESPEC(&old_tv
, &tsp
[0]);
3181 if (IS_64BIT_PROCESS(current_proc())) {
3182 error
= copyin(usrtvp
, (void *)tv
, sizeof(tv
));
3184 struct timeval old_tv
[2];
3185 error
= copyin(usrtvp
, (void *)old_tv
, sizeof(old_tv
));
3186 tv
[0].tv_sec
= old_tv
[0].tv_sec
;
3187 tv
[0].tv_usec
= old_tv
[0].tv_usec
;
3188 tv
[1].tv_sec
= old_tv
[1].tv_sec
;
3189 tv
[1].tv_usec
= old_tv
[1].tv_usec
;
3193 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
3194 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
3200 setutimes(vfs_context_t ctx
, struct vnode
*vp
, const struct timespec
*ts
,
3204 struct vnode_attr va
;
3205 kauth_action_t action
;
3207 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3210 VATTR_SET(&va
, va_access_time
, ts
[0]);
3211 VATTR_SET(&va
, va_modify_time
, ts
[1]);
3213 va
.va_vaflags
|= VA_UTIMES_NULL
;
3215 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
3217 /* since we may not need to auth anything, check here */
3218 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
3220 error
= vnode_setattr(vp
, &va
, ctx
);
3227 * Set the access and modification times of a file.
3231 utimes(struct proc
*p
, register struct utimes_args
*uap
, __unused register_t
*retval
)
3233 struct timespec ts
[2];
3236 struct nameidata nd
;
3237 struct vfs_context context
;
3239 context
.vc_proc
= p
;
3240 context
.vc_ucred
= kauth_cred_get();
3242 /* AUDIT: Needed to change the order of operations to do the
3243 * name lookup first because auditing wants the path.
3245 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3246 UIO_USERSPACE
, uap
->path
, &context
);
3253 * Fetch the user-supplied time. If usrtvp is USER_ADDR_NULL, we fetch
3254 * the current time instead.
3257 if ((error
= getutimes(usrtvp
, ts
)) != 0)
3260 error
= setutimes(&context
, nd
.ni_vp
, ts
, usrtvp
== USER_ADDR_NULL
);
3263 vnode_put(nd
.ni_vp
);
3268 * Set the access and modification times of a file.
3272 futimes(struct proc
*p
, register struct futimes_args
*uap
, __unused register_t
*retval
)
3274 struct timespec ts
[2];
3278 struct vfs_context context
;
3280 context
.vc_proc
= p
;
3281 context
.vc_ucred
= kauth_cred_get();
3283 AUDIT_ARG(fd
, uap
->fd
);
3285 if ((error
= getutimes(usrtvp
, ts
)) != 0)
3287 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
3289 if((error
= vnode_getwithref(vp
))) {
3294 error
= setutimes(&context
, vp
, ts
, usrtvp
== 0);
3301 * Truncate a file given its path name.
3305 truncate(struct proc
*p
, register struct truncate_args
*uap
, __unused register_t
*retval
)
3307 register struct vnode
*vp
;
3308 struct vnode_attr va
;
3309 struct vfs_context context
;
3311 struct nameidata nd
;
3312 kauth_action_t action
;
3314 context
.vc_proc
= p
;
3315 context
.vc_ucred
= kauth_cred_get();
3317 if (uap
->length
< 0)
3319 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3320 UIO_USERSPACE
, uap
->path
, &context
);
3321 if ((error
= namei(&nd
)))
3328 VATTR_SET(&va
, va_data_size
, uap
->length
);
3329 if ((error
= vnode_authattr(vp
, &va
, &action
, &context
)) != 0)
3331 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0))
3333 error
= vnode_setattr(vp
, &va
, &context
);
3340 * Truncate a file given a file descriptor.
3344 ftruncate(p
, uap
, retval
)
3346 register struct ftruncate_args
*uap
;
3349 struct vfs_context context
;
3350 struct vnode_attr va
;
3352 struct fileproc
*fp
;
3356 context
.vc_proc
= current_proc();
3357 context
.vc_ucred
= kauth_cred_get();
3359 AUDIT_ARG(fd
, uap
->fd
);
3360 if (uap
->length
< 0)
3363 if ( (error
= fp_lookup(p
,fd
,&fp
,0)) ) {
3367 if (fp
->f_fglob
->fg_type
== DTYPE_PSXSHM
) {
3368 error
= pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
);
3371 if (fp
->f_fglob
->fg_type
!= DTYPE_VNODE
) {
3376 vp
= (struct vnode
*)fp
->f_fglob
->fg_data
;
3378 if ((fp
->f_fglob
->fg_flag
& FWRITE
) == 0) {
3379 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
3384 if ((error
= vnode_getwithref(vp
)) != 0) {
3388 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3391 VATTR_SET(&va
, va_data_size
, uap
->length
);
3392 error
= vnode_setattr(vp
, &va
, &context
);
3393 (void)vnode_put(vp
);
3401 * Sync an open file.
3405 fsync(struct proc
*p
, struct fsync_args
*uap
, __unused register_t
*retval
)
3408 struct fileproc
*fp
;
3409 struct vfs_context context
;
3412 if ( (error
= fp_getfvp(p
, uap
->fd
, &fp
, &vp
)) )
3414 if ( (error
= vnode_getwithref(vp
)) ) {
3418 context
.vc_proc
= p
;
3419 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
3421 error
= VNOP_FSYNC(vp
, MNT_WAIT
, &context
);
3423 (void)vnode_put(vp
);
3429 * Duplicate files. Source must be a file, target must be a file or
3432 * XXX Copyfile authorisation checking is woefully inadequate, and will not
3433 * perform inheritance correctly.
3437 copyfile(struct proc
*p
, register struct copyfile_args
*uap
, __unused register_t
*retval
)
3439 vnode_t tvp
, fvp
, tdvp
, sdvp
;
3440 struct nameidata fromnd
, tond
;
3442 struct vfs_context context
;
3444 context
.vc_proc
= p
;
3445 context
.vc_ucred
= kauth_cred_get();
3447 /* Check that the flags are valid. */
3449 if (uap
->flags
& ~CPF_MASK
) {
3453 NDINIT(&fromnd
, LOOKUP
, SAVESTART
| AUDITVNPATH1
,
3454 UIO_USERSPACE
, uap
->from
, &context
);
3455 if ((error
= namei(&fromnd
)))
3459 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
| AUDITVNPATH2
,
3460 UIO_USERSPACE
, uap
->to
, &context
);
3461 if ((error
= namei(&tond
))) {
3468 if (!(uap
->flags
& CPF_OVERWRITE
)) {
3473 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
3478 if ((error
= vnode_authorize(tdvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
3484 * If source is the same as the destination (that is the
3485 * same inode number) then there is nothing to do.
3486 * (fixed to have POSIX semantics - CSM 3/2/98)
3491 error
= VNOP_COPYFILE(fvp
,tdvp
,tvp
,&tond
.ni_cnd
,uap
->mode
,uap
->flags
,&context
);
3493 sdvp
= tond
.ni_startdir
;
3495 * nameidone has to happen before we vnode_put(tdvp)
3496 * since it may need to release the fs_nodelock on the tdvp
3507 if (fromnd
.ni_startdir
)
3508 vnode_put(fromnd
.ni_startdir
);
3518 * Rename files. Source and destination must either both be directories,
3519 * or both not be directories. If target is a directory, it must be empty.
3523 rename(proc_t p
, register struct rename_args
*uap
, __unused register_t
*retval
)
3527 struct nameidata fromnd
, tond
;
3528 struct vfs_context context
;
3531 char *oname
, *from_name
, *to_name
;
3532 int from_len
, to_len
;
3533 int holding_mntlock
;
3534 mount_t locked_mp
= NULL
;
3536 fse_info from_finfo
, to_finfo
;
3538 context
.vc_proc
= p
;
3539 context
.vc_ucred
= kauth_cred_get();
3540 holding_mntlock
= 0;
3546 NDINIT(&fromnd
, DELETE
, WANTPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->from
, &context
);
3548 if ( (error
= namei(&fromnd
)) )
3550 fdvp
= fromnd
.ni_dvp
;
3553 NDINIT(&tond
, RENAME
, WANTPARENT
| AUDITVNPATH2
, UIO_USERSPACE
, uap
->to
, &context
);
3554 if (fvp
->v_type
== VDIR
)
3555 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
3557 if ( (error
= namei(&tond
)) ) {
3559 * Translate error code for rename("dir1", "dir2/.").
3561 if (error
== EISDIR
&& fvp
->v_type
== VDIR
)
3569 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
3572 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
3585 * If tvp is a directory and not the same as fdvp, or tdvp is not the same as fdvp,
3586 * the node is moving between directories and we need rights to remove from the
3587 * old and add to the new.
3589 * If tvp already exists and is not a directory, we need to be allowed to delete it.
3591 * Note that we do not inherit when renaming. XXX this needs to be revisited to
3592 * implement the deferred-inherit bit.
3598 if ((tvp
!= NULL
) && vnode_isdir(tvp
)) {
3601 } else if (tdvp
!= fdvp
) {
3605 * must have delete rights to remove the old name even in the simple case of
3608 if ((error
= vnode_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
, &context
)) != 0)
3611 /* moving into tdvp or tvp, must have rights to add */
3612 if ((error
= vnode_authorize(((tvp
!= NULL
) && vnode_isdir(tvp
)) ? tvp
: tdvp
,
3614 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
3618 /* node staying in same directory, must be allowed to add new name */
3619 if ((error
= vnode_authorize(fdvp
, NULL
,
3620 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
3623 /* overwriting tvp */
3624 if ((tvp
!= NULL
) && !vnode_isdir(tvp
) &&
3625 ((error
= vnode_authorize(tvp
, tdvp
, KAUTH_VNODE_DELETE
, &context
)) != 0))
3628 /* XXX more checks? */
3631 /* authorization denied */
3636 * Allow the renaming of mount points.
3637 * - target must not exist
3638 * - target must reside in the same directory as source
3639 * - union mounts cannot be renamed
3640 * - "/" cannot be renamed
3642 if ((fvp
->v_flag
& VROOT
) &&
3643 (fvp
->v_type
== VDIR
) &&
3645 (fvp
->v_mountedhere
== NULL
) &&
3647 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
3648 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
3649 struct vnode
*coveredvp
;
3651 /* switch fvp to the covered vnode */
3652 coveredvp
= fvp
->v_mount
->mnt_vnodecovered
;
3653 if ( (vnode_getwithref(coveredvp
)) ) {
3663 * Check for cross-device rename.
3665 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
3666 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
3671 * Avoid renaming "." and "..".
3673 if (fvp
->v_type
== VDIR
&&
3675 (fromnd
.ni_cnd
.cn_namelen
== 1 && fromnd
.ni_cnd
.cn_nameptr
[0] == '.') ||
3676 ((fromnd
.ni_cnd
.cn_flags
| tond
.ni_cnd
.cn_flags
) & ISDOTDOT
)) ) {
3681 * The following edge case is caught here:
3682 * (to cannot be a descendent of from)
3695 if (tdvp
->v_parent
== fvp
) {
3701 * If source is the same as the destination (that is the
3702 * same inode number) then there is nothing to do...
3703 * EXCEPT if the underlying file system supports case
3704 * insensitivity and is case preserving. In this case
3705 * the file system needs to handle the special case of
3706 * getting the same vnode as target (fvp) and source (tvp).
3708 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
3709 * and _PC_CASE_PRESERVING can have this exception, and they need to
3710 * handle the special case of getting the same vnode as target and
3711 * source. NOTE: Then the target is unlocked going into vnop_rename,
3712 * so not to cause locking problems. There is a single reference on tvp.
3714 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
3715 * that correct behaviour then is just to remove the source (link)
3717 if (fvp
== tvp
&& fdvp
== tdvp
) {
3718 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
3719 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
3720 fromnd
.ni_cnd
.cn_namelen
)) {
3725 if (holding_mntlock
&& fvp
->v_mount
!= locked_mp
) {
3727 * we're holding a reference and lock
3728 * on locked_mp, but it no longer matches
3729 * what we want to do... so drop our hold
3731 mount_unlock_renames(locked_mp
);
3732 mount_drop(locked_mp
, 0);
3733 holding_mntlock
= 0;
3735 if (tdvp
!= fdvp
&& fvp
->v_type
== VDIR
) {
3737 * serialize renames that re-shape
3738 * the tree... if holding_mntlock is
3739 * set, then we're ready to go...
3741 * first need to drop the iocounts
3742 * we picked up, second take the
3743 * lock to serialize the access,
3744 * then finally start the lookup
3745 * process over with the lock held
3747 if (!holding_mntlock
) {
3749 * need to grab a reference on
3750 * the mount point before we
3751 * drop all the iocounts... once
3752 * the iocounts are gone, the mount
3755 locked_mp
= fvp
->v_mount
;
3756 mount_ref(locked_mp
, 0);
3759 * nameidone has to happen before we vnode_put(tvp)
3760 * since it may need to release the fs_nodelock on the tvp
3769 * nameidone has to happen before we vnode_put(fdvp)
3770 * since it may need to release the fs_nodelock on the fvp
3777 mount_lock_renames(locked_mp
);
3778 holding_mntlock
= 1;
3784 * when we dropped the iocounts to take
3785 * the lock, we allowed the identity of
3786 * the various vnodes to change... if they did,
3787 * we may no longer be dealing with a rename
3788 * that reshapes the tree... once we're holding
3789 * the iocounts, the vnodes can't change type
3790 * so we're free to drop the lock at this point
3793 if (holding_mntlock
) {
3794 mount_unlock_renames(locked_mp
);
3795 mount_drop(locked_mp
, 0);
3796 holding_mntlock
= 0;
3799 // save these off so we can later verify that fvp is the same
3800 oname
= fvp
->v_name
;
3801 oparent
= fvp
->v_parent
;
3803 if (need_fsevent(FSE_RENAME
, fvp
)) {
3804 get_fse_info(fvp
, &from_finfo
, &context
);
3807 get_fse_info(tvp
, &to_finfo
, &context
);
3809 from_name
= get_pathbuff();
3810 from_len
= MAXPATHLEN
;
3811 vn_getpath(fvp
, from_name
, &from_len
);
3813 to_name
= get_pathbuff();
3814 to_len
= MAXPATHLEN
;
3816 if (tvp
&& tvp
->v_type
!= VDIR
) {
3817 vn_getpath(tvp
, to_name
, &to_len
);
3819 vn_getpath(tdvp
, to_name
, &to_len
);
3820 // if the path is not just "/", then append a "/"
3822 to_name
[to_len
-1] = '/';
3826 strcpy(&to_name
[to_len
], tond
.ni_cnd
.cn_nameptr
);
3827 to_len
+= tond
.ni_cnd
.cn_namelen
+ 1;
3828 to_name
[to_len
] = '\0';
3834 error
= VNOP_RENAME(fdvp
, fvp
, &fromnd
.ni_cnd
,
3835 tdvp
, tvp
, &tond
.ni_cnd
,
3838 if (holding_mntlock
) {
3840 * we can drop our serialization
3843 mount_unlock_renames(locked_mp
);
3844 mount_drop(locked_mp
, 0);
3845 holding_mntlock
= 0;
3848 if (to_name
!= NULL
)
3849 release_pathbuff(to_name
);
3850 if (from_name
!= NULL
)
3851 release_pathbuff(from_name
);
3852 from_name
= to_name
= NULL
;
3857 /* call out to allow 3rd party notification of rename.
3858 * Ignore result of kauth_authorize_fileop call.
3860 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_RENAME
,
3861 (uintptr_t)from_name
, (uintptr_t)to_name
);
3863 if (from_name
!= NULL
&& to_name
!= NULL
) {
3865 add_fsevent(FSE_RENAME
, &context
,
3866 FSE_ARG_STRING
, from_len
, from_name
,
3867 FSE_ARG_FINFO
, &from_finfo
,
3868 FSE_ARG_STRING
, to_len
, to_name
,
3869 FSE_ARG_FINFO
, &to_finfo
,
3872 add_fsevent(FSE_RENAME
, &context
,
3873 FSE_ARG_STRING
, from_len
, from_name
,
3874 FSE_ARG_FINFO
, &from_finfo
,
3875 FSE_ARG_STRING
, to_len
, to_name
,
3879 if (to_name
!= NULL
)
3880 release_pathbuff(to_name
);
3881 if (from_name
!= NULL
)
3882 release_pathbuff(from_name
);
3883 from_name
= to_name
= NULL
;
3886 * update filesystem's mount point data
3889 char *cp
, *pathend
, *mpname
;
3895 mp
= fvp
->v_mountedhere
;
3897 if (vfs_busy(mp
, LK_NOWAIT
)) {
3901 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
3903 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
3905 /* find current mount point prefix */
3906 pathend
= &mp
->mnt_vfsstat
.f_mntonname
[0];
3907 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
3911 /* find last component of target name */
3912 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
3916 /* append name to prefix */
3917 maxlen
= MAXPATHLEN
- (pathend
- mp
->mnt_vfsstat
.f_mntonname
);
3918 bzero(pathend
, maxlen
);
3919 strncpy(pathend
, mpname
, maxlen
- 1);
3921 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
3926 * fix up name & parent pointers. note that we first
3927 * check that fvp has the same name/parent pointers it
3928 * had before the rename call... this is a 'weak' check
3931 if (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
) {
3934 update_flags
= VNODE_UPDATE_NAME
;
3937 update_flags
|= VNODE_UPDATE_PARENT
;
3939 vnode_update_identity(fvp
, tdvp
, tond
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_namelen
, tond
.ni_cnd
.cn_hash
, update_flags
);
3942 if (holding_mntlock
) {
3943 mount_unlock_renames(locked_mp
);
3944 mount_drop(locked_mp
, 0);
3948 * nameidone has to happen before we vnode_put(tdvp)
3949 * since it may need to release the fs_nodelock on the tdvp
3959 * nameidone has to happen before we vnode_put(fdvp)
3960 * since it may need to release the fs_nodelock on the fdvp
3972 * Make a directory file.
3976 mkdir1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
3980 int update_flags
= 0;
3981 struct nameidata nd
;
3983 AUDIT_ARG(mode
, vap
->va_mode
);
3984 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
3985 UIO_USERSPACE
, path
, ctx
);
3986 nd
.ni_cnd
.cn_flags
|= WILLBEDIR
;
3998 /* authorize addition of a directory to the parent */
3999 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
)) != 0)
4002 VATTR_SET(vap
, va_type
, VDIR
);
4004 /* make the directory */
4005 if ((error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
)) != 0)
4008 // Make sure the name & parent pointers are hooked up
4009 if (vp
->v_name
== NULL
)
4010 update_flags
|= VNODE_UPDATE_NAME
;
4011 if (vp
->v_parent
== NULLVP
)
4012 update_flags
|= VNODE_UPDATE_PARENT
;
4015 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
4017 add_fsevent(FSE_CREATE_DIR
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
4021 * nameidone has to happen before we vnode_put(dvp)
4022 * since it may need to release the fs_nodelock on the dvp
4035 mkdir_extended(struct proc
*p
, register struct mkdir_extended_args
*uap
, __unused register_t
*retval
)
4037 struct vfs_context context
;
4039 kauth_filesec_t xsecdst
;
4040 struct vnode_attr va
;
4043 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
4044 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
4047 context
.vc_proc
= p
;
4048 context
.vc_ucred
= kauth_cred_get();
4051 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
4052 if (xsecdst
!= NULL
)
4053 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
4055 ciferror
= mkdir1(&context
, uap
->path
, &va
);
4056 if (xsecdst
!= NULL
)
4057 kauth_filesec_free(xsecdst
);
4062 mkdir(struct proc
*p
, register struct mkdir_args
*uap
, __unused register_t
*retval
)
4064 struct vfs_context context
;
4065 struct vnode_attr va
;
4067 context
.vc_proc
= p
;
4068 context
.vc_ucred
= kauth_cred_get();
4071 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
4073 return(mkdir1(&context
, uap
->path
, &va
));
4077 * Remove a directory file.
4081 rmdir(struct proc
*p
, struct rmdir_args
*uap
, __unused register_t
*retval
)
4085 struct nameidata nd
;
4086 struct vfs_context context
;
4088 context
.vc_proc
= p
;
4089 context
.vc_ucred
= kauth_cred_get();
4091 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
4092 UIO_USERSPACE
, uap
->path
, &context
);
4099 if (vp
->v_type
!= VDIR
) {
4101 * rmdir only deals with directories
4104 } else if (dvp
== vp
) {
4106 * No rmdir "." please.
4109 } else if (vp
->v_flag
& VROOT
) {
4111 * The root of a mounted filesystem cannot be deleted.
4115 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, &context
);
4122 if (need_fsevent(FSE_DELETE
, dvp
)) {
4123 path
= get_pathbuff();
4125 vn_getpath(vp
, path
, &len
);
4126 get_fse_info(vp
, &finfo
, &context
);
4128 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, &context
);
4130 if (!error
&& path
!= NULL
) {
4131 add_fsevent(FSE_DELETE
, &context
,
4132 FSE_ARG_STRING
, len
, path
,
4133 FSE_ARG_FINFO
, &finfo
,
4137 release_pathbuff(path
);
4140 * nameidone has to happen before we vnode_put(dvp)
4141 * since it may need to release the fs_nodelock on the dvp
4153 * Read a block of directory entries in a file system independent format.
4156 getdirentries(p
, uap
, retval
)
4158 register struct getdirentries_args
*uap
;
4162 struct vfs_context context
;
4163 struct fileproc
*fp
;
4165 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4169 char uio_buf
[ UIO_SIZEOF(1) ];
4171 AUDIT_ARG(fd
, uap
->fd
);
4172 error
= fp_getfvp(p
, fd
, &fp
, &vp
);
4176 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
4177 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4181 if ( (error
= vnode_getwithref(vp
)) ) {
4185 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4188 if (vp
->v_type
!= VDIR
) {
4189 (void)vnode_put(vp
);
4193 context
.vc_proc
= p
;
4194 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
4196 loff
= fp
->f_fglob
->fg_offset
;
4197 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
4198 &uio_buf
[0], sizeof(uio_buf
));
4199 uio_addiov(auio
, uap
->buf
, uap
->count
);
4201 error
= VNOP_READDIR(vp
, auio
, 0, &eofflag
, (int *)NULL
, &context
);
4202 fp
->f_fglob
->fg_offset
= uio_offset(auio
);
4204 (void)vnode_put(vp
);
4210 if ((uap
->count
== uio_resid(auio
)) &&
4211 (vp
->v_op
== union_vnodeop_p
)) {
4214 lvp
= union_dircache(vp
, p
);
4215 if (lvp
!= NULLVP
) {
4216 struct vnode_attr va
;
4218 * If the directory is opaque,
4219 * then don't show lower entries
4222 VATTR_WANTED(&va
, va_flags
);
4223 error
= vnode_getattr(vp
, &va
, &context
);
4224 if (va
.va_flags
& OPAQUE
) {
4230 if (lvp
!= NULLVP
) {
4231 error
= VNOP_OPEN(lvp
, FREAD
, &context
);
4237 fp
->f_fglob
->fg_data
= (caddr_t
) lvp
;
4238 fp
->f_fglob
->fg_offset
= 0;
4239 error
= VNOP_CLOSE(vp
, FREAD
, &context
);
4251 if (((user_ssize_t
)uap
->count
== uio_resid(auio
)) &&
4252 (vp
->v_flag
& VROOT
) &&
4253 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
4254 struct vnode
*tvp
= vp
;
4255 vp
= vp
->v_mount
->mnt_vnodecovered
;
4256 vnode_getwithref(vp
);
4258 fp
->f_fglob
->fg_data
= (caddr_t
) vp
;
4259 fp
->f_fglob
->fg_offset
= 0;
4265 error
= copyout((caddr_t
)&loff
, uap
->basep
, sizeof(long));
4266 // LP64todo - fix this
4267 *retval
= uap
->count
- uio_resid(auio
);
4274 * Set the mode mask for creation of filesystem nodes.
4276 #warning XXX implement xsecurity
4278 #define UMASK_NOXSECURITY (void *)1 /* leave existing xsecurity alone */
4280 umask1(struct proc
*p
, int newmask
, __unused kauth_filesec_t fsec
, register_t
*retval
)
4282 register struct filedesc
*fdp
;
4284 AUDIT_ARG(mask
, newmask
);
4286 *retval
= fdp
->fd_cmask
;
4287 fdp
->fd_cmask
= newmask
& ALLPERMS
;
4293 umask_extended(struct proc
*p
, struct umask_extended_args
*uap
, register_t
*retval
)
4296 kauth_filesec_t xsecdst
;
4298 xsecdst
= KAUTH_FILESEC_NONE
;
4299 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
4300 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
4303 xsecdst
= KAUTH_FILESEC_NONE
;
4306 ciferror
= umask1(p
, uap
->newmask
, xsecdst
, retval
);
4308 if (xsecdst
!= KAUTH_FILESEC_NONE
)
4309 kauth_filesec_free(xsecdst
);
4314 umask(struct proc
*p
, struct umask_args
*uap
, register_t
*retval
)
4316 return(umask1(p
, uap
->newmask
, UMASK_NOXSECURITY
, retval
));
4320 * Void all references to file by ripping underlying filesystem
4325 revoke(struct proc
*p
, register struct revoke_args
*uap
, __unused register_t
*retval
)
4327 register struct vnode
*vp
;
4328 struct vnode_attr va
;
4329 struct vfs_context context
;
4331 struct nameidata nd
;
4333 context
.vc_proc
= p
;
4334 context
.vc_ucred
= kauth_cred_get();
4336 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4337 UIO_USERSPACE
, uap
->path
, &context
);
4346 VATTR_WANTED(&va
, va_uid
);
4347 if ((error
= vnode_getattr(vp
, &va
, &context
)))
4349 if (kauth_cred_getuid(context
.vc_ucred
) != va
.va_uid
&&
4350 (error
= suser(context
.vc_ucred
, &p
->p_acflag
)))
4352 if (vp
->v_usecount
> 1 || (vp
->v_flag
& VALIASED
))
4353 VNOP_REVOKE(vp
, REVOKEALL
, &context
);
4361 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
4362 * The following system calls are designed to support features
4363 * which are specific to the HFS & HFS Plus volume formats
4366 #ifdef __APPLE_API_OBSOLETE
4368 /************************************************/
4369 /* *** Following calls will be deleted soon *** */
4370 /************************************************/
4373 * Make a complex file. A complex file is one with multiple forks (data streams)
4377 mkcomplex(__unused
struct proc
*p
, __unused
struct mkcomplex_args
*uap
, __unused register_t
*retval
)
4383 * Extended stat call which returns volumeid and vnodeid as well as other info
4387 statv(__unused
struct proc
*p
,
4388 __unused
struct statv_args
*uap
,
4389 __unused register_t
*retval
)
4391 return (ENOTSUP
); /* We'll just return an error for now */
4393 } /* end of statv system call */
4396 * Extended lstat call which returns volumeid and vnodeid as well as other info
4400 lstatv(__unused
struct proc
*p
,
4401 __unused
struct lstatv_args
*uap
,
4402 __unused register_t
*retval
)
4404 return (ENOTSUP
); /* We'll just return an error for now */
4405 } /* end of lstatv system call */
4408 * Extended fstat call which returns volumeid and vnodeid as well as other info
4412 fstatv(__unused
struct proc
*p
,
4413 __unused
struct fstatv_args
*uap
,
4414 __unused register_t
*retval
)
4416 return (ENOTSUP
); /* We'll just return an error for now */
4417 } /* end of fstatv system call */
4420 /************************************************/
4421 /* *** Preceding calls will be deleted soon *** */
4422 /************************************************/
4424 #endif /* __APPLE_API_OBSOLETE */
4427 * Obtain attribute information on objects in a directory while enumerating
4428 * the directory. This call does not yet support union mounted directories.
4430 * 1.union mounted directories.
4435 getdirentriesattr (struct proc
*p
, struct getdirentriesattr_args
*uap
, register_t
*retval
)
4438 struct fileproc
*fp
;
4440 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4441 uint64_t actualcount
;
4446 struct attrlist attributelist
;
4447 struct vfs_context context
;
4449 char uio_buf
[ UIO_SIZEOF(1) ];
4450 kauth_action_t action
;
4454 /* Get the attributes into kernel space */
4455 if ((error
= copyin(uap
->alist
, (caddr_t
) &attributelist
, sizeof (attributelist
))))
4457 actualcount
= fuulong(uap
->count
);
4458 if (actualcount
== -1ULL)
4461 if ( (error
= fp_getfvp(p
, fd
, &fp
, &vp
)) )
4464 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
4465 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4469 if ( (error
= vnode_getwithref(vp
)) )
4472 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4474 if (vp
->v_type
!= VDIR
) {
4475 (void)vnode_put(vp
);
4480 /* set up the uio structure which will contain the users return buffer */
4481 loff
= fp
->f_fglob
->fg_offset
;
4482 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
4483 &uio_buf
[0], sizeof(uio_buf
));
4484 uio_addiov(auio
, uap
->buffer
, uap
->buffersize
);
4486 context
.vc_proc
= p
;
4487 context
.vc_ucred
= kauth_cred_get();
4488 tmpcount
= (u_long
) actualcount
;
4491 * If the only item requested is file names, we can let that past with
4492 * just LIST_DIRECTORY. If they want any other attributes, that means
4493 * they need SEARCH as well.
4495 action
= KAUTH_VNODE_LIST_DIRECTORY
;
4496 if ((attributelist
.commonattr
& ~ATTR_CMN_NAME
) ||
4497 attributelist
.fileattr
|| attributelist
.dirattr
)
4498 action
|= KAUTH_VNODE_SEARCH
;
4500 if ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) == 0)
4501 error
= VNOP_READDIRATTR(vp
, &attributelist
, auio
,
4502 tmpcount
, uap
->options
, &newstate
, &eofflag
,
4503 &tmpcount
, &context
);
4504 (void)vnode_put(vp
);
4505 actualcount
= tmpcount
;
4509 fp
->f_fglob
->fg_offset
= uio_offset(auio
); /* should be multiple of dirent, not variable */
4511 if ((error
= suulong(uap
->count
, actualcount
)) != 0)
4513 if ((error
= suulong(uap
->newstate
, (uint64_t)newstate
)) != 0)
4515 if ((error
= suulong(uap
->basep
, (uint64_t)loff
)) != 0)
4518 *retval
= eofflag
; /* similar to getdirentries */
4522 return (error
); /* return error earlier, an retval of 0 or 1 now */
4524 } /* end of getdirentryattr system call */
4527 * Exchange data between two files
4532 exchangedata (struct proc
*p
, register struct exchangedata_args
*uap
, __unused register_t
*retval
)
4535 struct nameidata fnd
, snd
;
4536 struct vfs_context context
;
4537 struct vnode
*fvp
, *svp
;
4543 fse_info f_finfo
, s_finfo
;
4545 context
.vc_proc
= p
;
4546 context
.vc_ucred
= kauth_cred_get();
4549 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4551 NDINIT(&fnd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4552 UIO_USERSPACE
, uap
->path1
, &context
);
4554 error
= namei(&fnd
);
4561 NDINIT(&snd
, LOOKUP
, nameiflags
| AUDITVNPATH2
,
4562 UIO_USERSPACE
, uap
->path2
, &context
);
4564 error
= namei(&snd
);
4573 * if the files are the same, return an inval error
4581 * if the files are on different volumes, return an error
4583 if (svp
->v_mount
!= fvp
->v_mount
) {
4587 if (((error
= vnode_authorize(fvp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0) ||
4588 ((error
= vnode_authorize(svp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0))
4591 if (need_fsevent(FSE_EXCHANGE
, fvp
) || kauth_authorize_fileop_has_listeners()) {
4592 fpath
= get_pathbuff();
4593 spath
= get_pathbuff();
4596 if (vn_getpath(fvp
, fpath
, &flen
) != 0 || fpath
[0] == '\0') {
4597 printf("exchange: vn_getpath(fvp=0x%x) failed <<%s>>\n",
4600 if (vn_getpath(svp
, spath
, &slen
) != 0 || spath
[0] == '\0') {
4601 printf("exchange: vn_getpath(svp=0x%x) failed <<%s>>\n",
4604 get_fse_info(fvp
, &f_finfo
, &context
);
4605 get_fse_info(svp
, &s_finfo
, &context
);
4607 /* Ok, make the call */
4608 error
= VNOP_EXCHANGE(fvp
, svp
, 0, &context
);
4613 if (fpath
!= NULL
&& spath
!= NULL
) {
4614 /* call out to allow 3rd party notification of exchangedata.
4615 * Ignore result of kauth_authorize_fileop call.
4617 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_EXCHANGE
,
4618 (uintptr_t)fpath
, (uintptr_t)spath
);
4622 tmpname
= fvp
->v_name
;
4623 fvp
->v_name
= svp
->v_name
;
4624 svp
->v_name
= tmpname
;
4626 if (fvp
->v_parent
!= svp
->v_parent
) {
4629 tmp
= fvp
->v_parent
;
4630 fvp
->v_parent
= svp
->v_parent
;
4631 svp
->v_parent
= tmp
;
4633 name_cache_unlock();
4635 if (fpath
!= NULL
&& spath
!= NULL
) {
4636 add_fsevent(FSE_EXCHANGE
, &context
,
4637 FSE_ARG_STRING
, flen
, fpath
,
4638 FSE_ARG_FINFO
, &f_finfo
,
4639 FSE_ARG_STRING
, slen
, spath
,
4640 FSE_ARG_FINFO
, &s_finfo
,
4645 release_pathbuff(spath
);
4647 release_pathbuff(fpath
);
4657 #ifdef __APPLE_API_OBSOLETE
4659 /************************************************/
4660 /* *** Following calls will be deleted soon *** */
4661 /************************************************/
4664 * Check users access to a file
4668 #warning "checkuseraccess copies a cred in from user space but"
4669 #warning "user space has no way of knowing what one looks like"
4670 #warning "this code should use the access_extended spoof-as functionality"
4672 checkuseraccess (struct proc
*p
, register struct checkuseraccess_args
*uap
, __unused register_t
*retval
)
4674 register struct vnode
*vp
;
4676 struct nameidata nd
;
4677 struct ucred template_cred
;
4678 int flags
; /*what will actually get passed to access*/
4680 struct vfs_context context
;
4681 kauth_cred_t my_cred
;
4683 /* Make sure that the number of groups is correct before we do anything */
4685 if ((uap
->ngroups
<= 0) || (uap
->ngroups
> NGROUPS
))
4688 /* Verify that the caller is root */
4690 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
4694 * Fill in the template credential structure; we use a template because
4695 * lookup can attempt to take a persistent reference.
4697 template_cred
.cr_uid
= uap
->userid
;
4698 template_cred
.cr_ngroups
= uap
->ngroups
;
4699 if ((error
= copyin(CAST_USER_ADDR_T(uap
->groups
), (caddr_t
) &(template_cred
.cr_groups
), (sizeof(gid_t
))*uap
->ngroups
)))
4702 my_cred
= kauth_cred_create(&template_cred
);
4703 context
.vc_proc
= p
;
4704 context
.vc_ucred
= my_cred
;
4706 /* Get our hands on the file */
4708 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4709 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4710 UIO_USERSPACE
, CAST_USER_ADDR_T(uap
->path
), &context
);
4712 if ((error
= namei(&nd
))) {
4713 kauth_cred_unref(&context
.vc_ucred
);
4719 /* Flags == 0 means only check for existence. */
4723 if (uap
->accessrequired
) {
4724 if (uap
->accessrequired
& R_OK
)
4725 flags
|= KAUTH_VNODE_READ_DATA
;
4726 if (uap
->accessrequired
& W_OK
)
4727 flags
|= KAUTH_VNODE_WRITE_DATA
;
4728 if (uap
->accessrequired
& X_OK
)
4729 flags
|= KAUTH_VNODE_EXECUTE
;
4731 error
= vnode_authorize(vp
, NULL
, flags
, &context
);
4735 kauth_cred_unref(&context
.vc_ucred
);
4737 } /* end of checkuseraccess system call */
4739 /************************************************/
4740 /* *** Preceding calls will be deleted soon *** */
4741 /************************************************/
4743 #endif /* __APPLE_API_OBSOLETE */
4750 searchfs (struct proc
*p
, register struct searchfs_args
*uap
, __unused register_t
*retval
)
4752 register struct vnode
*vp
;
4755 struct nameidata nd
;
4756 struct user_fssearchblock searchblock
;
4757 struct searchstate
*state
;
4758 struct attrlist
*returnattrs
;
4759 void *searchparams1
,*searchparams2
;
4761 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4765 struct vfs_context context
;
4766 char uio_buf
[ UIO_SIZEOF(1) ];
4768 context
.vc_proc
= p
;
4769 context
.vc_ucred
= kauth_cred_get();
4771 /* Start by copying in fsearchblock paramater list */
4772 if (IS_64BIT_PROCESS(p
)) {
4773 error
= copyin(uap
->searchblock
, (caddr_t
) &searchblock
, sizeof(searchblock
));
4776 struct fssearchblock tmp_searchblock
;
4777 error
= copyin(uap
->searchblock
, (caddr_t
) &tmp_searchblock
, sizeof(tmp_searchblock
));
4778 // munge into 64-bit version
4779 searchblock
.returnattrs
= CAST_USER_ADDR_T(tmp_searchblock
.returnattrs
);
4780 searchblock
.returnbuffer
= CAST_USER_ADDR_T(tmp_searchblock
.returnbuffer
);
4781 searchblock
.returnbuffersize
= tmp_searchblock
.returnbuffersize
;
4782 searchblock
.maxmatches
= tmp_searchblock
.maxmatches
;
4783 searchblock
.timelimit
.tv_sec
= tmp_searchblock
.timelimit
.tv_sec
;
4784 searchblock
.timelimit
.tv_usec
= tmp_searchblock
.timelimit
.tv_usec
;
4785 searchblock
.searchparams1
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams1
);
4786 searchblock
.sizeofsearchparams1
= tmp_searchblock
.sizeofsearchparams1
;
4787 searchblock
.searchparams2
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams2
);
4788 searchblock
.sizeofsearchparams2
= tmp_searchblock
.sizeofsearchparams2
;
4789 searchblock
.searchattrs
= tmp_searchblock
.searchattrs
;
4794 /* Do a sanity check on sizeofsearchparams1 and sizeofsearchparams2.
4796 if (searchblock
.sizeofsearchparams1
> SEARCHFS_MAX_SEARCHPARMS
||
4797 searchblock
.sizeofsearchparams2
> SEARCHFS_MAX_SEARCHPARMS
)
4800 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
4801 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
4802 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
4805 mallocsize
= searchblock
.sizeofsearchparams1
+ searchblock
.sizeofsearchparams2
+
4806 sizeof(struct attrlist
) + sizeof(struct searchstate
);
4808 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
4810 /* Now set up the various pointers to the correct place in our newly allocated memory */
4812 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
4813 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
4814 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
4816 /* Now copy in the stuff given our local variables. */
4818 if ((error
= copyin(searchblock
.searchparams1
, searchparams1
, searchblock
.sizeofsearchparams1
)))
4821 if ((error
= copyin(searchblock
.searchparams2
, searchparams2
, searchblock
.sizeofsearchparams2
)))
4824 if ((error
= copyin(searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
))))
4827 if ((error
= copyin(uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
))))
4830 /* set up the uio structure which will contain the users return buffer */
4832 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
4833 &uio_buf
[0], sizeof(uio_buf
));
4834 uio_addiov(auio
, searchblock
.returnbuffer
, searchblock
.returnbuffersize
);
4837 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4838 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4839 UIO_USERSPACE
, uap
->path
, &context
);
4850 * If searchblock.maxmatches == 0, then skip the search. This has happened
4851 * before and sometimes the underlyning code doesnt deal with it well.
4853 if (searchblock
.maxmatches
== 0) {
4859 Allright, we have everything we need, so lets make that call.
4861 We keep special track of the return value from the file system:
4862 EAGAIN is an acceptable error condition that shouldn't keep us
4863 from copying out any results...
4866 fserror
= VNOP_SEARCHFS(vp
,
4869 &searchblock
.searchattrs
,
4870 searchblock
.maxmatches
,
4871 &searchblock
.timelimit
,
4884 /* Now copy out the stuff that needs copying out. That means the number of matches, the
4885 search state. Everything was already put into he return buffer by the vop call. */
4887 if ((error
= copyout((caddr_t
) state
, uap
->state
, sizeof(struct searchstate
))) != 0)
4890 if ((error
= suulong(uap
->nummatches
, (uint64_t)nummatches
)) != 0)
4897 FREE(searchparams1
,M_TEMP
);
4902 } /* end of searchfs system call */
4906 * Make a filesystem-specific control call:
4910 fsctl (struct proc
*p
, struct fsctl_args
*uap
, __unused register_t
*retval
)
4914 struct nameidata nd
;
4916 u_long cmd
= uap
->cmd
;
4917 register u_int size
;
4918 #define STK_PARAMS 128
4919 char stkbuf
[STK_PARAMS
];
4921 struct vfs_context context
;
4923 context
.vc_proc
= p
;
4924 context
.vc_ucred
= kauth_cred_get();
4926 size
= IOCPARM_LEN(cmd
);
4927 if (size
> IOCPARM_MAX
) return (EINVAL
);
4929 is64bit
= proc_is64bit(p
);
4932 if (size
> sizeof (stkbuf
)) {
4933 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
4941 error
= copyin(uap
->data
, data
, size
);
4942 if (error
) goto FSCtl_Exit
;
4945 *(user_addr_t
*)data
= uap
->data
;
4948 *(uint32_t *)data
= (uint32_t)uap
->data
;
4951 } else if ((cmd
& IOC_OUT
) && size
) {
4953 * Zero the buffer so the user always
4954 * gets back something deterministic.
4957 } else if (cmd
& IOC_VOID
) {
4959 *(user_addr_t
*)data
= uap
->data
;
4962 *(uint32_t *)data
= (uint32_t)uap
->data
;
4966 /* Get the vnode for the file we are getting info on: */
4968 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4969 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, uap
->path
, &context
);
4970 if ((error
= namei(&nd
))) goto FSCtl_Exit
;
4972 /* Invoke the filesystem-specific code */
4973 error
= VNOP_IOCTL(nd
.ni_vp
, IOCBASECMD(cmd
), data
, uap
->options
, &context
);
4975 vnode_put(nd
.ni_vp
);
4979 * Copy any data to user, size was
4980 * already set and checked above.
4982 if (error
== 0 && (cmd
& IOC_OUT
) && size
)
4983 error
= copyout(data
, uap
->data
, size
);
4986 if (memp
) kfree(memp
, size
);
4990 /* end of fsctl system call */
4993 * An in-kernel sync for power management to call.
4995 __private_extern__
int
5000 struct sync_args data
;
5005 error
= sync(current_proc(), &data
, &retval
[0]);
5009 } /* end of sync_internal call */
5013 * Retrieve the data of an extended attribute.
5016 getxattr(struct proc
*p
, struct getxattr_args
*uap
, user_ssize_t
*retval
)
5019 struct nameidata nd
;
5020 char attrname
[XATTR_MAXNAMELEN
+1];
5021 struct vfs_context context
;
5023 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5024 size_t attrsize
= 0;
5028 char uio_buf
[ UIO_SIZEOF(1) ];
5030 context
.vc_proc
= p
;
5031 context
.vc_ucred
= kauth_cred_get();
5033 if (uap
->options
& XATTR_NOSECURITY
)
5036 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5037 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5038 if ((error
= namei(&nd
))) {
5044 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5047 if (xattr_protected(attrname
)) {
5051 if (uap
->value
&& uap
->size
> 0) {
5052 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
5053 &uio_buf
[0], sizeof(uio_buf
));
5054 uio_addiov(auio
, uap
->value
, uap
->size
);
5057 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, &context
);
5062 *retval
= uap
->size
- uio_resid(auio
);
5064 *retval
= (user_ssize_t
)attrsize
;
5071 * Retrieve the data of an extended attribute.
5074 fgetxattr(struct proc
*p
, struct fgetxattr_args
*uap
, user_ssize_t
*retval
)
5077 char attrname
[XATTR_MAXNAMELEN
+1];
5078 struct vfs_context context
;
5080 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5081 size_t attrsize
= 0;
5084 char uio_buf
[ UIO_SIZEOF(1) ];
5086 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5089 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5092 if ( (error
= vnode_getwithref(vp
)) ) {
5096 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5099 if (xattr_protected(attrname
)) {
5103 if (uap
->value
&& uap
->size
> 0) {
5104 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
5105 &uio_buf
[0], sizeof(uio_buf
));
5106 uio_addiov(auio
, uap
->value
, uap
->size
);
5108 context
.vc_proc
= p
;
5109 context
.vc_ucred
= kauth_cred_get();
5111 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, &context
);
5113 (void)vnode_put(vp
);
5117 *retval
= uap
->size
- uio_resid(auio
);
5119 *retval
= (user_ssize_t
)attrsize
;
5125 * Set the data of an extended attribute.
5128 setxattr(struct proc
*p
, struct setxattr_args
*uap
, int *retval
)
5131 struct nameidata nd
;
5132 char attrname
[XATTR_MAXNAMELEN
+1];
5133 struct vfs_context context
;
5135 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5139 char uio_buf
[ UIO_SIZEOF(1) ];
5141 context
.vc_proc
= p
;
5142 context
.vc_ucred
= kauth_cred_get();
5144 if (uap
->options
& XATTR_NOSECURITY
)
5147 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5150 if (xattr_protected(attrname
))
5152 if (uap
->value
== 0 || uap
->size
== 0) {
5156 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5157 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5158 if ((error
= namei(&nd
))) {
5164 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
5165 &uio_buf
[0], sizeof(uio_buf
));
5166 uio_addiov(auio
, uap
->value
, uap
->size
);
5168 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, &context
);
5175 * Set the data of an extended attribute.
5178 fsetxattr(struct proc
*p
, struct fsetxattr_args
*uap
, int *retval
)
5181 char attrname
[XATTR_MAXNAMELEN
+1];
5182 struct vfs_context context
;
5184 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5187 char uio_buf
[ UIO_SIZEOF(1) ];
5189 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5192 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5195 if (xattr_protected(attrname
))
5197 if (uap
->value
== 0 || uap
->size
== 0) {
5200 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5203 if ( (error
= vnode_getwithref(vp
)) ) {
5207 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
5208 &uio_buf
[0], sizeof(uio_buf
));
5209 uio_addiov(auio
, uap
->value
, uap
->size
);
5210 context
.vc_proc
= p
;
5211 context
.vc_ucred
= kauth_cred_get();
5213 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, &context
);
5221 * Remove an extended attribute.
5223 #warning "code duplication"
5225 removexattr(struct proc
*p
, struct removexattr_args
*uap
, int *retval
)
5228 struct nameidata nd
;
5229 char attrname
[XATTR_MAXNAMELEN
+1];
5230 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5231 struct vfs_context context
;
5236 context
.vc_proc
= p
;
5237 context
.vc_ucred
= kauth_cred_get();
5239 if (uap
->options
& XATTR_NOSECURITY
)
5242 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
5246 if (xattr_protected(attrname
))
5248 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5249 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5250 if ((error
= namei(&nd
))) {
5256 error
= vn_removexattr(vp
, attrname
, uap
->options
, &context
);
5263 * Remove an extended attribute.
5265 #warning "code duplication"
5267 fremovexattr(struct proc
*p
, struct fremovexattr_args
*uap
, int *retval
)
5270 char attrname
[XATTR_MAXNAMELEN
+1];
5271 struct vfs_context context
;
5275 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5278 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
5282 if (xattr_protected(attrname
))
5284 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5287 if ( (error
= vnode_getwithref(vp
)) ) {
5291 context
.vc_proc
= p
;
5292 context
.vc_ucred
= kauth_cred_get();
5294 error
= vn_removexattr(vp
, attrname
, uap
->options
, &context
);
5302 * Retrieve the list of extended attribute names.
5304 #warning "code duplication"
5306 listxattr(struct proc
*p
, struct listxattr_args
*uap
, user_ssize_t
*retval
)
5309 struct nameidata nd
;
5310 struct vfs_context context
;
5312 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5313 size_t attrsize
= 0;
5316 char uio_buf
[ UIO_SIZEOF(1) ];
5318 context
.vc_proc
= p
;
5319 context
.vc_ucred
= kauth_cred_get();
5321 if (uap
->options
& XATTR_NOSECURITY
)
5324 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5325 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5326 if ((error
= namei(&nd
))) {
5331 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
5332 // LP64todo - fix this!
5333 auio
= uio_createwithbuffer(1, 0, spacetype
,
5334 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
5335 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
5338 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, &context
);
5342 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
5344 *retval
= (user_ssize_t
)attrsize
;
5350 * Retrieve the list of extended attribute names.
5352 #warning "code duplication"
5354 flistxattr(struct proc
*p
, struct flistxattr_args
*uap
, user_ssize_t
*retval
)
5357 struct vfs_context context
;
5359 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5360 size_t attrsize
= 0;
5362 char uio_buf
[ UIO_SIZEOF(1) ];
5364 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5367 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5370 if ( (error
= vnode_getwithref(vp
)) ) {
5374 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
5375 // LP64todo - fix this!
5376 auio
= uio_createwithbuffer(1, 0, spacetype
,
5377 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
5378 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
5380 context
.vc_proc
= p
;
5381 context
.vc_ucred
= kauth_cred_get();
5383 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, &context
);
5388 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
5390 *retval
= (user_ssize_t
)attrsize
;
5396 * Common routine to handle various flavors of statfs data heading out
5400 munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
5401 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
5402 boolean_t partial_copy
)
5405 int my_size
, copy_size
;
5408 struct user_statfs sfs
;
5409 my_size
= copy_size
= sizeof(sfs
);
5410 bzero(&sfs
, my_size
);
5411 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
5412 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
5413 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
5414 sfs
.f_bsize
= (user_long_t
)sfsp
->f_bsize
;
5415 sfs
.f_iosize
= (user_long_t
)sfsp
->f_iosize
;
5416 sfs
.f_blocks
= (user_long_t
)sfsp
->f_blocks
;
5417 sfs
.f_bfree
= (user_long_t
)sfsp
->f_bfree
;
5418 sfs
.f_bavail
= (user_long_t
)sfsp
->f_bavail
;
5419 sfs
.f_files
= (user_long_t
)sfsp
->f_files
;
5420 sfs
.f_ffree
= (user_long_t
)sfsp
->f_ffree
;
5421 sfs
.f_fsid
= sfsp
->f_fsid
;
5422 sfs
.f_owner
= sfsp
->f_owner
;
5423 strncpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
-1);
5424 strncpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
-1);
5425 strncpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
-1);
5428 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
5430 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
5434 my_size
= copy_size
= sizeof(sfs
);
5435 bzero(&sfs
, my_size
);
5437 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
5438 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
5439 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
5442 * It's possible for there to be more than 2^^31 blocks in the filesystem, so we
5443 * have to fudge the numbers here in that case. We inflate the blocksize in order
5444 * to reflect the filesystem size as best we can.
5446 if ((sfsp
->f_blocks
> LONG_MAX
)
5447 /* Hack for 4061702 . I think the real fix is for Carbon to
5448 * look for some volume capability and not depend on hidden
5449 * semantics agreed between a FS and carbon.
5450 * f_blocks, f_bfree, and f_bavail set to -1 is the trigger
5451 * for Carbon to set bNoVolumeSizes volume attribute.
5452 * Without this the webdavfs files cannot be copied onto
5453 * disk as they look huge. This change should not affect
5454 * XSAN as they should not setting these to -1..
5456 && (sfsp
->f_blocks
!= 0xffffffffffffffff)
5457 && (sfsp
->f_bfree
!= 0xffffffffffffffff)
5458 && (sfsp
->f_bavail
!= 0xffffffffffffffff)) {
5462 * Work out how far we have to shift the block count down to make it fit.
5463 * Note that it's possible to have to shift so far that the resulting
5464 * blocksize would be unreportably large. At that point, we will clip
5465 * any values that don't fit.
5467 * For safety's sake, we also ensure that f_iosize is never reported as
5468 * being smaller than f_bsize.
5470 for (shift
= 0; shift
< 32; shift
++) {
5471 if ((sfsp
->f_blocks
>> shift
) <= LONG_MAX
)
5473 if ((sfsp
->f_bsize
<< (shift
+ 1)) > LONG_MAX
)
5476 #define __SHIFT_OR_CLIP(x, s) ((((x) >> (s)) > LONG_MAX) ? LONG_MAX : ((x) >> (s)))
5477 sfs
.f_blocks
= (long)__SHIFT_OR_CLIP(sfsp
->f_blocks
, shift
);
5478 sfs
.f_bfree
= (long)__SHIFT_OR_CLIP(sfsp
->f_bfree
, shift
);
5479 sfs
.f_bavail
= (long)__SHIFT_OR_CLIP(sfsp
->f_bavail
, shift
);
5480 #undef __SHIFT_OR_CLIP
5481 sfs
.f_bsize
= (long)(sfsp
->f_bsize
<< shift
);
5482 sfs
.f_iosize
= lmax(sfsp
->f_iosize
, sfsp
->f_bsize
);
5484 /* filesystem is small enough to be reported honestly */
5485 sfs
.f_bsize
= (long)sfsp
->f_bsize
;
5486 sfs
.f_iosize
= (long)sfsp
->f_iosize
;
5487 sfs
.f_blocks
= (long)sfsp
->f_blocks
;
5488 sfs
.f_bfree
= (long)sfsp
->f_bfree
;
5489 sfs
.f_bavail
= (long)sfsp
->f_bavail
;
5491 sfs
.f_files
= (long)sfsp
->f_files
;
5492 sfs
.f_ffree
= (long)sfsp
->f_ffree
;
5493 sfs
.f_fsid
= sfsp
->f_fsid
;
5494 sfs
.f_owner
= sfsp
->f_owner
;
5495 strncpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
-1);
5496 strncpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
-1);
5497 strncpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
-1);
5500 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
5502 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
5505 if (sizep
!= NULL
) {
5512 * copy stat structure into user_stat structure.
5514 void munge_stat(struct stat
*sbp
, struct user_stat
*usbp
)
5516 bzero(usbp
, sizeof(struct user_stat
));
5518 usbp
->st_dev
= sbp
->st_dev
;
5519 usbp
->st_ino
= sbp
->st_ino
;
5520 usbp
->st_mode
= sbp
->st_mode
;
5521 usbp
->st_nlink
= sbp
->st_nlink
;
5522 usbp
->st_uid
= sbp
->st_uid
;
5523 usbp
->st_gid
= sbp
->st_gid
;
5524 usbp
->st_rdev
= sbp
->st_rdev
;
5525 #ifndef _POSIX_SOURCE
5526 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
5527 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
5528 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
5529 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
5530 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
5531 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
5533 usbp
->st_atime
= sbp
->st_atime
;
5534 usbp
->st_atimensec
= sbp
->st_atimensec
;
5535 usbp
->st_mtime
= sbp
->st_mtime
;
5536 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
5537 usbp
->st_ctime
= sbp
->st_ctime
;
5538 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
5540 usbp
->st_size
= sbp
->st_size
;
5541 usbp
->st_blocks
= sbp
->st_blocks
;
5542 usbp
->st_blksize
= sbp
->st_blksize
;
5543 usbp
->st_flags
= sbp
->st_flags
;
5544 usbp
->st_gen
= sbp
->st_gen
;
5545 usbp
->st_lspare
= sbp
->st_lspare
;
5546 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
5547 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];