2 * Copyright (c) 1995-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 * Copyright (c) 1989, 1993
32 * The Regents of the University of California. All rights reserved.
33 * (c) UNIX System Laboratories, Inc.
34 * All or some portions of this file are derived from material licensed
35 * to the University of California by American Telephone and Telegraph
36 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
37 * the permission of UNIX System Laboratories, Inc.
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 * 3. All advertising materials mentioning features or use of this software
48 * must display the following acknowledgement:
49 * This product includes software developed by the University of
50 * California, Berkeley and its contributors.
51 * 4. Neither the name of the University nor the names of its contributors
52 * may be used to endorse or promote products derived from this software
53 * without specific prior written permission.
55 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67 * @(#)vfs_syscalls.c 8.41 (Berkeley) 6/15/95
70 #include <sys/param.h>
71 #include <sys/systm.h>
72 #include <sys/namei.h>
73 #include <sys/filedesc.h>
74 #include <sys/kernel.h>
75 #include <sys/file_internal.h>
77 #include <sys/vnode_internal.h>
78 #include <sys/mount_internal.h>
79 #include <sys/proc_internal.h>
80 #include <sys/kauth.h>
81 #include <sys/uio_internal.h>
82 #include <sys/malloc.h>
84 #include <sys/dirent.h>
86 #include <sys/sysctl.h>
88 #include <sys/quota.h>
89 #include <sys/kdebug.h>
90 #include <sys/fsevents.h>
91 #include <sys/sysproto.h>
92 #include <sys/xattr.h>
93 #include <sys/ubc_internal.h>
94 #include <machine/cons.h>
95 #include <machine/limits.h>
96 #include <miscfs/specfs/specdev.h>
98 #include <bsm/audit_kernel.h>
99 #include <bsm/audit_kevents.h>
101 #include <mach/mach_types.h>
102 #include <kern/kern_types.h>
103 #include <kern/kalloc.h>
105 #include <vm/vm_pageout.h>
107 #include <architecture/byte_order.h>
108 #include <libkern/OSAtomic.h>
112 * The currently logged-in user, for ownership of files/directories whose on-disk
113 * permissions are ignored:
117 static int change_dir(struct nameidata
*ndp
, vfs_context_t ctx
);
118 static void checkdirs(struct vnode
*olddp
, vfs_context_t ctx
);
119 void enablequotas(struct mount
*mp
, vfs_context_t ctx
);
120 static int getfsstat_callback(mount_t mp
, void * arg
);
121 static int getutimes(user_addr_t usrtvp
, struct timespec
*tsp
);
122 static int setutimes(vfs_context_t ctx
, struct vnode
*vp
, const struct timespec
*ts
, int nullflag
);
123 static int sync_callback(mount_t
, void *);
124 static int munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
125 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
126 boolean_t partial_copy
);
128 __private_extern__
int sync_internal(void);
130 #ifdef __APPLE_API_OBSOLETE
132 int fd
; /* file descriptor of the target file */
133 struct vstat
*vsb
; /* vstat structure for returned info */
136 const char *path
; /* pathname of the target file */
137 struct vstat
*vsb
; /* vstat structure for returned info */
139 struct mkcomplex_args
{
140 const char *path
; /* pathname of the file to be created */
141 mode_t mode
; /* access mode for the newly created file */
142 u_long type
; /* format of the complex file */
145 const char *path
; /* pathname of the target file */
146 struct vstat
*vsb
; /* vstat structure for returned info */
149 int fstatv(struct proc
*p
, struct fstatv_args
*uap
, register_t
*retval
);
150 int lstatv(struct proc
*p
, struct lstatv_args
*uap
, register_t
*retval
);
151 int mkcomplex(struct proc
*p
, struct mkcomplex_args
*uap
, register_t
*retval
);
152 int statv(struct proc
*p
, struct statv_args
*uap
, register_t
*retval
);
154 #endif /* __APPLE_API_OBSOLETE */
157 extern int (**union_vnodeop_p
)(void *);
158 extern struct vnode
*union_dircache(struct vnode
*, struct proc
*);
161 /* counts number of mount and unmount operations */
162 unsigned int vfs_nummntops
=0;
164 extern struct fileops vnops
;
166 extern void mount_list_add(mount_t mp
);
167 extern void mount_list_remove(mount_t mp
);
168 extern int mount_refdrain(mount_t mp
);
169 extern int vcount(struct vnode
*vp
);
173 * Virtual File System System Calls
177 * Mount a file system.
181 mount(struct proc
*p
, register struct mount_args
*uap
, __unused register_t
*retval
)
184 struct vnode
*devvp
= NULLVP
;
185 struct vnode
*device_vnode
= NULLVP
;
187 struct vfstable
*vfsp
;
189 struct vnode_attr va
;
190 struct vfs_context context
;
192 struct nameidata nd1
;
193 char fstypename
[MFSNAMELEN
];
195 user_addr_t devpath
= USER_ADDR_NULL
;
196 user_addr_t fsmountargs
= uap
->data
;
201 boolean_t is_rwlock_locked
= FALSE
;
203 AUDIT_ARG(fflags
, uap
->flags
);
206 context
.vc_ucred
= kauth_cred_get();
207 is_64bit
= proc_is64bit(p
);
210 * Get vnode to be covered
212 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
213 UIO_USERSPACE
, uap
->path
, &context
);
219 if ((vp
->v_flag
& VROOT
) &&
220 (vp
->v_mount
->mnt_flag
& MNT_ROOTFS
))
221 uap
->flags
|= MNT_UPDATE
;
223 if (uap
->flags
& MNT_UPDATE
) {
224 if ((vp
->v_flag
& VROOT
) == 0) {
230 /* unmount in progress return error */
232 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
238 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
239 is_rwlock_locked
= TRUE
;
241 * We only allow the filesystem to be reloaded if it
242 * is currently mounted read-only.
244 if ((uap
->flags
& MNT_RELOAD
) &&
245 ((mp
->mnt_flag
& MNT_RDONLY
) == 0)) {
250 * Only root, or the user that did the original mount is
251 * permitted to update it.
253 if (mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(context
.vc_ucred
) &&
254 (error
= suser(context
.vc_ucred
, &p
->p_acflag
))) {
258 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV,
259 * and MNT_NOEXEC if mount point is already MNT_NOEXEC.
261 if (suser(context
.vc_ucred
, NULL
)) {
262 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
263 if (mp
->mnt_flag
& MNT_NOEXEC
)
264 uap
->flags
|= MNT_NOEXEC
;
269 uap
->flags
& (MNT_RELOAD
| MNT_FORCE
| MNT_UPDATE
);
271 vfsp
= mp
->mnt_vtable
;
275 * If the user is not root, ensure that they own the directory
276 * onto which we are attempting to mount.
279 VATTR_WANTED(&va
, va_uid
);
280 if ((error
= vnode_getattr(vp
, &va
, &context
)) ||
281 (va
.va_uid
!= kauth_cred_getuid(context
.vc_ucred
) &&
282 (error
= suser(context
.vc_ucred
, &p
->p_acflag
)))) {
286 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV, and
287 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
289 if (suser(context
.vc_ucred
, NULL
)) {
290 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
291 if (vp
->v_mount
->mnt_flag
& MNT_NOEXEC
)
292 uap
->flags
|= MNT_NOEXEC
;
294 if ( (error
= VNOP_FSYNC(vp
, MNT_WAIT
, &context
)) )
297 if ( (error
= buf_invalidateblks(vp
, BUF_WRITE_DATA
, 0, 0)) )
300 if (vp
->v_type
!= VDIR
) {
304 if ( (error
= copyinstr(uap
->type
, fstypename
, MFSNAMELEN
, &dummy
)) )
307 /* XXXAUDIT: Should we capture the type on the error path as well? */
308 AUDIT_ARG(text
, fstypename
);
310 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
311 if (!strcmp(vfsp
->vfc_name
, fstypename
))
318 if (ISSET(vp
->v_flag
, VMOUNT
) && (vp
->v_mountedhere
!= NULL
)) {
322 SET(vp
->v_flag
, VMOUNT
);
325 * Allocate and initialize the filesystem.
327 MALLOC_ZONE(mp
, struct mount
*, (u_long
)sizeof(struct mount
),
329 bzero((char *)mp
, (u_long
)sizeof(struct mount
));
332 /* Initialize the default IO constraints */
333 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
334 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
335 mp
->mnt_maxsegreadsize
= mp
->mnt_maxreadcnt
;
336 mp
->mnt_maxsegwritesize
= mp
->mnt_maxwritecnt
;
337 mp
->mnt_devblocksize
= DEV_BSIZE
;
339 TAILQ_INIT(&mp
->mnt_vnodelist
);
340 TAILQ_INIT(&mp
->mnt_workerqueue
);
341 TAILQ_INIT(&mp
->mnt_newvnodes
);
343 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
344 is_rwlock_locked
= TRUE
;
345 mp
->mnt_op
= vfsp
->vfc_vfsops
;
346 mp
->mnt_vtable
= vfsp
;
348 vfsp
->vfc_refcount
++;
350 //mp->mnt_stat.f_type = vfsp->vfc_typenum;
351 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
352 strncpy(mp
->mnt_vfsstat
.f_fstypename
, vfsp
->vfc_name
, MFSTYPENAMELEN
);
353 strncpy(mp
->mnt_vfsstat
.f_mntonname
, nd
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
354 mp
->mnt_vnodecovered
= vp
;
355 mp
->mnt_vfsstat
.f_owner
= kauth_cred_getuid(context
.vc_ucred
);
357 /* XXX 3762912 hack to support HFS filesystem 'owner' - filesystem may update later */
358 vfs_setowner(mp
, KAUTH_UID_NONE
, KAUTH_GID_NONE
);
362 * Set the mount level flags.
364 if (uap
->flags
& MNT_RDONLY
)
365 mp
->mnt_flag
|= MNT_RDONLY
;
366 else if (mp
->mnt_flag
& MNT_RDONLY
)
367 mp
->mnt_kern_flag
|= MNTK_WANTRDWR
;
368 mp
->mnt_flag
&= ~(MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
369 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
370 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
);
371 mp
->mnt_flag
|= uap
->flags
& (MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
372 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
373 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
|
376 if (vfsp
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
378 if ( (error
= copyin(fsmountargs
, (caddr_t
)&devpath
, sizeof(devpath
))) )
380 fsmountargs
+= sizeof(devpath
);
383 if ( (error
= copyin(fsmountargs
, (caddr_t
)&tmp
, sizeof(tmp
))) )
385 /* munge into LP64 addr */
386 devpath
= CAST_USER_ADDR_T(tmp
);
387 fsmountargs
+= sizeof(tmp
);
390 /* if it is not update and device name needs to be parsed */
392 NDINIT(&nd1
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, devpath
, &context
);
393 if ( (error
= namei(&nd1
)) )
396 strncpy(mp
->mnt_vfsstat
.f_mntfromname
, nd1
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
401 if (devvp
->v_type
!= VBLK
) {
405 if (major(devvp
->v_rdev
) >= nblkdev
) {
410 * If mount by non-root, then verify that user has necessary
411 * permissions on the device.
413 if (suser(context
.vc_ucred
, NULL
) != 0) {
414 accessmode
= KAUTH_VNODE_READ_DATA
;
415 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
416 accessmode
|= KAUTH_VNODE_WRITE_DATA
;
417 if ((error
= vnode_authorize(devvp
, NULL
, accessmode
, &context
)) != 0)
421 if (devpath
&& ((uap
->flags
& MNT_UPDATE
) == 0)) {
422 if ( (error
= vnode_ref(devvp
)) )
425 * Disallow multiple mounts of the same device.
426 * Disallow mounting of a device that is currently in use
427 * (except for root, which might share swap device for miniroot).
428 * Flush out any old buffers remaining from a previous use.
430 if ( (error
= vfs_mountedon(devvp
)) )
433 if (vcount(devvp
) > 1 && !(vfs_flags(mp
) & MNT_ROOTFS
)) {
437 if ( (error
= VNOP_FSYNC(devvp
, MNT_WAIT
, &context
)) ) {
441 if ( (error
= buf_invalidateblks(devvp
, BUF_WRITE_DATA
, 0, 0)) )
444 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
445 if ( (error
= VNOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, &context
)) )
448 mp
->mnt_devvp
= devvp
;
449 device_vnode
= devvp
;
451 if ((mp
->mnt_flag
& MNT_RDONLY
) && (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)) {
453 * If upgrade to read-write by non-root, then verify
454 * that user has necessary permissions on the device.
456 device_vnode
= mp
->mnt_devvp
;
457 if (device_vnode
&& suser(context
.vc_ucred
, NULL
)) {
458 if ((error
= vnode_authorize(device_vnode
, NULL
,
459 KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0)
463 device_vnode
= NULLVP
;
469 * Mount the filesystem.
471 error
= VFS_MOUNT(mp
, device_vnode
, fsmountargs
, &context
);
473 if (uap
->flags
& MNT_UPDATE
) {
474 if (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)
475 mp
->mnt_flag
&= ~MNT_RDONLY
;
477 (MNT_UPDATE
| MNT_RELOAD
| MNT_FORCE
);
478 mp
->mnt_kern_flag
&=~ MNTK_WANTRDWR
;
481 vfs_event_signal(NULL
, VQ_UPDATE
, (intptr_t)NULL
);
482 lck_rw_done(&mp
->mnt_rwlock
);
483 is_rwlock_locked
= FALSE
;
485 enablequotas(mp
,&context
);
489 * Put the new filesystem on the mount list after root.
492 CLR(vp
->v_flag
, VMOUNT
);
495 vp
->v_mountedhere
= mp
;
500 vfs_event_signal(NULL
, VQ_MOUNT
, (intptr_t)NULL
);
501 checkdirs(vp
, &context
);
502 lck_rw_done(&mp
->mnt_rwlock
);
503 is_rwlock_locked
= FALSE
;
506 * there is no cleanup code here so I have made it void
507 * we need to revisit this
509 (void)VFS_START(mp
, 0, &context
);
511 /* increment the operations count */
512 OSAddAtomic(1, (SInt32
*)&vfs_nummntops
);
513 enablequotas(mp
,&context
);
516 device_vnode
->v_specflags
|= SI_MOUNTEDON
;
519 * cache the IO attributes for the underlying physical media...
520 * an error return indicates the underlying driver doesn't
521 * support all the queries necessary... however, reasonable
522 * defaults will have been set, so no reason to bail or care
524 vfs_init_io_attributes(device_vnode
, mp
);
527 CLR(vp
->v_flag
, VMOUNT
);
529 mp
->mnt_vtable
->vfc_refcount
--;
533 VNOP_CLOSE(device_vnode
, ronly
? FREAD
: FREAD
|FWRITE
, &context
);
534 vnode_rele(device_vnode
);
536 lck_rw_done(&mp
->mnt_rwlock
);
537 is_rwlock_locked
= FALSE
;
538 mount_lock_destroy(mp
);
539 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
544 * drop I/O count on covered 'vp' and
545 * on the device vp if there was one
547 if (devpath
&& devvp
)
556 if (devpath
&& devvp
)
559 /* Release mnt_rwlock only when it was taken */
560 if (is_rwlock_locked
== TRUE
) {
561 lck_rw_done(&mp
->mnt_rwlock
);
564 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
573 enablequotas(struct mount
*mp
, vfs_context_t context
)
575 struct nameidata qnd
;
577 char qfpath
[MAXPATHLEN
];
578 const char *qfname
= QUOTAFILENAME
;
579 const char *qfopsname
= QUOTAOPSNAME
;
580 const char *qfextension
[] = INITQFNAMES
;
582 if ((strcmp(mp
->mnt_vfsstat
.f_fstypename
, "hfs") != 0 )
583 && (strcmp( mp
->mnt_vfsstat
.f_fstypename
, "ufs") != 0))
587 * Enable filesystem disk quotas if necessary.
588 * We ignore errors as this should not interfere with final mount
590 for (type
=0; type
< MAXQUOTAS
; type
++) {
591 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfopsname
, qfextension
[type
]);
592 NDINIT(&qnd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE32
, CAST_USER_ADDR_T(qfpath
), context
);
593 if (namei(&qnd
) != 0)
594 continue; /* option file to trigger quotas is not present */
595 vnode_put(qnd
.ni_vp
);
597 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfname
, qfextension
[type
]);
599 (void) VFS_QUOTACTL(mp
, QCMD(Q_QUOTAON
, type
), 0, qfpath
, context
);
605 * Scan all active processes to see if any of them have a current
606 * or root directory onto which the new filesystem has just been
607 * mounted. If so, replace them with the new mount point.
610 checkdirs(olddp
, context
)
612 vfs_context_t context
;
614 struct filedesc
*fdp
;
618 struct vnode
*fdp_cvp
;
619 struct vnode
*fdp_rvp
;
620 int cdir_changed
= 0;
621 int rdir_changed
= 0;
622 boolean_t funnel_state
;
624 if (olddp
->v_usecount
== 1)
626 if (VFS_ROOT(olddp
->v_mountedhere
, &newdp
, context
))
627 panic("mount: lost mount");
628 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
630 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
633 if (fdp
== (struct filedesc
*)0) {
637 fdp_cvp
= fdp
->fd_cdir
;
638 fdp_rvp
= fdp
->fd_rdir
;
641 if (fdp_cvp
== olddp
) {
648 if (fdp_rvp
== olddp
) {
655 if (cdir_changed
|| rdir_changed
) {
657 fdp
->fd_cdir
= fdp_cvp
;
658 fdp
->fd_rdir
= fdp_rvp
;
662 if (rootvnode
== olddp
) {
668 thread_funnel_set(kernel_flock
, funnel_state
);
674 * Unmount a file system.
676 * Note: unmount takes a path to the vnode mounted on as argument,
677 * not special file (as before).
681 unmount(struct proc
*p
, register struct unmount_args
*uap
, __unused register_t
*retval
)
683 register struct vnode
*vp
;
687 struct vfs_context context
;
690 context
.vc_ucred
= kauth_cred_get();
692 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
693 UIO_USERSPACE
, uap
->path
, &context
);
702 * Must be the root of the filesystem
704 if ((vp
->v_flag
& VROOT
) == 0) {
709 return (safedounmount(mp
, uap
->flags
, p
));
713 * Do the actual file system unmount, prevent some common foot shooting.
715 * XXX Should take a "vfs_context_t" instead of a "struct proc *"
718 safedounmount(mp
, flags
, p
)
726 * Only root, or the user that did the original mount is
727 * permitted to unmount this filesystem.
729 if ((mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(kauth_cred_get())) &&
730 (error
= suser(kauth_cred_get(), &p
->p_acflag
)))
734 * Don't allow unmounting the root file system.
736 if (mp
->mnt_flag
& MNT_ROOTFS
)
737 return (EBUSY
); /* the root is always busy */
739 return (dounmount(mp
, flags
, p
));
743 * Do the actual file system unmount.
746 dounmount(mp
, flags
, p
)
747 register struct mount
*mp
;
751 struct vnode
*coveredvp
= (vnode_t
)0;
754 struct vfs_context context
;
755 int forcedunmount
= 0;
759 context
.vc_ucred
= kauth_cred_get();
761 if (flags
& MNT_FORCE
)
764 /* XXX post jaguar fix LK_DRAIN - then clean this up */
765 if ((flags
& MNT_FORCE
)) {
766 mp
->mnt_kern_flag
|= MNTK_FRCUNMOUNT
;
767 mp
->mnt_lflag
|= MNT_LFORCE
;
769 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
770 mp
->mnt_lflag
|= MNT_LWAIT
;
771 msleep((caddr_t
)mp
, &mp
->mnt_mlock
, (PVFS
| PDROP
), "dounmount", 0 );
773 * The prior unmount attempt has probably succeeded.
774 * Do not dereference mp here - returning EBUSY is safest.
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 open_extended(struct proc
*p
, struct open_extended_args
*uap
, register_t
*retval
)
1536 struct vfs_context context
;
1537 register struct filedesc
*fdp
= p
->p_fd
;
1539 kauth_filesec_t xsecdst
;
1540 struct vnode_attr va
;
1544 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
1545 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
1548 context
.vc_proc
= p
;
1549 context
.vc_ucred
= kauth_cred_get();
1552 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
1553 VATTR_SET(&va
, va_mode
, cmode
);
1554 if (uap
->uid
!= KAUTH_UID_NONE
)
1555 VATTR_SET(&va
, va_uid
, uap
->uid
);
1556 if (uap
->gid
!= KAUTH_GID_NONE
)
1557 VATTR_SET(&va
, va_gid
, uap
->gid
);
1558 if (xsecdst
!= NULL
)
1559 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
1561 ciferror
= open1(&context
, uap
->path
, uap
->flags
, &va
, retval
);
1562 if (xsecdst
!= NULL
)
1563 kauth_filesec_free(xsecdst
);
1569 open(struct proc
*p
, struct open_args
*uap
, register_t
*retval
)
1571 struct vfs_context context
;
1572 register struct filedesc
*fdp
= p
->p_fd
;
1573 struct vnode_attr va
;
1576 context
.vc_proc
= p
;
1577 context
.vc_ucred
= kauth_cred_get();
1580 /* Mask off all but regular access permissions */
1581 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
1582 VATTR_SET(&va
, va_mode
, cmode
& ACCESSPERMS
);
1584 return(open1(&context
, uap
->path
, uap
->flags
, &va
, retval
));
1589 * Create a special file.
1591 static int mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
);
1594 mknod(struct proc
*p
, register struct mknod_args
*uap
, __unused register_t
*retval
)
1596 struct vnode_attr va
;
1597 struct vfs_context context
;
1600 struct nameidata nd
;
1603 context
.vc_proc
= p
;
1604 context
.vc_ucred
= kauth_cred_get();
1607 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1608 VATTR_SET(&va
, va_rdev
, uap
->dev
);
1610 /* If it's a mknod() of a FIFO, call mkfifo1() instead */
1611 if ((uap
->mode
& S_IFMT
) == S_IFIFO
)
1612 return(mkfifo1(&context
, uap
->path
, &va
));
1614 AUDIT_ARG(mode
, uap
->mode
);
1615 AUDIT_ARG(dev
, uap
->dev
);
1617 if ((error
= suser(context
.vc_ucred
, &p
->p_acflag
)))
1619 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1620 UIO_USERSPACE
, uap
->path
, &context
);
1632 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
1635 switch (uap
->mode
& S_IFMT
) {
1636 case S_IFMT
: /* used by badsect to flag bad sectors */
1637 VATTR_SET(&va
, va_type
, VBAD
);
1640 VATTR_SET(&va
, va_type
, VCHR
);
1643 VATTR_SET(&va
, va_type
, VBLK
);
1653 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, CREATE
, &context
);
1655 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, &va
, 0, &context
);
1661 int update_flags
= 0;
1663 // Make sure the name & parent pointers are hooked up
1664 if (vp
->v_name
== NULL
)
1665 update_flags
|= VNODE_UPDATE_NAME
;
1666 if (vp
->v_parent
== NULLVP
)
1667 update_flags
|= VNODE_UPDATE_PARENT
;
1670 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
1672 add_fsevent(FSE_CREATE_FILE
, &context
,
1679 * nameidone has to happen before we vnode_put(dvp)
1680 * since it may need to release the fs_nodelock on the dvp
1692 * Create a named pipe.
1695 mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
)
1699 struct nameidata nd
;
1701 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1702 UIO_USERSPACE
, upath
, ctx
);
1709 /* check that this is a new file and authorize addition */
1714 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
1717 VATTR_SET(vap
, va_type
, VFIFO
);
1719 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
);
1722 * nameidone has to happen before we vnode_put(dvp)
1723 * since it may need to release the fs_nodelock on the dvp
1735 mkfifo_extended(struct proc
*p
, struct mkfifo_extended_args
*uap
, __unused register_t
*retval
)
1738 kauth_filesec_t xsecdst
;
1739 struct vfs_context context
;
1740 struct vnode_attr va
;
1742 xsecdst
= KAUTH_FILESEC_NONE
;
1743 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
1744 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
1748 context
.vc_proc
= p
;
1749 context
.vc_ucred
= kauth_cred_get();
1752 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1753 if (uap
->uid
!= KAUTH_UID_NONE
)
1754 VATTR_SET(&va
, va_uid
, uap
->uid
);
1755 if (uap
->gid
!= KAUTH_GID_NONE
)
1756 VATTR_SET(&va
, va_gid
, uap
->gid
);
1757 if (xsecdst
!= KAUTH_FILESEC_NONE
)
1758 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
1760 ciferror
= mkfifo1(&context
, uap
->path
, &va
);
1762 if (xsecdst
!= KAUTH_FILESEC_NONE
)
1763 kauth_filesec_free(xsecdst
);
1769 mkfifo(struct proc
*p
, register struct mkfifo_args
*uap
, __unused register_t
*retval
)
1771 struct vfs_context context
;
1772 struct vnode_attr va
;
1774 context
.vc_proc
= p
;
1775 context
.vc_ucred
= kauth_cred_get();
1778 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1780 return(mkfifo1(&context
, uap
->path
, &va
));
1784 * Make a hard file link.
1788 link(struct proc
*p
, register struct link_args
*uap
, __unused register_t
*retval
)
1790 vnode_t vp
, dvp
, lvp
;
1791 struct nameidata nd
;
1792 struct vfs_context context
;
1795 int need_event
, has_listeners
;
1797 context
.vc_proc
= p
;
1798 context
.vc_ucred
= kauth_cred_get();
1799 vp
= dvp
= lvp
= NULLVP
;
1801 /* look up the object we are linking to */
1802 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1803 UIO_USERSPACE
, uap
->path
, &context
);
1811 /* we're not allowed to link to directories */
1812 if (vp
->v_type
== VDIR
) {
1813 error
= EPERM
; /* POSIX */
1817 /* or to anything that kauth doesn't want us to (eg. immutable items) */
1818 if ((error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_LINKTARGET
, &context
)) != 0)
1821 /* lookup the target node */
1822 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1823 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| AUDITVNPATH2
;
1824 nd
.ni_dirp
= uap
->link
;
1830 /* target node must not exist */
1831 if (lvp
!= NULLVP
) {
1835 /* cannot link across mountpoints */
1836 if (vnode_mount(vp
) != vnode_mount(dvp
)) {
1841 /* authorize creation of the target note */
1842 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
1845 /* and finally make the link */
1846 error
= VNOP_LINK(vp
, dvp
, &nd
.ni_cnd
, &context
);
1850 need_event
= need_fsevent(FSE_CREATE_FILE
, dvp
);
1851 has_listeners
= kauth_authorize_fileop_has_listeners();
1853 if (need_event
|| has_listeners
) {
1854 char *target_path
= NULL
;
1855 char *link_to_path
= NULL
;
1856 int len
, link_name_len
;
1858 /* build the path to the new link file */
1859 target_path
= get_pathbuff();
1861 vn_getpath(dvp
, target_path
, &len
);
1862 target_path
[len
-1] = '/';
1863 strcpy(&target_path
[len
], nd
.ni_cnd
.cn_nameptr
);
1864 len
+= nd
.ni_cnd
.cn_namelen
;
1866 if (has_listeners
) {
1867 /* build the path to file we are linking to */
1868 link_to_path
= get_pathbuff();
1869 link_name_len
= MAXPATHLEN
;
1870 vn_getpath(vp
, link_to_path
, &link_name_len
);
1872 /* call out to allow 3rd party notification of rename.
1873 * Ignore result of kauth_authorize_fileop call.
1875 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_LINK
,
1876 (uintptr_t)link_to_path
, (uintptr_t)target_path
);
1877 if (link_to_path
!= NULL
)
1878 release_pathbuff(link_to_path
);
1881 /* construct fsevent */
1882 if (get_fse_info(vp
, &finfo
, &context
) == 0) {
1883 // build the path to the destination of the link
1884 add_fsevent(FSE_CREATE_FILE
, &context
,
1885 FSE_ARG_STRING
, len
, target_path
,
1886 FSE_ARG_FINFO
, &finfo
,
1890 release_pathbuff(target_path
);
1894 * nameidone has to happen before we vnode_put(dvp)
1895 * since it may need to release the fs_nodelock on the dvp
1908 * Make a symbolic link.
1910 * We could add support for ACLs here too...
1914 symlink(struct proc
*p
, register struct symlink_args
*uap
, __unused register_t
*retval
)
1916 struct vnode_attr va
;
1919 struct nameidata nd
;
1920 struct vfs_context context
;
1924 context
.vc_proc
= p
;
1925 context
.vc_ucred
= kauth_cred_get();
1927 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1928 error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
);
1931 AUDIT_ARG(text
, path
); /* This is the link string */
1933 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1934 UIO_USERSPACE
, uap
->link
, &context
);
1943 VATTR_SET(&va
, va_type
, VLNK
);
1944 VATTR_SET(&va
, va_mode
, ACCESSPERMS
& ~p
->p_fd
->fd_cmask
);
1947 error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
);
1948 /* get default ownership, etc. */
1950 error
= vnode_authattr_new(dvp
, &va
, 0, &context
);
1952 error
= VNOP_SYMLINK(dvp
, &vp
, &nd
.ni_cnd
, &va
, path
, &context
);
1954 /* do fallback attribute handling */
1956 error
= vnode_setattr_fallback(vp
, &va
, &context
);
1959 int update_flags
= 0;
1962 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
1963 nd
.ni_cnd
.cn_flags
= 0;
1971 #if 0 /* XXX - kauth_todo - is KAUTH_FILEOP_SYMLINK needed? */
1972 /* call out to allow 3rd party notification of rename.
1973 * Ignore result of kauth_authorize_fileop call.
1975 if (kauth_authorize_fileop_has_listeners() &&
1977 char *new_link_path
= NULL
;
1980 /* build the path to the new link file */
1981 new_link_path
= get_pathbuff();
1983 vn_getpath(dvp
, new_link_path
, &len
);
1984 new_link_path
[len
- 1] = '/';
1985 strcpy(&new_link_path
[len
], nd
.ni_cnd
.cn_nameptr
);
1987 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_SYMLINK
,
1988 (uintptr_t)path
, (uintptr_t)new_link_path
);
1989 if (new_link_path
!= NULL
)
1990 release_pathbuff(new_link_path
);
1993 // Make sure the name & parent pointers are hooked up
1994 if (vp
->v_name
== NULL
)
1995 update_flags
|= VNODE_UPDATE_NAME
;
1996 if (vp
->v_parent
== NULLVP
)
1997 update_flags
|= VNODE_UPDATE_PARENT
;
2000 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
2002 add_fsevent(FSE_CREATE_FILE
, &context
,
2011 * nameidone has to happen before we vnode_put(dvp)
2012 * since it may need to release the fs_nodelock on the dvp
2020 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
2026 * Delete a whiteout from the filesystem.
2029 #warning XXX authorization not implmented for whiteouts
2031 undelete(struct proc
*p
, register struct undelete_args
*uap
, __unused register_t
*retval
)
2034 struct nameidata nd
;
2035 struct vfs_context context
;
2038 context
.vc_proc
= p
;
2039 context
.vc_ucred
= kauth_cred_get();
2041 NDINIT(&nd
, DELETE
, LOCKPARENT
|DOWHITEOUT
|AUDITVNPATH1
,
2042 UIO_USERSPACE
, uap
->path
, &context
);
2049 if (vp
== NULLVP
&& (nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
2050 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, DELETE
, &context
);
2055 * nameidone has to happen before we vnode_put(dvp)
2056 * since it may need to release the fs_nodelock on the dvp
2068 * Delete a name from the filesystem.
2072 _unlink(struct proc
*p
, struct unlink_args
*uap
, __unused register_t
*retval
, int nodelbusy
)
2076 struct nameidata nd
;
2077 struct vfs_context context
;
2078 struct componentname
*cnp
;
2081 context
.vc_proc
= p
;
2082 context
.vc_ucred
= kauth_cred_get();
2084 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
2085 UIO_USERSPACE
, uap
->path
, &context
);
2088 /* With Carbon delete semantics, busy files cannot be deleted */
2090 flags
|= VNODE_REMOVE_NODELETEBUSY
;
2098 if (vp
->v_type
== VDIR
) {
2099 error
= EPERM
; /* POSIX */
2102 * The root of a mounted filesystem cannot be deleted.
2104 if (vp
->v_flag
& VROOT
) {
2108 /* authorize the delete operation */
2110 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, &context
);
2117 if (need_fsevent(FSE_DELETE
, dvp
)) {
2118 path
= get_pathbuff();
2120 vn_getpath(vp
, path
, &len
);
2121 get_fse_info(vp
, &finfo
, &context
);
2123 error
= VNOP_REMOVE(dvp
, vp
, &nd
.ni_cnd
, flags
, &context
);
2125 if ( !error
&& path
!= NULL
) {
2126 add_fsevent(FSE_DELETE
, &context
,
2127 FSE_ARG_STRING
, len
, path
,
2128 FSE_ARG_FINFO
, &finfo
,
2132 release_pathbuff(path
);
2135 * nameidone has to happen before we vnode_put(dvp)
2136 * since it may need to release the fs_nodelock on the dvp
2145 * Delete a name from the filesystem using POSIX semantics.
2148 unlink(p
, uap
, retval
)
2150 struct unlink_args
*uap
;
2153 return _unlink(p
, uap
, retval
, 0);
2157 * Delete a name from the filesystem using Carbon semantics.
2160 delete(p
, uap
, retval
)
2162 struct delete_args
*uap
;
2165 return _unlink(p
, (struct unlink_args
*)uap
, retval
, 1);
2169 * Reposition read/write file offset.
2172 lseek(p
, uap
, retval
)
2174 register struct lseek_args
*uap
;
2177 struct fileproc
*fp
;
2179 struct vfs_context context
;
2180 off_t offset
= uap
->offset
, file_size
;
2183 if ( (error
= fp_getfvp(p
,uap
->fd
, &fp
, &vp
)) ) {
2184 if (error
== ENOTSUP
)
2188 if (vnode_isfifo(vp
)) {
2192 if ( (error
= vnode_getwithref(vp
)) ) {
2197 switch (uap
->whence
) {
2199 offset
+= fp
->f_fglob
->fg_offset
;
2202 context
.vc_proc
= p
;
2203 context
.vc_ucred
= kauth_cred_get();
2204 if ((error
= vnode_size(vp
, &file_size
, &context
)) != 0)
2206 offset
+= file_size
;
2214 if (uap
->offset
> 0 && offset
< 0) {
2215 /* Incremented/relative move past max size */
2219 * Allow negative offsets on character devices, per
2220 * POSIX 1003.1-2001. Most likely for writing disk
2223 if (offset
< 0 && vp
->v_type
!= VCHR
) {
2224 /* Decremented/relative move before start */
2228 fp
->f_fglob
->fg_offset
= offset
;
2229 *retval
= fp
->f_fglob
->fg_offset
;
2233 (void)vnode_put(vp
);
2240 * Check access permissions.
2243 access1(vnode_t vp
, vnode_t dvp
, int uflags
, vfs_context_t ctx
)
2245 kauth_action_t action
;
2249 * If just the regular access bits, convert them to something
2250 * that vnode_authorize will understand.
2252 if (!(uflags
& _ACCESS_EXTENDED_MASK
)) {
2255 action
|= KAUTH_VNODE_READ_DATA
; /* aka KAUTH_VNODE_LIST_DIRECTORY */
2256 if (uflags
& W_OK
) {
2257 if (vnode_isdir(vp
)) {
2258 action
|= KAUTH_VNODE_ADD_FILE
|
2259 KAUTH_VNODE_ADD_SUBDIRECTORY
;
2260 /* might want delete rights here too */
2262 action
|= KAUTH_VNODE_WRITE_DATA
;
2265 if (uflags
& X_OK
) {
2266 if (vnode_isdir(vp
)) {
2267 action
|= KAUTH_VNODE_SEARCH
;
2269 action
|= KAUTH_VNODE_EXECUTE
;
2273 /* take advantage of definition of uflags */
2274 action
= uflags
>> 8;
2277 /* action == 0 means only check for existence */
2279 error
= vnode_authorize(vp
, dvp
, action
| KAUTH_VNODE_ACCESS
, ctx
);
2289 /* XXX need to support the check-as uid argument */
2291 access_extended(__unused
struct proc
*p
, struct access_extended_args
*uap
, __unused register_t
*retval
)
2293 struct accessx_descriptor
*input
;
2295 int error
, limit
, nent
, i
, j
, wantdelete
;
2296 struct vfs_context context
;
2297 struct nameidata nd
;
2306 context
.vc_ucred
= NULL
;
2308 /* check input size and fetch descriptor array into allocated storage */
2309 if (uap
->size
> ACCESSX_MAX_TABLESIZE
)
2311 if (uap
->size
< sizeof(struct accessx_descriptor
))
2313 MALLOC(input
, struct accessx_descriptor
*, uap
->size
, M_TEMP
, M_WAITOK
);
2314 if (input
== NULL
) {
2318 error
= copyin(uap
->entries
, input
, uap
->size
);
2323 * Access is defined as checking against the process'
2324 * real identity, even if operations are checking the
2325 * effective identity. So we need to tweak the credential
2328 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
2329 context
.vc_proc
= current_proc();
2332 * Find out how many entries we have, so we can allocate the result array.
2334 limit
= uap
->size
/ sizeof(struct accessx_descriptor
);
2337 for (i
= 0; i
< nent
; i
++) {
2339 * Take the offset to the name string for this entry and convert to an
2340 * input array index, which would be one off the end of the array if this
2341 * was the lowest-addressed name string.
2343 j
= input
[i
].ad_name_offset
/ sizeof(struct accessx_descriptor
);
2349 /* implicit reference to previous name, not a real offset */
2351 /* first entry must have a name string */
2361 if (nent
> ACCESSX_MAX_DESCRIPTORS
) {
2365 MALLOC(result
, errno_t
*, nent
* sizeof(errno_t
), M_TEMP
, M_WAITOK
);
2366 if (result
== NULL
) {
2375 for (i
= 0; i
< nent
; i
++) {
2377 * Looking up a new name?
2379 if (input
[i
].ad_name_offset
!= 0) {
2380 /* discard old vnodes */
2390 /* scan forwards to see if we need the parent this time */
2391 wantdelete
= input
[i
].ad_flags
& _DELETE_OK
;
2392 for (j
= i
+ 1; (j
< nent
) && (input
[j
].ad_name_offset
== 0); j
++)
2393 if (input
[j
].ad_flags
& _DELETE_OK
)
2396 niopts
= FOLLOW
| AUDITVNPATH1
;
2397 /* need parent for vnode_authorize for deletion test */
2399 niopts
|= WANTPARENT
;
2402 NDINIT(&nd
, LOOKUP
, niopts
, UIO_SYSSPACE
, CAST_USER_ADDR_T((const char *)input
+ input
[i
].ad_name_offset
), &context
);
2413 * Handle lookup errors.
2423 /* run this access check */
2424 result
[i
] = access1(vp
, dvp
, input
[i
].ad_flags
, &context
);
2427 /* fatal lookup error */
2433 /* copy out results */
2434 error
= copyout(result
, uap
->results
, nent
* sizeof(errno_t
));
2438 FREE(input
, M_TEMP
);
2440 FREE(result
, M_TEMP
);
2445 if (context
.vc_ucred
)
2446 kauth_cred_rele(context
.vc_ucred
);
2451 access(__unused
struct proc
*p
, register struct access_args
*uap
, __unused register_t
*retval
)
2454 struct nameidata nd
;
2456 struct vfs_context context
;
2459 * Access is defined as checking against the process'
2460 * real identity, even if operations are checking the
2461 * effective identity. So we need to tweak the credential
2464 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
2465 context
.vc_proc
= current_proc();
2467 niopts
= FOLLOW
| AUDITVNPATH1
;
2468 /* need parent for vnode_authorize for deletion test */
2469 if (uap
->flags
& _DELETE_OK
)
2470 niopts
|= WANTPARENT
;
2471 NDINIT(&nd
, LOOKUP
, niopts
, UIO_USERSPACE
, uap
->path
, &context
);
2476 error
= access1(nd
.ni_vp
, nd
.ni_dvp
, uap
->flags
, &context
);
2478 vnode_put(nd
.ni_vp
);
2479 if (uap
->flags
& _DELETE_OK
)
2480 vnode_put(nd
.ni_dvp
);
2484 kauth_cred_rele(context
.vc_ucred
);
2490 stat2(vfs_context_t ctx
, struct nameidata
*ndp
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2493 struct user_stat user_sb
;
2496 kauth_filesec_t fsec
;
2497 size_t xsecurity_bufsize
;
2502 fsec
= KAUTH_FILESEC_NONE
;
2503 error
= vn_stat(ndp
->ni_vp
, &sb
, (xsecurity
!= USER_ADDR_NULL
? &fsec
: NULL
), ctx
);
2504 vnode_put(ndp
->ni_vp
);
2509 /* Zap spare fields */
2511 sb
.st_qspare
[0] = 0LL;
2512 sb
.st_qspare
[1] = 0LL;
2513 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
2514 munge_stat(&sb
, &user_sb
);
2515 my_size
= sizeof(user_sb
);
2516 sbp
= (caddr_t
)&user_sb
;
2519 my_size
= sizeof(sb
);
2522 if ((error
= copyout(sbp
, ub
, my_size
)) != 0)
2525 /* caller wants extended security information? */
2526 if (xsecurity
!= USER_ADDR_NULL
) {
2528 /* did we get any? */
2529 if (fsec
== KAUTH_FILESEC_NONE
) {
2530 if (susize(xsecurity_size
, 0) != 0) {
2535 /* find the user buffer size */
2536 xsecurity_bufsize
= fusize(xsecurity_size
);
2538 /* copy out the actual data size */
2539 if (susize(xsecurity_size
, KAUTH_FILESEC_COPYSIZE(fsec
)) != 0) {
2544 /* if the caller supplied enough room, copy out to it */
2545 if (xsecurity_bufsize
>= KAUTH_FILESEC_COPYSIZE(fsec
))
2546 error
= copyout(fsec
, xsecurity
, KAUTH_FILESEC_COPYSIZE(fsec
));
2550 if (fsec
!= KAUTH_FILESEC_NONE
)
2551 kauth_filesec_free(fsec
);
2556 * Get file status; this version follows links.
2559 stat1(struct proc
*p
, user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2561 struct nameidata nd
;
2562 struct vfs_context context
;
2564 context
.vc_proc
= p
;
2565 context
.vc_ucred
= kauth_cred_get();
2567 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2568 UIO_USERSPACE
, path
, &context
);
2569 return(stat2(&context
, &nd
, ub
, xsecurity
, xsecurity_size
));
2573 stat_extended(struct proc
*p
, struct stat_extended_args
*uap
, __unused register_t
*retval
)
2575 return (stat1(p
, uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
));
2579 stat(struct proc
*p
, struct stat_args
*uap
, __unused register_t
*retval
)
2581 return(stat1(p
, uap
->path
, uap
->ub
, 0, 0));
2585 * Get file status; this version does not follow links.
2588 lstat1(struct proc
*p
, user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2590 struct nameidata nd
;
2591 struct vfs_context context
;
2593 context
.vc_proc
= p
;
2594 context
.vc_ucred
= kauth_cred_get();
2596 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
2597 UIO_USERSPACE
, path
, &context
);
2599 return(stat2(&context
, &nd
, ub
, xsecurity
, xsecurity_size
));
2603 lstat_extended(struct proc
*p
, struct lstat_extended_args
*uap
, __unused register_t
*retval
)
2605 return (lstat1(p
, uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
));
2609 lstat(struct proc
*p
, struct lstat_args
*uap
, __unused register_t
*retval
)
2611 return(lstat1(p
, uap
->path
, uap
->ub
, 0, 0));
2615 * Get configurable pathname variables.
2619 pathconf(p
, uap
, retval
)
2621 register struct pathconf_args
*uap
;
2625 struct nameidata nd
;
2626 struct vfs_context context
;
2628 context
.vc_proc
= p
;
2629 context
.vc_ucred
= kauth_cred_get();
2631 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2632 UIO_USERSPACE
, uap
->path
, &context
);
2637 error
= vn_pathconf(nd
.ni_vp
, uap
->name
, retval
, &context
);
2639 vnode_put(nd
.ni_vp
);
2645 * Return target name of a symbolic link.
2649 readlink(p
, uap
, retval
)
2651 register struct readlink_args
*uap
;
2654 register struct vnode
*vp
;
2656 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
2658 struct nameidata nd
;
2659 struct vfs_context context
;
2660 char uio_buf
[ UIO_SIZEOF(1) ];
2662 context
.vc_proc
= p
;
2663 context
.vc_ucred
= kauth_cred_get();
2665 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
2666 UIO_USERSPACE
, uap
->path
, &context
);
2674 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
2675 &uio_buf
[0], sizeof(uio_buf
));
2676 uio_addiov(auio
, uap
->buf
, uap
->count
);
2677 if (vp
->v_type
!= VLNK
)
2680 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, &context
);
2682 error
= VNOP_READLINK(vp
, auio
, &context
);
2685 // LP64todo - fix this
2686 *retval
= uap
->count
- (int)uio_resid(auio
);
2691 * Change file flags.
2694 chflags1(vnode_t vp
, int flags
, vfs_context_t ctx
)
2696 struct vnode_attr va
;
2697 kauth_action_t action
;
2701 VATTR_SET(&va
, va_flags
, flags
);
2703 /* request authorisation, disregard immutability */
2704 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
2707 * Request that the auth layer disregard those file flags it's allowed to when
2708 * authorizing this operation; we need to do this in order to be able to
2709 * clear immutable flags.
2711 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
| KAUTH_VNODE_NOIMMUTABLE
, ctx
)) != 0))
2713 error
= vnode_setattr(vp
, &va
, ctx
);
2721 * Change flags of a file given a path name.
2725 chflags(struct proc
*p
, register struct chflags_args
*uap
, __unused register_t
*retval
)
2727 register struct vnode
*vp
;
2728 struct vfs_context context
;
2730 struct nameidata nd
;
2732 context
.vc_proc
= p
;
2733 context
.vc_ucred
= kauth_cred_get();
2735 AUDIT_ARG(fflags
, uap
->flags
);
2736 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2737 UIO_USERSPACE
, uap
->path
, &context
);
2744 error
= chflags1(vp
, uap
->flags
, &context
);
2750 * Change flags of a file given a file descriptor.
2754 fchflags(struct proc
*p
, register struct fchflags_args
*uap
, __unused register_t
*retval
)
2756 struct vfs_context context
;
2760 AUDIT_ARG(fd
, uap
->fd
);
2761 AUDIT_ARG(fflags
, uap
->flags
);
2762 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
2765 if ((error
= vnode_getwithref(vp
))) {
2770 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2772 context
.vc_proc
= p
;
2773 context
.vc_ucred
= kauth_cred_get();
2775 error
= chflags1(vp
, uap
->flags
, &context
);
2782 * Change security information on a filesystem object.
2785 chmod2(vfs_context_t ctx
, struct vnode
*vp
, struct vnode_attr
*vap
)
2787 kauth_action_t action
;
2790 AUDIT_ARG(mode
, (mode_t
)vap
->va_mode
);
2791 #warning XXX audit new args
2793 /* make sure that the caller is allowed to set this security information */
2794 if (((error
= vnode_authattr(vp
, vap
, &action
, ctx
)) != 0) ||
2795 ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
2796 if (error
== EACCES
)
2801 error
= vnode_setattr(vp
, vap
, ctx
);
2808 * Change mode of a file given path name.
2811 chmod1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
2813 struct nameidata nd
;
2816 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2817 UIO_USERSPACE
, path
, ctx
);
2818 if ((error
= namei(&nd
)))
2820 error
= chmod2(ctx
, nd
.ni_vp
, vap
);
2821 vnode_put(nd
.ni_vp
);
2827 chmod_extended(struct proc
*p
, struct chmod_extended_args
*uap
, __unused register_t
*retval
)
2829 struct vfs_context context
;
2831 struct vnode_attr va
;
2832 kauth_filesec_t xsecdst
;
2835 if (uap
->mode
!= -1)
2836 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2837 if (uap
->uid
!= KAUTH_UID_NONE
)
2838 VATTR_SET(&va
, va_uid
, uap
->uid
);
2839 if (uap
->gid
!= KAUTH_GID_NONE
)
2840 VATTR_SET(&va
, va_gid
, uap
->gid
);
2843 switch(uap
->xsecurity
) {
2844 /* explicit remove request */
2845 case CAST_USER_ADDR_T((void *)1): /* _FILESEC_REMOVE_ACL */
2846 VATTR_SET(&va
, va_acl
, NULL
);
2849 case USER_ADDR_NULL
:
2852 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
2854 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2855 KAUTH_DEBUG("CHMOD - setting ACL with %d entries", va
.va_acl
->acl_entrycount
);
2857 context
.vc_proc
= p
;
2858 context
.vc_ucred
= kauth_cred_get();
2860 error
= chmod1(&context
, uap
->path
, &va
);
2862 if (xsecdst
!= NULL
)
2863 kauth_filesec_free(xsecdst
);
2868 chmod(struct proc
*p
, register struct chmod_args
*uap
, __unused register_t
*retval
)
2870 struct vfs_context context
;
2871 struct vnode_attr va
;
2874 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2876 context
.vc_proc
= p
;
2877 context
.vc_ucred
= kauth_cred_get();
2879 return(chmod1(&context
, uap
->path
, &va
));
2883 * Change mode of a file given a file descriptor.
2886 fchmod1(struct proc
*p
, int fd
, struct vnode_attr
*vap
)
2890 struct vfs_context context
;
2892 context
.vc_proc
= p
;
2893 context
.vc_ucred
= kauth_cred_get();
2897 if ((error
= file_vnode(fd
, &vp
)) != 0)
2899 if ((error
= vnode_getwithref(vp
)) != 0) {
2903 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2905 error
= chmod2(&context
, vp
, vap
);
2906 (void)vnode_put(vp
);
2913 fchmod_extended(struct proc
*p
, struct fchmod_extended_args
*uap
, __unused register_t
*retval
)
2916 struct vnode_attr va
;
2917 kauth_filesec_t xsecdst
;
2920 if (uap
->mode
!= -1)
2921 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2922 if (uap
->uid
!= KAUTH_UID_NONE
)
2923 VATTR_SET(&va
, va_uid
, uap
->uid
);
2924 if (uap
->gid
!= KAUTH_GID_NONE
)
2925 VATTR_SET(&va
, va_gid
, uap
->gid
);
2928 switch(uap
->xsecurity
) {
2929 case USER_ADDR_NULL
:
2930 VATTR_SET(&va
, va_acl
, NULL
);
2932 case CAST_USER_ADDR_T(-1):
2935 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
2937 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2940 error
= fchmod1(p
, uap
->fd
, &va
);
2943 switch(uap
->xsecurity
) {
2944 case USER_ADDR_NULL
:
2945 case CAST_USER_ADDR_T(-1):
2948 if (xsecdst
!= NULL
)
2949 kauth_filesec_free(xsecdst
);
2955 fchmod(struct proc
*p
, register struct fchmod_args
*uap
, __unused register_t
*retval
)
2957 struct vnode_attr va
;
2960 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2962 return(fchmod1(p
, uap
->fd
, &va
));
2967 * Set ownership given a path name.
2971 chown1(vfs_context_t ctx
, register struct chown_args
*uap
, __unused register_t
*retval
, int follow
)
2973 register struct vnode
*vp
;
2974 struct vnode_attr va
;
2976 struct nameidata nd
;
2977 kauth_action_t action
;
2979 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
2981 NDINIT(&nd
, LOOKUP
, (follow
? FOLLOW
: 0) | AUDITVNPATH1
,
2982 UIO_USERSPACE
, uap
->path
, ctx
);
2991 * XXX A TEMPORARY HACK FOR NOW: Try to track console_user
2992 * by looking for chown() calls on /dev/console from a console process.
2994 if ((vp
) && (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
) && (vp
->v_specinfo
) &&
2995 (major(vp
->v_specinfo
->si_rdev
) == CONSMAJOR
) &&
2996 (minor(vp
->v_specinfo
->si_rdev
) == 0)) {
2997 console_user
= uap
->uid
;
3000 if (uap
->uid
!= VNOVAL
)
3001 VATTR_SET(&va
, va_uid
, uap
->uid
);
3002 if (uap
->gid
!= VNOVAL
)
3003 VATTR_SET(&va
, va_gid
, uap
->gid
);
3005 /* preflight and authorize attribute changes */
3006 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
3008 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
3010 error
= vnode_setattr(vp
, &va
, ctx
);
3014 * EACCES is only allowed from namei(); permissions failure should
3015 * return EPERM, so we need to translate the error code.
3017 if (error
== EACCES
)
3025 chown(struct proc
*p
, register struct chown_args
*uap
, register_t
*retval
)
3027 struct vfs_context context
;
3029 context
.vc_proc
= p
;
3030 context
.vc_ucred
= kauth_cred_get();
3032 return chown1(&context
, uap
, retval
, 1);
3036 lchown(struct proc
*p
, register struct lchown_args
*uap
, register_t
*retval
)
3038 struct vfs_context context
;
3040 context
.vc_proc
= p
;
3041 context
.vc_ucred
= kauth_cred_get();
3043 /* Argument list identical, but machine generated; cast for chown1() */
3044 return chown1(&context
, (struct chown_args
*)uap
, retval
, 0);
3048 * Set ownership given a file descriptor.
3052 fchown(struct proc
*p
, register struct fchown_args
*uap
, __unused register_t
*retval
)
3054 struct vnode_attr va
;
3055 struct vfs_context context
;
3058 kauth_action_t action
;
3060 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
3061 AUDIT_ARG(fd
, uap
->fd
);
3063 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
3066 if ( (error
= vnode_getwithref(vp
)) ) {
3070 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3073 if (uap
->uid
!= VNOVAL
)
3074 VATTR_SET(&va
, va_uid
, uap
->uid
);
3075 if (uap
->gid
!= VNOVAL
)
3076 VATTR_SET(&va
, va_gid
, uap
->gid
);
3078 context
.vc_proc
= p
;
3079 context
.vc_ucred
= kauth_cred_get();
3081 /* preflight and authorize attribute changes */
3082 if ((error
= vnode_authattr(vp
, &va
, &action
, &context
)) != 0)
3084 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0)) {
3085 if (error
== EACCES
)
3089 error
= vnode_setattr(vp
, &va
, &context
);
3092 (void)vnode_put(vp
);
3098 getutimes(usrtvp
, tsp
)
3100 struct timespec
*tsp
;
3102 struct user_timeval tv
[2];
3105 if (usrtvp
== USER_ADDR_NULL
) {
3106 struct timeval old_tv
;
3107 /* XXX Y2038 bug because of microtime argument */
3109 TIMEVAL_TO_TIMESPEC(&old_tv
, &tsp
[0]);
3112 if (IS_64BIT_PROCESS(current_proc())) {
3113 error
= copyin(usrtvp
, (void *)tv
, sizeof(tv
));
3115 struct timeval old_tv
[2];
3116 error
= copyin(usrtvp
, (void *)old_tv
, sizeof(old_tv
));
3117 tv
[0].tv_sec
= old_tv
[0].tv_sec
;
3118 tv
[0].tv_usec
= old_tv
[0].tv_usec
;
3119 tv
[1].tv_sec
= old_tv
[1].tv_sec
;
3120 tv
[1].tv_usec
= old_tv
[1].tv_usec
;
3124 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
3125 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
3131 setutimes(vfs_context_t ctx
, struct vnode
*vp
, const struct timespec
*ts
,
3135 struct vnode_attr va
;
3136 kauth_action_t action
;
3138 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3141 VATTR_SET(&va
, va_access_time
, ts
[0]);
3142 VATTR_SET(&va
, va_modify_time
, ts
[1]);
3144 va
.va_vaflags
|= VA_UTIMES_NULL
;
3146 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
3148 /* since we may not need to auth anything, check here */
3149 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
3151 error
= vnode_setattr(vp
, &va
, ctx
);
3158 * Set the access and modification times of a file.
3162 utimes(struct proc
*p
, register struct utimes_args
*uap
, __unused register_t
*retval
)
3164 struct timespec ts
[2];
3167 struct nameidata nd
;
3168 struct vfs_context context
;
3170 context
.vc_proc
= p
;
3171 context
.vc_ucred
= kauth_cred_get();
3173 /* AUDIT: Needed to change the order of operations to do the
3174 * name lookup first because auditing wants the path.
3176 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3177 UIO_USERSPACE
, uap
->path
, &context
);
3184 * Fetch the user-supplied time. If usrtvp is USER_ADDR_NULL, we fetch
3185 * the current time instead.
3188 if ((error
= getutimes(usrtvp
, ts
)) != 0)
3191 error
= setutimes(&context
, nd
.ni_vp
, ts
, usrtvp
== USER_ADDR_NULL
);
3194 vnode_put(nd
.ni_vp
);
3199 * Set the access and modification times of a file.
3203 futimes(struct proc
*p
, register struct futimes_args
*uap
, __unused register_t
*retval
)
3205 struct timespec ts
[2];
3209 struct vfs_context context
;
3211 context
.vc_proc
= p
;
3212 context
.vc_ucred
= kauth_cred_get();
3214 AUDIT_ARG(fd
, uap
->fd
);
3216 if ((error
= getutimes(usrtvp
, ts
)) != 0)
3218 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
3220 if((error
= vnode_getwithref(vp
))) {
3225 error
= setutimes(&context
, vp
, ts
, usrtvp
== 0);
3232 * Truncate a file given its path name.
3236 truncate(struct proc
*p
, register struct truncate_args
*uap
, __unused register_t
*retval
)
3238 register struct vnode
*vp
;
3239 struct vnode_attr va
;
3240 struct vfs_context context
;
3242 struct nameidata nd
;
3243 kauth_action_t action
;
3245 context
.vc_proc
= p
;
3246 context
.vc_ucred
= kauth_cred_get();
3248 if (uap
->length
< 0)
3250 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3251 UIO_USERSPACE
, uap
->path
, &context
);
3252 if ((error
= namei(&nd
)))
3259 VATTR_SET(&va
, va_data_size
, uap
->length
);
3260 if ((error
= vnode_authattr(vp
, &va
, &action
, &context
)) != 0)
3262 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0))
3264 error
= vnode_setattr(vp
, &va
, &context
);
3271 * Truncate a file given a file descriptor.
3275 ftruncate(p
, uap
, retval
)
3277 register struct ftruncate_args
*uap
;
3280 struct vfs_context context
;
3281 struct vnode_attr va
;
3283 struct fileproc
*fp
;
3287 context
.vc_proc
= current_proc();
3288 context
.vc_ucred
= kauth_cred_get();
3290 AUDIT_ARG(fd
, uap
->fd
);
3291 if (uap
->length
< 0)
3294 if ( (error
= fp_lookup(p
,fd
,&fp
,0)) ) {
3298 if (fp
->f_fglob
->fg_type
== DTYPE_PSXSHM
) {
3299 error
= pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
);
3302 if (fp
->f_fglob
->fg_type
!= DTYPE_VNODE
) {
3307 vp
= (struct vnode
*)fp
->f_fglob
->fg_data
;
3309 if ((fp
->f_fglob
->fg_flag
& FWRITE
) == 0) {
3310 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
3315 if ((error
= vnode_getwithref(vp
)) != 0) {
3319 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3322 VATTR_SET(&va
, va_data_size
, uap
->length
);
3323 error
= vnode_setattr(vp
, &va
, &context
);
3324 (void)vnode_put(vp
);
3332 * Sync an open file.
3336 fsync(struct proc
*p
, struct fsync_args
*uap
, __unused register_t
*retval
)
3339 struct fileproc
*fp
;
3340 struct vfs_context context
;
3343 if ( (error
= fp_getfvp(p
, uap
->fd
, &fp
, &vp
)) )
3345 if ( (error
= vnode_getwithref(vp
)) ) {
3349 context
.vc_proc
= p
;
3350 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
3352 error
= VNOP_FSYNC(vp
, MNT_WAIT
, &context
);
3354 (void)vnode_put(vp
);
3360 * Duplicate files. Source must be a file, target must be a file or
3363 * XXX Copyfile authorisation checking is woefully inadequate, and will not
3364 * perform inheritance correctly.
3368 copyfile(struct proc
*p
, register struct copyfile_args
*uap
, __unused register_t
*retval
)
3370 vnode_t tvp
, fvp
, tdvp
, sdvp
;
3371 struct nameidata fromnd
, tond
;
3373 struct vfs_context context
;
3375 context
.vc_proc
= p
;
3376 context
.vc_ucred
= kauth_cred_get();
3378 /* Check that the flags are valid. */
3380 if (uap
->flags
& ~CPF_MASK
) {
3384 NDINIT(&fromnd
, LOOKUP
, SAVESTART
| AUDITVNPATH1
,
3385 UIO_USERSPACE
, uap
->from
, &context
);
3386 if ((error
= namei(&fromnd
)))
3390 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
| AUDITVNPATH2
,
3391 UIO_USERSPACE
, uap
->to
, &context
);
3392 if ((error
= namei(&tond
))) {
3399 if (!(uap
->flags
& CPF_OVERWRITE
)) {
3404 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
3409 if ((error
= vnode_authorize(tdvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
3415 * If source is the same as the destination (that is the
3416 * same inode number) then there is nothing to do.
3417 * (fixed to have POSIX semantics - CSM 3/2/98)
3422 error
= VNOP_COPYFILE(fvp
,tdvp
,tvp
,&tond
.ni_cnd
,uap
->mode
,uap
->flags
,&context
);
3424 sdvp
= tond
.ni_startdir
;
3426 * nameidone has to happen before we vnode_put(tdvp)
3427 * since it may need to release the fs_nodelock on the tdvp
3438 if (fromnd
.ni_startdir
)
3439 vnode_put(fromnd
.ni_startdir
);
3449 * Rename files. Source and destination must either both be directories,
3450 * or both not be directories. If target is a directory, it must be empty.
3454 rename(proc_t p
, register struct rename_args
*uap
, __unused register_t
*retval
)
3458 struct nameidata fromnd
, tond
;
3459 struct vfs_context context
;
3462 char *oname
, *from_name
, *to_name
;
3463 int from_len
, to_len
;
3464 int holding_mntlock
;
3465 mount_t locked_mp
= NULL
;
3467 fse_info from_finfo
, to_finfo
;
3469 context
.vc_proc
= p
;
3470 context
.vc_ucred
= kauth_cred_get();
3471 holding_mntlock
= 0;
3477 NDINIT(&fromnd
, DELETE
, WANTPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->from
, &context
);
3479 if ( (error
= namei(&fromnd
)) )
3481 fdvp
= fromnd
.ni_dvp
;
3484 NDINIT(&tond
, RENAME
, WANTPARENT
| AUDITVNPATH2
, UIO_USERSPACE
, uap
->to
, &context
);
3485 if (fvp
->v_type
== VDIR
)
3486 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
3488 if ( (error
= namei(&tond
)) ) {
3490 * Translate error code for rename("dir1", "dir2/.").
3492 if (error
== EISDIR
&& fvp
->v_type
== VDIR
)
3500 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
3503 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
3516 * If tvp is a directory and not the same as fdvp, or tdvp is not the same as fdvp,
3517 * the node is moving between directories and we need rights to remove from the
3518 * old and add to the new.
3520 * If tvp already exists and is not a directory, we need to be allowed to delete it.
3522 * Note that we do not inherit when renaming. XXX this needs to be revisited to
3523 * implement the deferred-inherit bit.
3529 if ((tvp
!= NULL
) && vnode_isdir(tvp
)) {
3532 } else if (tdvp
!= fdvp
) {
3536 * must have delete rights to remove the old name even in the simple case of
3539 if ((error
= vnode_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
, &context
)) != 0)
3542 /* moving into tdvp or tvp, must have rights to add */
3543 if ((error
= vnode_authorize(((tvp
!= NULL
) && vnode_isdir(tvp
)) ? tvp
: tdvp
,
3545 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
3549 /* node staying in same directory, must be allowed to add new name */
3550 if ((error
= vnode_authorize(fdvp
, NULL
,
3551 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
3554 /* overwriting tvp */
3555 if ((tvp
!= NULL
) && !vnode_isdir(tvp
) &&
3556 ((error
= vnode_authorize(tvp
, tdvp
, KAUTH_VNODE_DELETE
, &context
)) != 0))
3559 /* XXX more checks? */
3562 /* authorization denied */
3567 * Allow the renaming of mount points.
3568 * - target must not exist
3569 * - target must reside in the same directory as source
3570 * - union mounts cannot be renamed
3571 * - "/" cannot be renamed
3573 if ((fvp
->v_flag
& VROOT
) &&
3574 (fvp
->v_type
== VDIR
) &&
3576 (fvp
->v_mountedhere
== NULL
) &&
3578 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
3579 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
3580 struct vnode
*coveredvp
;
3582 /* switch fvp to the covered vnode */
3583 coveredvp
= fvp
->v_mount
->mnt_vnodecovered
;
3584 if ( (vnode_getwithref(coveredvp
)) ) {
3594 * Check for cross-device rename.
3596 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
3597 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
3602 * Avoid renaming "." and "..".
3604 if (fvp
->v_type
== VDIR
&&
3606 (fromnd
.ni_cnd
.cn_namelen
== 1 && fromnd
.ni_cnd
.cn_nameptr
[0] == '.') ||
3607 ((fromnd
.ni_cnd
.cn_flags
| tond
.ni_cnd
.cn_flags
) & ISDOTDOT
)) ) {
3612 * The following edge case is caught here:
3613 * (to cannot be a descendent of from)
3626 if (tdvp
->v_parent
== fvp
) {
3632 * If source is the same as the destination (that is the
3633 * same inode number) then there is nothing to do...
3634 * EXCEPT if the underlying file system supports case
3635 * insensitivity and is case preserving. In this case
3636 * the file system needs to handle the special case of
3637 * getting the same vnode as target (fvp) and source (tvp).
3639 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
3640 * and _PC_CASE_PRESERVING can have this exception, and they need to
3641 * handle the special case of getting the same vnode as target and
3642 * source. NOTE: Then the target is unlocked going into vnop_rename,
3643 * so not to cause locking problems. There is a single reference on tvp.
3645 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
3646 * that correct behaviour then is just to remove the source (link)
3648 if (fvp
== tvp
&& fdvp
== tdvp
) {
3649 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
3650 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
3651 fromnd
.ni_cnd
.cn_namelen
)) {
3656 if (holding_mntlock
&& fvp
->v_mount
!= locked_mp
) {
3658 * we're holding a reference and lock
3659 * on locked_mp, but it no longer matches
3660 * what we want to do... so drop our hold
3662 mount_unlock_renames(locked_mp
);
3663 mount_drop(locked_mp
, 0);
3664 holding_mntlock
= 0;
3666 if (tdvp
!= fdvp
&& fvp
->v_type
== VDIR
) {
3668 * serialize renames that re-shape
3669 * the tree... if holding_mntlock is
3670 * set, then we're ready to go...
3672 * first need to drop the iocounts
3673 * we picked up, second take the
3674 * lock to serialize the access,
3675 * then finally start the lookup
3676 * process over with the lock held
3678 if (!holding_mntlock
) {
3680 * need to grab a reference on
3681 * the mount point before we
3682 * drop all the iocounts... once
3683 * the iocounts are gone, the mount
3686 locked_mp
= fvp
->v_mount
;
3687 mount_ref(locked_mp
, 0);
3690 * nameidone has to happen before we vnode_put(tvp)
3691 * since it may need to release the fs_nodelock on the tvp
3700 * nameidone has to happen before we vnode_put(fdvp)
3701 * since it may need to release the fs_nodelock on the fvp
3708 mount_lock_renames(locked_mp
);
3709 holding_mntlock
= 1;
3715 * when we dropped the iocounts to take
3716 * the lock, we allowed the identity of
3717 * the various vnodes to change... if they did,
3718 * we may no longer be dealing with a rename
3719 * that reshapes the tree... once we're holding
3720 * the iocounts, the vnodes can't change type
3721 * so we're free to drop the lock at this point
3724 if (holding_mntlock
) {
3725 mount_unlock_renames(locked_mp
);
3726 mount_drop(locked_mp
, 0);
3727 holding_mntlock
= 0;
3730 // save these off so we can later verify that fvp is the same
3731 oname
= fvp
->v_name
;
3732 oparent
= fvp
->v_parent
;
3734 if (need_fsevent(FSE_RENAME
, fvp
)) {
3735 get_fse_info(fvp
, &from_finfo
, &context
);
3738 get_fse_info(tvp
, &to_finfo
, &context
);
3740 from_name
= get_pathbuff();
3741 from_len
= MAXPATHLEN
;
3742 vn_getpath(fvp
, from_name
, &from_len
);
3744 to_name
= get_pathbuff();
3745 to_len
= MAXPATHLEN
;
3747 if (tvp
&& tvp
->v_type
!= VDIR
) {
3748 vn_getpath(tvp
, to_name
, &to_len
);
3750 vn_getpath(tdvp
, to_name
, &to_len
);
3751 // if the path is not just "/", then append a "/"
3753 to_name
[to_len
-1] = '/';
3757 strcpy(&to_name
[to_len
], tond
.ni_cnd
.cn_nameptr
);
3758 to_len
+= tond
.ni_cnd
.cn_namelen
+ 1;
3759 to_name
[to_len
] = '\0';
3765 error
= VNOP_RENAME(fdvp
, fvp
, &fromnd
.ni_cnd
,
3766 tdvp
, tvp
, &tond
.ni_cnd
,
3769 if (holding_mntlock
) {
3771 * we can drop our serialization
3774 mount_unlock_renames(locked_mp
);
3775 mount_drop(locked_mp
, 0);
3776 holding_mntlock
= 0;
3779 if (to_name
!= NULL
)
3780 release_pathbuff(to_name
);
3781 if (from_name
!= NULL
)
3782 release_pathbuff(from_name
);
3783 from_name
= to_name
= NULL
;
3788 /* call out to allow 3rd party notification of rename.
3789 * Ignore result of kauth_authorize_fileop call.
3791 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_RENAME
,
3792 (uintptr_t)from_name
, (uintptr_t)to_name
);
3794 if (from_name
!= NULL
&& to_name
!= NULL
) {
3796 add_fsevent(FSE_RENAME
, &context
,
3797 FSE_ARG_STRING
, from_len
, from_name
,
3798 FSE_ARG_FINFO
, &from_finfo
,
3799 FSE_ARG_STRING
, to_len
, to_name
,
3800 FSE_ARG_FINFO
, &to_finfo
,
3803 add_fsevent(FSE_RENAME
, &context
,
3804 FSE_ARG_STRING
, from_len
, from_name
,
3805 FSE_ARG_FINFO
, &from_finfo
,
3806 FSE_ARG_STRING
, to_len
, to_name
,
3810 if (to_name
!= NULL
)
3811 release_pathbuff(to_name
);
3812 if (from_name
!= NULL
)
3813 release_pathbuff(from_name
);
3814 from_name
= to_name
= NULL
;
3817 * update filesystem's mount point data
3820 char *cp
, *pathend
, *mpname
;
3826 mp
= fvp
->v_mountedhere
;
3828 if (vfs_busy(mp
, LK_NOWAIT
)) {
3832 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
3834 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
3836 /* find current mount point prefix */
3837 pathend
= &mp
->mnt_vfsstat
.f_mntonname
[0];
3838 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
3842 /* find last component of target name */
3843 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
3847 /* append name to prefix */
3848 maxlen
= MAXPATHLEN
- (pathend
- mp
->mnt_vfsstat
.f_mntonname
);
3849 bzero(pathend
, maxlen
);
3850 strncpy(pathend
, mpname
, maxlen
- 1);
3852 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
3857 * fix up name & parent pointers. note that we first
3858 * check that fvp has the same name/parent pointers it
3859 * had before the rename call... this is a 'weak' check
3862 if (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
) {
3865 update_flags
= VNODE_UPDATE_NAME
;
3868 update_flags
|= VNODE_UPDATE_PARENT
;
3870 vnode_update_identity(fvp
, tdvp
, tond
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_namelen
, tond
.ni_cnd
.cn_hash
, update_flags
);
3873 if (holding_mntlock
) {
3874 mount_unlock_renames(locked_mp
);
3875 mount_drop(locked_mp
, 0);
3879 * nameidone has to happen before we vnode_put(tdvp)
3880 * since it may need to release the fs_nodelock on the tdvp
3890 * nameidone has to happen before we vnode_put(fdvp)
3891 * since it may need to release the fs_nodelock on the fdvp
3903 * Make a directory file.
3907 mkdir1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
3911 int update_flags
= 0;
3912 struct nameidata nd
;
3914 AUDIT_ARG(mode
, vap
->va_mode
);
3915 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
3916 UIO_USERSPACE
, path
, ctx
);
3917 nd
.ni_cnd
.cn_flags
|= WILLBEDIR
;
3929 /* authorize addition of a directory to the parent */
3930 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
)) != 0)
3933 VATTR_SET(vap
, va_type
, VDIR
);
3935 /* make the directory */
3936 if ((error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
)) != 0)
3939 // Make sure the name & parent pointers are hooked up
3940 if (vp
->v_name
== NULL
)
3941 update_flags
|= VNODE_UPDATE_NAME
;
3942 if (vp
->v_parent
== NULLVP
)
3943 update_flags
|= VNODE_UPDATE_PARENT
;
3946 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
3948 add_fsevent(FSE_CREATE_DIR
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
3952 * nameidone has to happen before we vnode_put(dvp)
3953 * since it may need to release the fs_nodelock on the dvp
3966 mkdir_extended(struct proc
*p
, register struct mkdir_extended_args
*uap
, __unused register_t
*retval
)
3968 struct vfs_context context
;
3970 kauth_filesec_t xsecdst
;
3971 struct vnode_attr va
;
3974 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
3975 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
3978 context
.vc_proc
= p
;
3979 context
.vc_ucred
= kauth_cred_get();
3982 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
3983 if (xsecdst
!= NULL
)
3984 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
3986 ciferror
= mkdir1(&context
, uap
->path
, &va
);
3987 if (xsecdst
!= NULL
)
3988 kauth_filesec_free(xsecdst
);
3993 mkdir(struct proc
*p
, register struct mkdir_args
*uap
, __unused register_t
*retval
)
3995 struct vfs_context context
;
3996 struct vnode_attr va
;
3998 context
.vc_proc
= p
;
3999 context
.vc_ucred
= kauth_cred_get();
4002 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
4004 return(mkdir1(&context
, uap
->path
, &va
));
4008 * Remove a directory file.
4012 rmdir(struct proc
*p
, struct rmdir_args
*uap
, __unused register_t
*retval
)
4016 struct nameidata nd
;
4017 struct vfs_context context
;
4019 context
.vc_proc
= p
;
4020 context
.vc_ucred
= kauth_cred_get();
4022 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
4023 UIO_USERSPACE
, uap
->path
, &context
);
4030 if (vp
->v_type
!= VDIR
) {
4032 * rmdir only deals with directories
4035 } else if (dvp
== vp
) {
4037 * No rmdir "." please.
4040 } else if (vp
->v_flag
& VROOT
) {
4042 * The root of a mounted filesystem cannot be deleted.
4046 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, &context
);
4053 if (need_fsevent(FSE_DELETE
, dvp
)) {
4054 path
= get_pathbuff();
4056 vn_getpath(vp
, path
, &len
);
4057 get_fse_info(vp
, &finfo
, &context
);
4059 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, &context
);
4061 if (!error
&& path
!= NULL
) {
4062 add_fsevent(FSE_DELETE
, &context
,
4063 FSE_ARG_STRING
, len
, path
,
4064 FSE_ARG_FINFO
, &finfo
,
4068 release_pathbuff(path
);
4071 * nameidone has to happen before we vnode_put(dvp)
4072 * since it may need to release the fs_nodelock on the dvp
4084 * Read a block of directory entries in a file system independent format.
4087 getdirentries(p
, uap
, retval
)
4089 register struct getdirentries_args
*uap
;
4093 struct vfs_context context
;
4094 struct fileproc
*fp
;
4096 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4100 char uio_buf
[ UIO_SIZEOF(1) ];
4102 AUDIT_ARG(fd
, uap
->fd
);
4103 error
= fp_getfvp(p
, fd
, &fp
, &vp
);
4107 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
4108 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4112 if ( (error
= vnode_getwithref(vp
)) ) {
4116 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4119 if (vp
->v_type
!= VDIR
) {
4120 (void)vnode_put(vp
);
4124 context
.vc_proc
= p
;
4125 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
4127 loff
= fp
->f_fglob
->fg_offset
;
4128 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
4129 &uio_buf
[0], sizeof(uio_buf
));
4130 uio_addiov(auio
, uap
->buf
, uap
->count
);
4132 error
= VNOP_READDIR(vp
, auio
, 0, &eofflag
, (int *)NULL
, &context
);
4133 fp
->f_fglob
->fg_offset
= uio_offset(auio
);
4135 (void)vnode_put(vp
);
4141 if ((uap
->count
== uio_resid(auio
)) &&
4142 (vp
->v_op
== union_vnodeop_p
)) {
4145 lvp
= union_dircache(vp
, p
);
4146 if (lvp
!= NULLVP
) {
4147 struct vnode_attr va
;
4149 * If the directory is opaque,
4150 * then don't show lower entries
4153 VATTR_WANTED(&va
, va_flags
);
4154 error
= vnode_getattr(vp
, &va
, &context
);
4155 if (va
.va_flags
& OPAQUE
) {
4161 if (lvp
!= NULLVP
) {
4162 error
= VNOP_OPEN(lvp
, FREAD
, &context
);
4168 fp
->f_fglob
->fg_data
= (caddr_t
) lvp
;
4169 fp
->f_fglob
->fg_offset
= 0;
4170 error
= VNOP_CLOSE(vp
, FREAD
, &context
);
4182 if (((user_ssize_t
)uap
->count
== uio_resid(auio
)) &&
4183 (vp
->v_flag
& VROOT
) &&
4184 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
4185 struct vnode
*tvp
= vp
;
4186 vp
= vp
->v_mount
->mnt_vnodecovered
;
4187 vnode_getwithref(vp
);
4189 fp
->f_fglob
->fg_data
= (caddr_t
) vp
;
4190 fp
->f_fglob
->fg_offset
= 0;
4196 error
= copyout((caddr_t
)&loff
, uap
->basep
, sizeof(long));
4197 // LP64todo - fix this
4198 *retval
= uap
->count
- uio_resid(auio
);
4205 * Set the mode mask for creation of filesystem nodes.
4207 #warning XXX implement xsecurity
4209 #define UMASK_NOXSECURITY (void *)1 /* leave existing xsecurity alone */
4211 umask1(struct proc
*p
, int newmask
, __unused kauth_filesec_t fsec
, register_t
*retval
)
4213 register struct filedesc
*fdp
;
4215 AUDIT_ARG(mask
, newmask
);
4217 *retval
= fdp
->fd_cmask
;
4218 fdp
->fd_cmask
= newmask
& ALLPERMS
;
4224 umask_extended(struct proc
*p
, struct umask_extended_args
*uap
, register_t
*retval
)
4227 kauth_filesec_t xsecdst
;
4229 xsecdst
= KAUTH_FILESEC_NONE
;
4230 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
4231 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
4234 xsecdst
= KAUTH_FILESEC_NONE
;
4237 ciferror
= umask1(p
, uap
->newmask
, xsecdst
, retval
);
4239 if (xsecdst
!= KAUTH_FILESEC_NONE
)
4240 kauth_filesec_free(xsecdst
);
4245 umask(struct proc
*p
, struct umask_args
*uap
, register_t
*retval
)
4247 return(umask1(p
, uap
->newmask
, UMASK_NOXSECURITY
, retval
));
4251 * Void all references to file by ripping underlying filesystem
4256 revoke(struct proc
*p
, register struct revoke_args
*uap
, __unused register_t
*retval
)
4258 register struct vnode
*vp
;
4259 struct vnode_attr va
;
4260 struct vfs_context context
;
4262 struct nameidata nd
;
4264 context
.vc_proc
= p
;
4265 context
.vc_ucred
= kauth_cred_get();
4267 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4268 UIO_USERSPACE
, uap
->path
, &context
);
4277 VATTR_WANTED(&va
, va_uid
);
4278 if ((error
= vnode_getattr(vp
, &va
, &context
)))
4280 if (kauth_cred_getuid(context
.vc_ucred
) != va
.va_uid
&&
4281 (error
= suser(context
.vc_ucred
, &p
->p_acflag
)))
4283 if (vp
->v_usecount
> 1 || (vp
->v_flag
& VALIASED
))
4284 VNOP_REVOKE(vp
, REVOKEALL
, &context
);
4292 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
4293 * The following system calls are designed to support features
4294 * which are specific to the HFS & HFS Plus volume formats
4297 #ifdef __APPLE_API_OBSOLETE
4299 /************************************************/
4300 /* *** Following calls will be deleted soon *** */
4301 /************************************************/
4304 * Make a complex file. A complex file is one with multiple forks (data streams)
4308 mkcomplex(__unused
struct proc
*p
, __unused
struct mkcomplex_args
*uap
, __unused register_t
*retval
)
4314 * Extended stat call which returns volumeid and vnodeid as well as other info
4318 statv(__unused
struct proc
*p
,
4319 __unused
struct statv_args
*uap
,
4320 __unused register_t
*retval
)
4322 return (ENOTSUP
); /* We'll just return an error for now */
4324 } /* end of statv system call */
4327 * Extended lstat call which returns volumeid and vnodeid as well as other info
4331 lstatv(__unused
struct proc
*p
,
4332 __unused
struct lstatv_args
*uap
,
4333 __unused register_t
*retval
)
4335 return (ENOTSUP
); /* We'll just return an error for now */
4336 } /* end of lstatv system call */
4339 * Extended fstat call which returns volumeid and vnodeid as well as other info
4343 fstatv(__unused
struct proc
*p
,
4344 __unused
struct fstatv_args
*uap
,
4345 __unused register_t
*retval
)
4347 return (ENOTSUP
); /* We'll just return an error for now */
4348 } /* end of fstatv system call */
4351 /************************************************/
4352 /* *** Preceding calls will be deleted soon *** */
4353 /************************************************/
4355 #endif /* __APPLE_API_OBSOLETE */
4358 * Obtain attribute information on objects in a directory while enumerating
4359 * the directory. This call does not yet support union mounted directories.
4361 * 1.union mounted directories.
4366 getdirentriesattr (struct proc
*p
, struct getdirentriesattr_args
*uap
, register_t
*retval
)
4369 struct fileproc
*fp
;
4371 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4372 uint64_t actualcount
;
4377 struct attrlist attributelist
;
4378 struct vfs_context context
;
4380 char uio_buf
[ UIO_SIZEOF(1) ];
4381 kauth_action_t action
;
4385 /* Get the attributes into kernel space */
4386 if ((error
= copyin(uap
->alist
, (caddr_t
) &attributelist
, sizeof (attributelist
))))
4388 actualcount
= fuulong(uap
->count
);
4389 if (actualcount
== -1ULL)
4392 if ( (error
= fp_getfvp(p
, fd
, &fp
, &vp
)) )
4395 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
4396 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4400 if ( (error
= vnode_getwithref(vp
)) )
4403 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4405 if (vp
->v_type
!= VDIR
) {
4406 (void)vnode_put(vp
);
4411 /* set up the uio structure which will contain the users return buffer */
4412 loff
= fp
->f_fglob
->fg_offset
;
4413 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
4414 &uio_buf
[0], sizeof(uio_buf
));
4415 uio_addiov(auio
, uap
->buffer
, uap
->buffersize
);
4417 context
.vc_proc
= p
;
4418 context
.vc_ucred
= kauth_cred_get();
4419 tmpcount
= (u_long
) actualcount
;
4422 * If the only item requested is file names, we can let that past with
4423 * just LIST_DIRECTORY. If they want any other attributes, that means
4424 * they need SEARCH as well.
4426 action
= KAUTH_VNODE_LIST_DIRECTORY
;
4427 if ((attributelist
.commonattr
& ~ATTR_CMN_NAME
) ||
4428 attributelist
.fileattr
|| attributelist
.dirattr
)
4429 action
|= KAUTH_VNODE_SEARCH
;
4431 if ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) == 0)
4432 error
= VNOP_READDIRATTR(vp
, &attributelist
, auio
,
4433 tmpcount
, uap
->options
, &newstate
, &eofflag
,
4434 &tmpcount
, &context
);
4435 (void)vnode_put(vp
);
4436 actualcount
= tmpcount
;
4440 fp
->f_fglob
->fg_offset
= uio_offset(auio
); /* should be multiple of dirent, not variable */
4442 if ((error
= suulong(uap
->count
, actualcount
)) != 0)
4444 if ((error
= suulong(uap
->newstate
, (uint64_t)newstate
)) != 0)
4446 if ((error
= suulong(uap
->basep
, (uint64_t)loff
)) != 0)
4449 *retval
= eofflag
; /* similar to getdirentries */
4453 return (error
); /* return error earlier, an retval of 0 or 1 now */
4455 } /* end of getdirentryattr system call */
4458 * Exchange data between two files
4463 exchangedata (struct proc
*p
, register struct exchangedata_args
*uap
, __unused register_t
*retval
)
4466 struct nameidata fnd
, snd
;
4467 struct vfs_context context
;
4468 struct vnode
*fvp
, *svp
;
4474 fse_info f_finfo
, s_finfo
;
4476 context
.vc_proc
= p
;
4477 context
.vc_ucred
= kauth_cred_get();
4480 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4482 NDINIT(&fnd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4483 UIO_USERSPACE
, uap
->path1
, &context
);
4485 error
= namei(&fnd
);
4492 NDINIT(&snd
, LOOKUP
, nameiflags
| AUDITVNPATH2
,
4493 UIO_USERSPACE
, uap
->path2
, &context
);
4495 error
= namei(&snd
);
4504 * if the files are the same, return an inval error
4512 * if the files are on different volumes, return an error
4514 if (svp
->v_mount
!= fvp
->v_mount
) {
4518 if (((error
= vnode_authorize(fvp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0) ||
4519 ((error
= vnode_authorize(svp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0))
4522 if (need_fsevent(FSE_EXCHANGE
, fvp
) || kauth_authorize_fileop_has_listeners()) {
4523 fpath
= get_pathbuff();
4524 spath
= get_pathbuff();
4527 if (vn_getpath(fvp
, fpath
, &flen
) != 0 || fpath
[0] == '\0') {
4528 printf("exchange: vn_getpath(fvp=0x%x) failed <<%s>>\n",
4531 if (vn_getpath(svp
, spath
, &slen
) != 0 || spath
[0] == '\0') {
4532 printf("exchange: vn_getpath(svp=0x%x) failed <<%s>>\n",
4535 get_fse_info(fvp
, &f_finfo
, &context
);
4536 get_fse_info(svp
, &s_finfo
, &context
);
4538 /* Ok, make the call */
4539 error
= VNOP_EXCHANGE(fvp
, svp
, 0, &context
);
4544 if (fpath
!= NULL
&& spath
!= NULL
) {
4545 /* call out to allow 3rd party notification of exchangedata.
4546 * Ignore result of kauth_authorize_fileop call.
4548 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_EXCHANGE
,
4549 (uintptr_t)fpath
, (uintptr_t)spath
);
4553 tmpname
= fvp
->v_name
;
4554 fvp
->v_name
= svp
->v_name
;
4555 svp
->v_name
= tmpname
;
4557 if (fvp
->v_parent
!= svp
->v_parent
) {
4560 tmp
= fvp
->v_parent
;
4561 fvp
->v_parent
= svp
->v_parent
;
4562 svp
->v_parent
= tmp
;
4564 name_cache_unlock();
4566 if (fpath
!= NULL
&& spath
!= NULL
) {
4567 add_fsevent(FSE_EXCHANGE
, &context
,
4568 FSE_ARG_STRING
, flen
, fpath
,
4569 FSE_ARG_FINFO
, &f_finfo
,
4570 FSE_ARG_STRING
, slen
, spath
,
4571 FSE_ARG_FINFO
, &s_finfo
,
4576 release_pathbuff(spath
);
4578 release_pathbuff(fpath
);
4588 #ifdef __APPLE_API_OBSOLETE
4590 /************************************************/
4591 /* *** Following calls will be deleted soon *** */
4592 /************************************************/
4595 * Check users access to a file
4599 #warning "checkuseraccess copies a cred in from user space but"
4600 #warning "user space has no way of knowing what one looks like"
4601 #warning "this code should use the access_extended spoof-as functionality"
4603 checkuseraccess (struct proc
*p
, register struct checkuseraccess_args
*uap
, __unused register_t
*retval
)
4605 register struct vnode
*vp
;
4607 struct nameidata nd
;
4608 struct ucred cred
; /* XXX ILLEGAL */
4609 int flags
; /*what will actually get passed to access*/
4611 struct vfs_context context
;
4613 /* Make sure that the number of groups is correct before we do anything */
4615 if ((uap
->ngroups
<= 0) || (uap
->ngroups
> NGROUPS
))
4618 /* Verify that the caller is root */
4620 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
4623 /* Fill in the credential structure */
4626 cred
.cr_uid
= uap
->userid
;
4627 cred
.cr_ngroups
= uap
->ngroups
;
4628 if ((error
= copyin(CAST_USER_ADDR_T(uap
->groups
), (caddr_t
) &(cred
.cr_groups
), (sizeof(gid_t
))*uap
->ngroups
)))
4631 context
.vc_proc
= p
;
4632 context
.vc_ucred
= &cred
;
4634 /* Get our hands on the file */
4636 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4637 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4638 UIO_USERSPACE
, CAST_USER_ADDR_T(uap
->path
), &context
);
4640 if ((error
= namei(&nd
)))
4645 /* Flags == 0 means only check for existence. */
4649 if (uap
->accessrequired
) {
4650 if (uap
->accessrequired
& R_OK
)
4651 flags
|= KAUTH_VNODE_READ_DATA
;
4652 if (uap
->accessrequired
& W_OK
)
4653 flags
|= KAUTH_VNODE_WRITE_DATA
;
4654 if (uap
->accessrequired
& X_OK
)
4655 flags
|= KAUTH_VNODE_EXECUTE
;
4657 error
= vnode_authorize(vp
, NULL
, flags
, &context
);
4666 } /* end of checkuseraccess system call */
4668 /************************************************/
4669 /* *** Preceding calls will be deleted soon *** */
4670 /************************************************/
4672 #endif /* __APPLE_API_OBSOLETE */
4679 searchfs (struct proc
*p
, register struct searchfs_args
*uap
, __unused register_t
*retval
)
4681 register struct vnode
*vp
;
4684 struct nameidata nd
;
4685 struct user_fssearchblock searchblock
;
4686 struct searchstate
*state
;
4687 struct attrlist
*returnattrs
;
4688 void *searchparams1
,*searchparams2
;
4690 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4694 struct vfs_context context
;
4695 char uio_buf
[ UIO_SIZEOF(1) ];
4697 context
.vc_proc
= p
;
4698 context
.vc_ucred
= kauth_cred_get();
4700 /* Start by copying in fsearchblock paramater list */
4701 if (IS_64BIT_PROCESS(p
)) {
4702 error
= copyin(uap
->searchblock
, (caddr_t
) &searchblock
, sizeof(searchblock
));
4705 struct fssearchblock tmp_searchblock
;
4706 error
= copyin(uap
->searchblock
, (caddr_t
) &tmp_searchblock
, sizeof(tmp_searchblock
));
4707 // munge into 64-bit version
4708 searchblock
.returnattrs
= CAST_USER_ADDR_T(tmp_searchblock
.returnattrs
);
4709 searchblock
.returnbuffer
= CAST_USER_ADDR_T(tmp_searchblock
.returnbuffer
);
4710 searchblock
.returnbuffersize
= tmp_searchblock
.returnbuffersize
;
4711 searchblock
.maxmatches
= tmp_searchblock
.maxmatches
;
4712 searchblock
.timelimit
= tmp_searchblock
.timelimit
;
4713 searchblock
.searchparams1
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams1
);
4714 searchblock
.sizeofsearchparams1
= tmp_searchblock
.sizeofsearchparams1
;
4715 searchblock
.searchparams2
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams2
);
4716 searchblock
.sizeofsearchparams2
= tmp_searchblock
.sizeofsearchparams2
;
4717 searchblock
.searchattrs
= tmp_searchblock
.searchattrs
;
4722 /* Do a sanity check on sizeofsearchparams1 and sizeofsearchparams2.
4724 if (searchblock
.sizeofsearchparams1
> SEARCHFS_MAX_SEARCHPARMS
||
4725 searchblock
.sizeofsearchparams2
> SEARCHFS_MAX_SEARCHPARMS
)
4728 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
4729 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
4730 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
4733 mallocsize
= searchblock
.sizeofsearchparams1
+ searchblock
.sizeofsearchparams2
+
4734 sizeof(struct attrlist
) + sizeof(struct searchstate
);
4736 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
4738 /* Now set up the various pointers to the correct place in our newly allocated memory */
4740 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
4741 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
4742 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
4744 /* Now copy in the stuff given our local variables. */
4746 if ((error
= copyin(searchblock
.searchparams1
, searchparams1
, searchblock
.sizeofsearchparams1
)))
4749 if ((error
= copyin(searchblock
.searchparams2
, searchparams2
, searchblock
.sizeofsearchparams2
)))
4752 if ((error
= copyin(searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
))))
4755 if ((error
= copyin(uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
))))
4758 /* set up the uio structure which will contain the users return buffer */
4760 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
4761 &uio_buf
[0], sizeof(uio_buf
));
4762 uio_addiov(auio
, searchblock
.returnbuffer
, searchblock
.returnbuffersize
);
4765 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4766 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4767 UIO_USERSPACE
, uap
->path
, &context
);
4778 * If searchblock.maxmatches == 0, then skip the search. This has happened
4779 * before and sometimes the underlyning code doesnt deal with it well.
4781 if (searchblock
.maxmatches
== 0) {
4787 Allright, we have everything we need, so lets make that call.
4789 We keep special track of the return value from the file system:
4790 EAGAIN is an acceptable error condition that shouldn't keep us
4791 from copying out any results...
4794 fserror
= VNOP_SEARCHFS(vp
,
4797 &searchblock
.searchattrs
,
4798 searchblock
.maxmatches
,
4799 &searchblock
.timelimit
,
4812 /* Now copy out the stuff that needs copying out. That means the number of matches, the
4813 search state. Everything was already put into he return buffer by the vop call. */
4815 if ((error
= copyout((caddr_t
) state
, uap
->state
, sizeof(struct searchstate
))) != 0)
4818 if ((error
= suulong(uap
->nummatches
, (uint64_t)nummatches
)) != 0)
4825 FREE(searchparams1
,M_TEMP
);
4830 } /* end of searchfs system call */
4834 * Make a filesystem-specific control call:
4838 fsctl (struct proc
*p
, struct fsctl_args
*uap
, __unused register_t
*retval
)
4842 struct nameidata nd
;
4844 u_long cmd
= uap
->cmd
;
4845 register u_int size
;
4846 #define STK_PARAMS 128
4847 char stkbuf
[STK_PARAMS
];
4849 struct vfs_context context
;
4851 context
.vc_proc
= p
;
4852 context
.vc_ucred
= kauth_cred_get();
4854 size
= IOCPARM_LEN(cmd
);
4855 if (size
> IOCPARM_MAX
) return (EINVAL
);
4857 is64bit
= proc_is64bit(p
);
4860 if (size
> sizeof (stkbuf
)) {
4861 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
4869 error
= copyin(uap
->data
, data
, size
);
4870 if (error
) goto FSCtl_Exit
;
4873 *(user_addr_t
*)data
= uap
->data
;
4876 *(uint32_t *)data
= (uint32_t)uap
->data
;
4879 } else if ((cmd
& IOC_OUT
) && size
) {
4881 * Zero the buffer so the user always
4882 * gets back something deterministic.
4885 } else if (cmd
& IOC_VOID
) {
4887 *(user_addr_t
*)data
= uap
->data
;
4890 *(uint32_t *)data
= (uint32_t)uap
->data
;
4894 /* Get the vnode for the file we are getting info on: */
4896 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4897 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, uap
->path
, &context
);
4898 if ((error
= namei(&nd
))) goto FSCtl_Exit
;
4900 /* Invoke the filesystem-specific code */
4901 error
= VNOP_IOCTL(nd
.ni_vp
, IOCBASECMD(cmd
), data
, uap
->options
, &context
);
4903 vnode_put(nd
.ni_vp
);
4907 * Copy any data to user, size was
4908 * already set and checked above.
4910 if (error
== 0 && (cmd
& IOC_OUT
) && size
)
4911 error
= copyout(data
, uap
->data
, size
);
4914 if (memp
) kfree(memp
, size
);
4918 /* end of fsctl system call */
4921 * An in-kernel sync for power management to call.
4923 __private_extern__
int
4928 struct sync_args data
;
4933 error
= sync(current_proc(), &data
, &retval
[0]);
4937 } /* end of sync_internal call */
4941 * Retrieve the data of an extended attribute.
4944 getxattr(struct proc
*p
, struct getxattr_args
*uap
, user_ssize_t
*retval
)
4947 struct nameidata nd
;
4948 char attrname
[XATTR_MAXNAMELEN
+1];
4949 struct vfs_context context
;
4951 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4952 size_t attrsize
= 0;
4956 char uio_buf
[ UIO_SIZEOF(1) ];
4958 context
.vc_proc
= p
;
4959 context
.vc_ucred
= kauth_cred_get();
4961 if (uap
->options
& XATTR_NOSECURITY
)
4964 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
4965 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
4966 if ((error
= namei(&nd
))) {
4972 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
4975 if (xattr_protected(attrname
)) {
4979 if (uap
->value
&& uap
->size
> 0) {
4980 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
4981 &uio_buf
[0], sizeof(uio_buf
));
4982 uio_addiov(auio
, uap
->value
, uap
->size
);
4985 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, &context
);
4990 *retval
= uap
->size
- uio_resid(auio
);
4992 *retval
= (user_ssize_t
)attrsize
;
4999 * Retrieve the data of an extended attribute.
5002 fgetxattr(struct proc
*p
, struct fgetxattr_args
*uap
, user_ssize_t
*retval
)
5005 char attrname
[XATTR_MAXNAMELEN
+1];
5006 struct vfs_context context
;
5008 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5009 size_t attrsize
= 0;
5012 char uio_buf
[ UIO_SIZEOF(1) ];
5014 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5017 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5020 if ( (error
= vnode_getwithref(vp
)) ) {
5024 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5027 if (xattr_protected(attrname
)) {
5031 if (uap
->value
&& uap
->size
> 0) {
5032 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
5033 &uio_buf
[0], sizeof(uio_buf
));
5034 uio_addiov(auio
, uap
->value
, uap
->size
);
5036 context
.vc_proc
= p
;
5037 context
.vc_ucred
= kauth_cred_get();
5039 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, &context
);
5041 (void)vnode_put(vp
);
5045 *retval
= uap
->size
- uio_resid(auio
);
5047 *retval
= (user_ssize_t
)attrsize
;
5053 * Set the data of an extended attribute.
5056 setxattr(struct proc
*p
, struct setxattr_args
*uap
, int *retval
)
5059 struct nameidata nd
;
5060 char attrname
[XATTR_MAXNAMELEN
+1];
5061 struct vfs_context context
;
5063 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5067 char uio_buf
[ UIO_SIZEOF(1) ];
5069 context
.vc_proc
= p
;
5070 context
.vc_ucred
= kauth_cred_get();
5072 if (uap
->options
& XATTR_NOSECURITY
)
5075 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5078 if (xattr_protected(attrname
))
5080 if (uap
->value
== 0 || uap
->size
== 0) {
5084 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5085 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5086 if ((error
= namei(&nd
))) {
5092 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
5093 &uio_buf
[0], sizeof(uio_buf
));
5094 uio_addiov(auio
, uap
->value
, uap
->size
);
5096 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, &context
);
5103 * Set the data of an extended attribute.
5106 fsetxattr(struct proc
*p
, struct fsetxattr_args
*uap
, int *retval
)
5109 char attrname
[XATTR_MAXNAMELEN
+1];
5110 struct vfs_context context
;
5112 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5115 char uio_buf
[ UIO_SIZEOF(1) ];
5117 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5120 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5123 if (xattr_protected(attrname
))
5125 if (uap
->value
== 0 || uap
->size
== 0) {
5128 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5131 if ( (error
= vnode_getwithref(vp
)) ) {
5135 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
5136 &uio_buf
[0], sizeof(uio_buf
));
5137 uio_addiov(auio
, uap
->value
, uap
->size
);
5138 context
.vc_proc
= p
;
5139 context
.vc_ucred
= kauth_cred_get();
5141 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, &context
);
5149 * Remove an extended attribute.
5151 #warning "code duplication"
5153 removexattr(struct proc
*p
, struct removexattr_args
*uap
, int *retval
)
5156 struct nameidata nd
;
5157 char attrname
[XATTR_MAXNAMELEN
+1];
5158 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5159 struct vfs_context context
;
5164 context
.vc_proc
= p
;
5165 context
.vc_ucred
= kauth_cred_get();
5167 if (uap
->options
& XATTR_NOSECURITY
)
5170 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
5174 if (xattr_protected(attrname
))
5176 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5177 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5178 if ((error
= namei(&nd
))) {
5184 error
= vn_removexattr(vp
, attrname
, uap
->options
, &context
);
5191 * Remove an extended attribute.
5193 #warning "code duplication"
5195 fremovexattr(struct proc
*p
, struct fremovexattr_args
*uap
, int *retval
)
5198 char attrname
[XATTR_MAXNAMELEN
+1];
5199 struct vfs_context context
;
5203 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5206 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
5210 if (xattr_protected(attrname
))
5212 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5215 if ( (error
= vnode_getwithref(vp
)) ) {
5219 context
.vc_proc
= p
;
5220 context
.vc_ucred
= kauth_cred_get();
5222 error
= vn_removexattr(vp
, attrname
, uap
->options
, &context
);
5230 * Retrieve the list of extended attribute names.
5232 #warning "code duplication"
5234 listxattr(struct proc
*p
, struct listxattr_args
*uap
, user_ssize_t
*retval
)
5237 struct nameidata nd
;
5238 struct vfs_context context
;
5240 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5241 size_t attrsize
= 0;
5244 char uio_buf
[ UIO_SIZEOF(1) ];
5246 context
.vc_proc
= p
;
5247 context
.vc_ucred
= kauth_cred_get();
5249 if (uap
->options
& XATTR_NOSECURITY
)
5252 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5253 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5254 if ((error
= namei(&nd
))) {
5259 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
5260 // LP64todo - fix this!
5261 auio
= uio_createwithbuffer(1, 0, spacetype
,
5262 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
5263 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
5266 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, &context
);
5270 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
5272 *retval
= (user_ssize_t
)attrsize
;
5278 * Retrieve the list of extended attribute names.
5280 #warning "code duplication"
5282 flistxattr(struct proc
*p
, struct flistxattr_args
*uap
, user_ssize_t
*retval
)
5285 struct vfs_context context
;
5287 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5288 size_t attrsize
= 0;
5290 char uio_buf
[ UIO_SIZEOF(1) ];
5292 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5295 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5298 if ( (error
= vnode_getwithref(vp
)) ) {
5302 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
5303 // LP64todo - fix this!
5304 auio
= uio_createwithbuffer(1, 0, spacetype
,
5305 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
5306 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
5308 context
.vc_proc
= p
;
5309 context
.vc_ucred
= kauth_cred_get();
5311 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, &context
);
5316 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
5318 *retval
= (user_ssize_t
)attrsize
;
5324 * Common routine to handle various flavors of statfs data heading out
5328 munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
5329 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
5330 boolean_t partial_copy
)
5333 int my_size
, copy_size
;
5336 struct user_statfs sfs
;
5337 my_size
= copy_size
= sizeof(sfs
);
5338 bzero(&sfs
, my_size
);
5339 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
5340 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
5341 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
5342 sfs
.f_bsize
= (user_long_t
)sfsp
->f_bsize
;
5343 sfs
.f_iosize
= (user_long_t
)sfsp
->f_iosize
;
5344 sfs
.f_blocks
= (user_long_t
)sfsp
->f_blocks
;
5345 sfs
.f_bfree
= (user_long_t
)sfsp
->f_bfree
;
5346 sfs
.f_bavail
= (user_long_t
)sfsp
->f_bavail
;
5347 sfs
.f_files
= (user_long_t
)sfsp
->f_files
;
5348 sfs
.f_ffree
= (user_long_t
)sfsp
->f_ffree
;
5349 sfs
.f_fsid
= sfsp
->f_fsid
;
5350 sfs
.f_owner
= sfsp
->f_owner
;
5351 strncpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
-1);
5352 strncpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
-1);
5353 strncpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
-1);
5356 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
5358 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
5362 my_size
= copy_size
= sizeof(sfs
);
5363 bzero(&sfs
, my_size
);
5365 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
5366 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
5367 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
5370 * It's possible for there to be more than 2^^31 blocks in the filesystem, so we
5371 * have to fudge the numbers here in that case. We inflate the blocksize in order
5372 * to reflect the filesystem size as best we can.
5374 if ((sfsp
->f_blocks
> LONG_MAX
)
5375 /* Hack for 4061702 . I think the real fix is for Carbon to
5376 * look for some volume capability and not depend on hidden
5377 * semantics agreed between a FS and carbon.
5378 * f_blocks, f_bfree, and f_bavail set to -1 is the trigger
5379 * for Carbon to set bNoVolumeSizes volume attribute.
5380 * Without this the webdavfs files cannot be copied onto
5381 * disk as they look huge. This change should not affect
5382 * XSAN as they should not setting these to -1..
5384 && (sfsp
->f_blocks
!= 0xffffffffffffffff)
5385 && (sfsp
->f_bfree
!= 0xffffffffffffffff)
5386 && (sfsp
->f_bavail
!= 0xffffffffffffffff)) {
5390 * Work out how far we have to shift the block count down to make it fit.
5391 * Note that it's possible to have to shift so far that the resulting
5392 * blocksize would be unreportably large. At that point, we will clip
5393 * any values that don't fit.
5395 * For safety's sake, we also ensure that f_iosize is never reported as
5396 * being smaller than f_bsize.
5398 for (shift
= 0; shift
< 32; shift
++) {
5399 if ((sfsp
->f_blocks
>> shift
) <= LONG_MAX
)
5401 if ((sfsp
->f_bsize
<< (shift
+ 1)) > LONG_MAX
)
5404 #define __SHIFT_OR_CLIP(x, s) ((((x) >> (s)) > LONG_MAX) ? LONG_MAX : ((x) >> (s)))
5405 sfs
.f_blocks
= (long)__SHIFT_OR_CLIP(sfsp
->f_blocks
, shift
);
5406 sfs
.f_bfree
= (long)__SHIFT_OR_CLIP(sfsp
->f_bfree
, shift
);
5407 sfs
.f_bavail
= (long)__SHIFT_OR_CLIP(sfsp
->f_bavail
, shift
);
5408 #undef __SHIFT_OR_CLIP
5409 sfs
.f_bsize
= (long)(sfsp
->f_bsize
<< shift
);
5410 sfs
.f_iosize
= lmax(sfsp
->f_iosize
, sfsp
->f_bsize
);
5412 /* filesystem is small enough to be reported honestly */
5413 sfs
.f_bsize
= (long)sfsp
->f_bsize
;
5414 sfs
.f_iosize
= (long)sfsp
->f_iosize
;
5415 sfs
.f_blocks
= (long)sfsp
->f_blocks
;
5416 sfs
.f_bfree
= (long)sfsp
->f_bfree
;
5417 sfs
.f_bavail
= (long)sfsp
->f_bavail
;
5419 sfs
.f_files
= (long)sfsp
->f_files
;
5420 sfs
.f_ffree
= (long)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
);
5433 if (sizep
!= NULL
) {
5440 * copy stat structure into user_stat structure.
5442 void munge_stat(struct stat
*sbp
, struct user_stat
*usbp
)
5444 usbp
->st_dev
= sbp
->st_dev
;
5445 usbp
->st_ino
= sbp
->st_ino
;
5446 usbp
->st_mode
= sbp
->st_mode
;
5447 usbp
->st_nlink
= sbp
->st_nlink
;
5448 usbp
->st_uid
= sbp
->st_uid
;
5449 usbp
->st_gid
= sbp
->st_gid
;
5450 usbp
->st_rdev
= sbp
->st_rdev
;
5451 #ifndef _POSIX_SOURCE
5452 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
5453 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
5454 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
5455 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
5456 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
5457 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
5459 usbp
->st_atime
= sbp
->st_atime
;
5460 usbp
->st_atimensec
= sbp
->st_atimensec
;
5461 usbp
->st_mtime
= sbp
->st_mtime
;
5462 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
5463 usbp
->st_ctime
= sbp
->st_ctime
;
5464 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
5466 usbp
->st_size
= sbp
->st_size
;
5467 usbp
->st_blocks
= sbp
->st_blocks
;
5468 usbp
->st_blksize
= sbp
->st_blksize
;
5469 usbp
->st_flags
= sbp
->st_flags
;
5470 usbp
->st_gen
= sbp
->st_gen
;
5471 usbp
->st_lspare
= sbp
->st_lspare
;
5472 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
5473 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];