2 * Copyright (c) 1995-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 * Copyright (c) 1989, 1993
25 * The Regents of the University of California. All rights reserved.
26 * (c) UNIX System Laboratories, Inc.
27 * All or some portions of this file are derived from material licensed
28 * to the University of California by American Telephone and Telegraph
29 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
30 * the permission of UNIX System Laboratories, Inc.
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * @(#)vfs_syscalls.c 8.41 (Berkeley) 6/15/95
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/namei.h>
66 #include <sys/filedesc.h>
67 #include <sys/kernel.h>
68 #include <sys/file_internal.h>
70 #include <sys/vnode_internal.h>
71 #include <sys/mount_internal.h>
72 #include <sys/proc_internal.h>
73 #include <sys/kauth.h>
74 #include <sys/uio_internal.h>
75 #include <sys/malloc.h>
77 #include <sys/dirent.h>
79 #include <sys/sysctl.h>
81 #include <sys/quota.h>
82 #include <sys/kdebug.h>
83 #include <sys/fsevents.h>
84 #include <sys/sysproto.h>
85 #include <sys/xattr.h>
86 #include <sys/ubc_internal.h>
87 #include <machine/cons.h>
88 #include <machine/limits.h>
89 #include <miscfs/specfs/specdev.h>
91 #include <bsm/audit_kernel.h>
92 #include <bsm/audit_kevents.h>
94 #include <mach/mach_types.h>
95 #include <kern/kern_types.h>
96 #include <kern/kalloc.h>
98 #include <vm/vm_pageout.h>
100 #include <architecture/byte_order.h>
101 #include <libkern/OSAtomic.h>
105 * The currently logged-in user, for ownership of files/directories whose on-disk
106 * permissions are ignored:
110 static int change_dir(struct nameidata
*ndp
, vfs_context_t ctx
);
111 static void checkdirs(struct vnode
*olddp
, vfs_context_t ctx
);
112 void enablequotas(struct mount
*mp
, vfs_context_t ctx
);
113 static int getfsstat_callback(mount_t mp
, void * arg
);
114 static int getutimes(user_addr_t usrtvp
, struct timespec
*tsp
);
115 static int setutimes(vfs_context_t ctx
, struct vnode
*vp
, const struct timespec
*ts
, int nullflag
);
116 static int sync_callback(mount_t
, void *);
117 static int munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
118 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
119 boolean_t partial_copy
);
121 __private_extern__
int sync_internal(void);
123 #ifdef __APPLE_API_OBSOLETE
125 int fd
; /* file descriptor of the target file */
126 struct vstat
*vsb
; /* vstat structure for returned info */
129 const char *path
; /* pathname of the target file */
130 struct vstat
*vsb
; /* vstat structure for returned info */
132 struct mkcomplex_args
{
133 const char *path
; /* pathname of the file to be created */
134 mode_t mode
; /* access mode for the newly created file */
135 u_long type
; /* format of the complex file */
138 const char *path
; /* pathname of the target file */
139 struct vstat
*vsb
; /* vstat structure for returned info */
142 int fstatv(struct proc
*p
, struct fstatv_args
*uap
, register_t
*retval
);
143 int lstatv(struct proc
*p
, struct lstatv_args
*uap
, register_t
*retval
);
144 int mkcomplex(struct proc
*p
, struct mkcomplex_args
*uap
, register_t
*retval
);
145 int statv(struct proc
*p
, struct statv_args
*uap
, register_t
*retval
);
147 #endif /* __APPLE_API_OBSOLETE */
150 extern int (**union_vnodeop_p
)(void *);
151 extern struct vnode
*union_dircache(struct vnode
*, struct proc
*);
154 /* counts number of mount and unmount operations */
155 unsigned int vfs_nummntops
=0;
157 extern struct fileops vnops
;
159 extern void mount_list_add(mount_t mp
);
160 extern void mount_list_remove(mount_t mp
);
161 extern int mount_refdrain(mount_t mp
);
162 extern int vcount(struct vnode
*vp
);
166 * Virtual File System System Calls
170 * Mount a file system.
174 mount(struct proc
*p
, register struct mount_args
*uap
, __unused register_t
*retval
)
177 struct vnode
*devvp
= NULLVP
;
178 struct vnode
*device_vnode
= NULLVP
;
180 struct vfstable
*vfsp
;
182 struct vnode_attr va
;
183 struct vfs_context context
;
185 struct nameidata nd1
;
186 char fstypename
[MFSNAMELEN
];
188 user_addr_t devpath
= USER_ADDR_NULL
;
189 user_addr_t fsmountargs
= uap
->data
;
195 AUDIT_ARG(fflags
, uap
->flags
);
198 context
.vc_ucred
= kauth_cred_get();
199 is_64bit
= proc_is64bit(p
);
202 * Get vnode to be covered
204 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
205 UIO_USERSPACE
, uap
->path
, &context
);
211 if ((vp
->v_flag
& VROOT
) &&
212 (vp
->v_mount
->mnt_flag
& MNT_ROOTFS
))
213 uap
->flags
|= MNT_UPDATE
;
215 if (uap
->flags
& MNT_UPDATE
) {
216 if ((vp
->v_flag
& VROOT
) == 0) {
222 /* unmount in progress return error */
224 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
230 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
232 * We only allow the filesystem to be reloaded if it
233 * is currently mounted read-only.
235 if ((uap
->flags
& MNT_RELOAD
) &&
236 ((mp
->mnt_flag
& MNT_RDONLY
) == 0)) {
237 lck_rw_done(&mp
->mnt_rwlock
);
242 * Only root, or the user that did the original mount is
243 * permitted to update it.
245 if (mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(context
.vc_ucred
) &&
246 (error
= suser(context
.vc_ucred
, &p
->p_acflag
))) {
247 lck_rw_done(&mp
->mnt_rwlock
);
251 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV,
252 * and MNT_NOEXEC if mount point is already MNT_NOEXEC.
254 if (suser(context
.vc_ucred
, NULL
)) {
255 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
256 if (mp
->mnt_flag
& MNT_NOEXEC
)
257 uap
->flags
|= MNT_NOEXEC
;
262 uap
->flags
& (MNT_RELOAD
| MNT_FORCE
| MNT_UPDATE
);
264 vfsp
= mp
->mnt_vtable
;
268 * If the user is not root, ensure that they own the directory
269 * onto which we are attempting to mount.
272 VATTR_WANTED(&va
, va_uid
);
273 if ((error
= vnode_getattr(vp
, &va
, &context
)) ||
274 (va
.va_uid
!= kauth_cred_getuid(context
.vc_ucred
) &&
275 (error
= suser(context
.vc_ucred
, &p
->p_acflag
)))) {
279 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV, and
280 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
282 if (suser(context
.vc_ucred
, NULL
)) {
283 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
284 if (vp
->v_mount
->mnt_flag
& MNT_NOEXEC
)
285 uap
->flags
|= MNT_NOEXEC
;
287 if ( (error
= VNOP_FSYNC(vp
, MNT_WAIT
, &context
)) )
290 if ( (error
= buf_invalidateblks(vp
, BUF_WRITE_DATA
, 0, 0)) )
293 if (vp
->v_type
!= VDIR
) {
297 if ( (error
= copyinstr(uap
->type
, fstypename
, MFSNAMELEN
, &dummy
)) )
300 /* XXXAUDIT: Should we capture the type on the error path as well? */
301 AUDIT_ARG(text
, fstypename
);
303 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
304 if (!strcmp(vfsp
->vfc_name
, fstypename
))
311 if (ISSET(vp
->v_flag
, VMOUNT
) && (vp
->v_mountedhere
!= NULL
)) {
315 SET(vp
->v_flag
, VMOUNT
);
318 * Allocate and initialize the filesystem.
320 MALLOC_ZONE(mp
, struct mount
*, (u_long
)sizeof(struct mount
),
322 bzero((char *)mp
, (u_long
)sizeof(struct mount
));
325 /* Initialize the default IO constraints */
326 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
327 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
328 mp
->mnt_maxsegreadsize
= mp
->mnt_maxreadcnt
;
329 mp
->mnt_maxsegwritesize
= mp
->mnt_maxwritecnt
;
330 mp
->mnt_devblocksize
= DEV_BSIZE
;
332 TAILQ_INIT(&mp
->mnt_vnodelist
);
333 TAILQ_INIT(&mp
->mnt_workerqueue
);
334 TAILQ_INIT(&mp
->mnt_newvnodes
);
336 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
337 mp
->mnt_op
= vfsp
->vfc_vfsops
;
338 mp
->mnt_vtable
= vfsp
;
340 vfsp
->vfc_refcount
++;
342 //mp->mnt_stat.f_type = vfsp->vfc_typenum;
343 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
344 strncpy(mp
->mnt_vfsstat
.f_fstypename
, vfsp
->vfc_name
, MFSTYPENAMELEN
);
345 strncpy(mp
->mnt_vfsstat
.f_mntonname
, nd
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
346 mp
->mnt_vnodecovered
= vp
;
347 mp
->mnt_vfsstat
.f_owner
= kauth_cred_getuid(context
.vc_ucred
);
349 /* XXX 3762912 hack to support HFS filesystem 'owner' - filesystem may update later */
350 vfs_setowner(mp
, KAUTH_UID_NONE
, KAUTH_GID_NONE
);
354 * Set the mount level flags.
356 if (uap
->flags
& MNT_RDONLY
)
357 mp
->mnt_flag
|= MNT_RDONLY
;
358 else if (mp
->mnt_flag
& MNT_RDONLY
)
359 mp
->mnt_kern_flag
|= MNTK_WANTRDWR
;
360 mp
->mnt_flag
&= ~(MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
361 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
362 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
);
363 mp
->mnt_flag
|= uap
->flags
& (MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
364 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
365 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
|
368 if (vfsp
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
370 if ( (error
= copyin(fsmountargs
, (caddr_t
)&devpath
, sizeof(devpath
))) )
372 fsmountargs
+= sizeof(devpath
);
375 if ( (error
= copyin(fsmountargs
, (caddr_t
)&tmp
, sizeof(tmp
))) )
377 /* munge into LP64 addr */
378 devpath
= CAST_USER_ADDR_T(tmp
);
379 fsmountargs
+= sizeof(tmp
);
382 /* if it is not update and device name needs to be parsed */
384 NDINIT(&nd1
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, devpath
, &context
);
385 if ( (error
= namei(&nd1
)) )
388 strncpy(mp
->mnt_vfsstat
.f_mntfromname
, nd1
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
393 if (devvp
->v_type
!= VBLK
) {
397 if (major(devvp
->v_rdev
) >= nblkdev
) {
402 * If mount by non-root, then verify that user has necessary
403 * permissions on the device.
405 if (suser(context
.vc_ucred
, NULL
) != 0) {
406 accessmode
= KAUTH_VNODE_READ_DATA
;
407 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
408 accessmode
|= KAUTH_VNODE_WRITE_DATA
;
409 if ((error
= vnode_authorize(devvp
, NULL
, accessmode
, &context
)) != 0)
413 if (devpath
&& ((uap
->flags
& MNT_UPDATE
) == 0)) {
414 if ( (error
= vnode_ref(devvp
)) )
417 * Disallow multiple mounts of the same device.
418 * Disallow mounting of a device that is currently in use
419 * (except for root, which might share swap device for miniroot).
420 * Flush out any old buffers remaining from a previous use.
422 if ( (error
= vfs_mountedon(devvp
)) )
425 if (vcount(devvp
) > 1 && !(vfs_flags(mp
) & MNT_ROOTFS
)) {
429 if ( (error
= VNOP_FSYNC(devvp
, MNT_WAIT
, &context
)) ) {
433 if ( (error
= buf_invalidateblks(devvp
, BUF_WRITE_DATA
, 0, 0)) )
436 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
437 if ( (error
= VNOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, &context
)) )
440 mp
->mnt_devvp
= devvp
;
441 device_vnode
= devvp
;
443 if ((mp
->mnt_flag
& MNT_RDONLY
) && (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)) {
445 * If upgrade to read-write by non-root, then verify
446 * that user has necessary permissions on the device.
448 device_vnode
= mp
->mnt_devvp
;
449 if (device_vnode
&& suser(context
.vc_ucred
, NULL
)) {
450 if ((error
= vnode_authorize(device_vnode
, NULL
,
451 KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0)
455 device_vnode
= NULLVP
;
461 * Mount the filesystem.
463 error
= VFS_MOUNT(mp
, device_vnode
, fsmountargs
, &context
);
465 if (uap
->flags
& MNT_UPDATE
) {
466 if (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)
467 mp
->mnt_flag
&= ~MNT_RDONLY
;
469 (MNT_UPDATE
| MNT_RELOAD
| MNT_FORCE
);
470 mp
->mnt_kern_flag
&=~ MNTK_WANTRDWR
;
473 vfs_event_signal(NULL
, VQ_UPDATE
, (intptr_t)NULL
);
474 lck_rw_done(&mp
->mnt_rwlock
);
476 enablequotas(mp
,&context
);
480 * Put the new filesystem on the mount list after root.
483 CLR(vp
->v_flag
, VMOUNT
);
486 vp
->v_mountedhere
= mp
;
491 vfs_event_signal(NULL
, VQ_MOUNT
, (intptr_t)NULL
);
492 checkdirs(vp
, &context
);
493 lck_rw_done(&mp
->mnt_rwlock
);
496 * there is no cleanup code here so I have made it void
497 * we need to revisit this
499 (void)VFS_START(mp
, 0, &context
);
501 /* increment the operations count */
502 OSAddAtomic(1, (SInt32
*)&vfs_nummntops
);
503 enablequotas(mp
,&context
);
506 device_vnode
->v_specflags
|= SI_MOUNTEDON
;
509 * cache the IO attributes for the underlying physical media...
510 * an error return indicates the underlying driver doesn't
511 * support all the queries necessary... however, reasonable
512 * defaults will have been set, so no reason to bail or care
514 vfs_init_io_attributes(device_vnode
, mp
);
517 CLR(vp
->v_flag
, VMOUNT
);
519 mp
->mnt_vtable
->vfc_refcount
--;
523 VNOP_CLOSE(device_vnode
, ronly
? FREAD
: FREAD
|FWRITE
, &context
);
524 vnode_rele(device_vnode
);
526 lck_rw_done(&mp
->mnt_rwlock
);
527 mount_lock_destroy(mp
);
528 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
533 * drop I/O count on covered 'vp' and
534 * on the device vp if there was one
536 if (devpath
&& devvp
)
545 if (devpath
&& devvp
)
549 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
558 enablequotas(struct mount
*mp
, vfs_context_t context
)
560 struct nameidata qnd
;
562 char qfpath
[MAXPATHLEN
];
563 const char *qfname
= QUOTAFILENAME
;
564 const char *qfopsname
= QUOTAOPSNAME
;
565 const char *qfextension
[] = INITQFNAMES
;
567 if ((strcmp(mp
->mnt_vfsstat
.f_fstypename
, "hfs") != 0 )
568 && (strcmp( mp
->mnt_vfsstat
.f_fstypename
, "ufs") != 0))
572 * Enable filesystem disk quotas if necessary.
573 * We ignore errors as this should not interfere with final mount
575 for (type
=0; type
< MAXQUOTAS
; type
++) {
576 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfopsname
, qfextension
[type
]);
577 NDINIT(&qnd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE32
, CAST_USER_ADDR_T(qfpath
), context
);
578 if (namei(&qnd
) != 0)
579 continue; /* option file to trigger quotas is not present */
580 vnode_put(qnd
.ni_vp
);
582 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfname
, qfextension
[type
]);
584 (void) VFS_QUOTACTL(mp
, QCMD(Q_QUOTAON
, type
), 0, qfpath
, context
);
590 * Scan all active processes to see if any of them have a current
591 * or root directory onto which the new filesystem has just been
592 * mounted. If so, replace them with the new mount point.
595 checkdirs(olddp
, context
)
597 vfs_context_t context
;
599 struct filedesc
*fdp
;
603 struct vnode
*fdp_cvp
;
604 struct vnode
*fdp_rvp
;
605 int cdir_changed
= 0;
606 int rdir_changed
= 0;
607 boolean_t funnel_state
;
609 if (olddp
->v_usecount
== 1)
611 if (VFS_ROOT(olddp
->v_mountedhere
, &newdp
, context
))
612 panic("mount: lost mount");
613 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
615 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
618 if (fdp
== (struct filedesc
*)0) {
622 fdp_cvp
= fdp
->fd_cdir
;
623 fdp_rvp
= fdp
->fd_rdir
;
626 if (fdp_cvp
== olddp
) {
633 if (fdp_rvp
== olddp
) {
640 if (cdir_changed
|| rdir_changed
) {
642 fdp
->fd_cdir
= fdp_cvp
;
643 fdp
->fd_rdir
= fdp_rvp
;
647 if (rootvnode
== olddp
) {
653 thread_funnel_set(kernel_flock
, funnel_state
);
659 * Unmount a file system.
661 * Note: unmount takes a path to the vnode mounted on as argument,
662 * not special file (as before).
666 unmount(struct proc
*p
, register struct unmount_args
*uap
, __unused register_t
*retval
)
668 register struct vnode
*vp
;
672 struct vfs_context context
;
675 context
.vc_ucred
= kauth_cred_get();
677 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
678 UIO_USERSPACE
, uap
->path
, &context
);
687 * Must be the root of the filesystem
689 if ((vp
->v_flag
& VROOT
) == 0) {
694 return (safedounmount(mp
, uap
->flags
, p
));
698 * Do the actual file system unmount, prevent some common foot shooting.
700 * XXX Should take a "vfs_context_t" instead of a "struct proc *"
703 safedounmount(mp
, flags
, p
)
711 * Only root, or the user that did the original mount is
712 * permitted to unmount this filesystem.
714 if ((mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(kauth_cred_get())) &&
715 (error
= suser(kauth_cred_get(), &p
->p_acflag
)))
719 * Don't allow unmounting the root file system.
721 if (mp
->mnt_flag
& MNT_ROOTFS
)
722 return (EBUSY
); /* the root is always busy */
724 return (dounmount(mp
, flags
, p
));
728 * Do the actual file system unmount.
731 dounmount(mp
, flags
, p
)
732 register struct mount
*mp
;
736 struct vnode
*coveredvp
= (vnode_t
)0;
739 struct vfs_context context
;
740 int forcedunmount
= 0;
744 context
.vc_ucred
= kauth_cred_get();
746 if (flags
& MNT_FORCE
)
749 /* XXX post jaguar fix LK_DRAIN - then clean this up */
750 if ((flags
& MNT_FORCE
)) {
751 mp
->mnt_kern_flag
|= MNTK_FRCUNMOUNT
;
752 mp
->mnt_lflag
|= MNT_LFORCE
;
754 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
755 mp
->mnt_lflag
|= MNT_LWAIT
;
756 msleep((caddr_t
)mp
, &mp
->mnt_mlock
, (PVFS
| PDROP
), "dounmount", 0 );
758 * The prior unmount attempt has probably succeeded.
759 * Do not dereference mp here - returning EBUSY is safest.
763 mp
->mnt_kern_flag
|= MNTK_UNMOUNT
;
764 mp
->mnt_lflag
|= MNT_LUNMOUNT
;
765 mp
->mnt_flag
&=~ MNT_ASYNC
;
767 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
768 fsevent_unmount(mp
); /* has to come first! */
770 if (forcedunmount
== 0) {
771 ubc_umount(mp
); /* release cached vnodes */
772 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
773 error
= VFS_SYNC(mp
, MNT_WAIT
, &context
);
776 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
777 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
778 mp
->mnt_lflag
&= ~MNT_LFORCE
;
785 lflags
|= FORCECLOSE
;
786 error
= vflush(mp
, NULLVP
, SKIPSWAP
| SKIPSYSTEM
| SKIPROOT
| lflags
);
787 if ((forcedunmount
== 0) && error
) {
789 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
790 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
791 mp
->mnt_lflag
&= ~MNT_LFORCE
;
795 /* make sure there are no one in the mount iterations or lookup */
798 error
= VFS_UNMOUNT(mp
, flags
, &context
);
802 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
803 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
804 mp
->mnt_lflag
&= ~MNT_LFORCE
;
808 /* increment the operations count */
810 OSAddAtomic(1, (SInt32
*)&vfs_nummntops
);
812 if ( mp
->mnt_devvp
&& mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
813 mp
->mnt_devvp
->v_specflags
&= ~SI_MOUNTEDON
;
814 VNOP_CLOSE(mp
->mnt_devvp
, mp
->mnt_flag
& MNT_RDONLY
? FREAD
: FREAD
|FWRITE
,
816 vnode_rele(mp
->mnt_devvp
);
818 lck_rw_done(&mp
->mnt_rwlock
);
819 mount_list_remove(mp
);
820 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
822 /* mark the mount point hook in the vp but not drop the ref yet */
823 if ((coveredvp
= mp
->mnt_vnodecovered
) != NULLVP
) {
824 vnode_getwithref(coveredvp
);
825 vnode_lock(coveredvp
);
826 coveredvp
->v_mountedhere
= (struct mount
*)0;
827 vnode_unlock(coveredvp
);
828 vnode_put(coveredvp
);
832 mp
->mnt_vtable
->vfc_refcount
--;
835 cache_purgevfs(mp
); /* remove cache entries for this file sys */
836 vfs_event_signal(NULL
, VQ_UNMOUNT
, (intptr_t)NULL
);
838 mp
->mnt_lflag
|= MNT_LDEAD
;
840 if (mp
->mnt_lflag
& MNT_LWAIT
) {
843 * in case we block in mount_refdrain
844 * which will drop the mount lock
845 * and allow anyone blocked in vfs_busy
846 * to wakeup and see the LDEAD state
848 mp
->mnt_lflag
&= ~MNT_LWAIT
;
853 if (mp
->mnt_lflag
& MNT_LWAIT
) {
854 mp
->mnt_lflag
&= ~MNT_LWAIT
;
858 lck_rw_done(&mp
->mnt_rwlock
);
863 if ((coveredvp
!= NULLVP
)) {
864 vnode_getwithref(coveredvp
);
865 vnode_rele(coveredvp
);
866 vnode_lock(coveredvp
);
867 if(mp
->mnt_crossref
== 0) {
868 vnode_unlock(coveredvp
);
869 mount_lock_destroy(mp
);
870 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
872 coveredvp
->v_lflag
|= VL_MOUNTDEAD
;
873 vnode_unlock(coveredvp
);
875 vnode_put(coveredvp
);
876 } else if (mp
->mnt_flag
& MNT_ROOTFS
) {
877 mount_lock_destroy(mp
);
878 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
880 panic("dounmount: no coveredvp");
886 mount_dropcrossref(mount_t mp
, vnode_t dp
, int need_put
)
890 if (mp
->mnt_crossref
< 0)
891 panic("mount cross refs -ve");
892 if (((dp
->v_lflag
& VL_MOUNTDEAD
) == VL_MOUNTDEAD
) && (mp
->mnt_crossref
== 0)) {
893 dp
->v_lflag
&= ~VL_MOUNTDEAD
;
895 vnode_put_locked(dp
);
897 mount_lock_destroy(mp
);
898 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
902 vnode_put_locked(dp
);
908 * Sync each mounted filesystem.
912 struct ctldebug debug0
= { "syncprt", &syncprt
};
915 int print_vmpage_stat
=0;
918 sync_callback(mount_t mp
, __unused
void * arg
)
920 struct proc
* p
= current_proc();
922 struct vfs_context context
;
925 context
.vc_ucred
= kauth_cred_get();
927 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
928 asyncflag
= mp
->mnt_flag
& MNT_ASYNC
;
929 mp
->mnt_flag
&= ~MNT_ASYNC
;
930 VFS_SYNC(mp
, MNT_NOWAIT
, &context
);
932 mp
->mnt_flag
|= MNT_ASYNC
;
934 return(VFS_RETURNED
);
938 extern unsigned int vp_pagein
, vp_pgodirty
, vp_pgoclean
;
939 extern unsigned int dp_pgins
, dp_pgouts
;
943 sync(__unused
struct proc
*p
, __unused
struct sync_args
*uap
, __unused register_t
*retval
)
946 vfs_iterate(LK_NOWAIT
, sync_callback
, (void *)0);
948 if(print_vmpage_stat
) {
949 vm_countdirtypages();
950 printf("VP: %d: %d: %d: %d: %d\n", vp_pgodirty
, vp_pgoclean
, vp_pagein
,
951 dp_pgins
, dp_pgouts
);
957 #endif /* DIAGNOSTIC */
962 * Change filesystem quotas.
966 quotactl(struct proc
*p
, register struct quotactl_args
*uap
, __unused register_t
*retval
)
968 register struct mount
*mp
;
969 int error
, quota_cmd
, quota_status
;
973 struct vfs_context context
;
974 struct dqblk my_dqblk
;
977 context
.vc_ucred
= kauth_cred_get();
979 AUDIT_ARG(uid
, uap
->uid
, 0, 0, 0);
980 AUDIT_ARG(cmd
, uap
->cmd
);
981 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
982 UIO_USERSPACE
, uap
->path
, &context
);
986 mp
= nd
.ni_vp
->v_mount
;
990 /* copyin any data we will need for downstream code */
991 quota_cmd
= uap
->cmd
>> SUBCMDSHIFT
;
995 /* uap->arg specifies a file from which to take the quotas */
996 fnamelen
= MAXPATHLEN
;
997 datap
= kalloc(MAXPATHLEN
);
998 error
= copyinstr(uap
->arg
, datap
, MAXPATHLEN
, &fnamelen
);
1001 /* uap->arg is a pointer to a dqblk structure. */
1002 datap
= (caddr_t
) &my_dqblk
;
1006 /* uap->arg is a pointer to a dqblk structure. */
1007 datap
= (caddr_t
) &my_dqblk
;
1008 if (proc_is64bit(p
)) {
1009 struct user_dqblk my_dqblk64
;
1010 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk64
, sizeof (my_dqblk64
));
1012 munge_dqblk(&my_dqblk
, &my_dqblk64
, FALSE
);
1016 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk
, sizeof (my_dqblk
));
1020 /* uap->arg is a pointer to an integer */
1021 datap
= (caddr_t
) "a_status
;
1029 error
= VFS_QUOTACTL(mp
, uap
->cmd
, uap
->uid
, datap
, &context
);
1032 switch (quota_cmd
) {
1035 kfree(datap
, MAXPATHLEN
);
1038 /* uap->arg is a pointer to a dqblk structure we need to copy out to */
1040 if (proc_is64bit(p
)) {
1041 struct user_dqblk my_dqblk64
;
1042 munge_dqblk(&my_dqblk
, &my_dqblk64
, TRUE
);
1043 error
= copyout((caddr_t
)&my_dqblk64
, uap
->arg
, sizeof (my_dqblk64
));
1046 error
= copyout(datap
, uap
->arg
, sizeof (struct dqblk
));
1051 /* uap->arg is a pointer to an integer */
1053 error
= copyout(datap
, uap
->arg
, sizeof(quota_status
));
1064 * Get filesystem statistics.
1068 statfs(struct proc
*p
, register struct statfs_args
*uap
, __unused register_t
*retval
)
1071 struct vfsstatfs
*sp
;
1073 struct nameidata nd
;
1074 struct vfs_context context
;
1077 context
.vc_proc
= p
;
1078 context
.vc_ucred
= kauth_cred_get();
1080 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1081 UIO_USERSPACE
, uap
->path
, &context
);
1087 sp
= &mp
->mnt_vfsstat
;
1090 error
= vfs_update_vfsstat(mp
, &context
);
1095 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1100 * Get filesystem statistics.
1104 fstatfs(struct proc
*p
, register struct fstatfs_args
*uap
, __unused register_t
*retval
)
1108 struct vfsstatfs
*sp
;
1110 struct vfs_context context
;
1112 context
.vc_proc
= p
;
1113 context
.vc_ucred
= kauth_cred_get();
1115 AUDIT_ARG(fd
, uap
->fd
);
1117 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1120 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
1127 sp
= &mp
->mnt_vfsstat
;
1128 if ((error
= vfs_update_vfsstat(mp
, &context
)) != 0) {
1134 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1140 struct getfsstat_struct
{
1150 getfsstat_callback(mount_t mp
, void * arg
)
1153 struct getfsstat_struct
*fstp
= (struct getfsstat_struct
*)arg
;
1154 struct vfsstatfs
*sp
;
1155 struct proc
* p
= current_proc();
1157 struct vfs_context context
;
1159 context
.vc_proc
= p
;
1160 context
.vc_ucred
= kauth_cred_get();
1162 if (fstp
->sfsp
&& fstp
->count
< fstp
->maxcount
) {
1163 sp
= &mp
->mnt_vfsstat
;
1165 * If MNT_NOWAIT is specified, do not refresh the
1166 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
1168 if (((fstp
->flags
& MNT_NOWAIT
) == 0 || (fstp
->flags
& MNT_WAIT
)) &&
1169 (error
= vfs_update_vfsstat(mp
, &context
))) {
1170 KAUTH_DEBUG("vfs_update_vfsstat returned %d", error
);
1171 return(VFS_RETURNED
);
1175 * Need to handle LP64 version of struct statfs
1177 error
= munge_statfs(mp
, sp
, fstp
->sfsp
, &my_size
, IS_64BIT_PROCESS(p
), FALSE
);
1179 fstp
->error
= error
;
1180 return(VFS_RETURNED_DONE
);
1182 fstp
->sfsp
+= my_size
;
1185 return(VFS_RETURNED
);
1189 * Get statistics on all filesystems.
1192 getfsstat(__unused proc_t p
, struct getfsstat_args
*uap
, int *retval
)
1195 int count
, maxcount
;
1196 struct getfsstat_struct fst
;
1198 if (IS_64BIT_PROCESS(p
)) {
1199 maxcount
= uap
->bufsize
/ sizeof(struct user_statfs
);
1202 maxcount
= uap
->bufsize
/ sizeof(struct statfs
);
1208 fst
.flags
= uap
->flags
;
1211 fst
.maxcount
= maxcount
;
1214 vfs_iterate(0, getfsstat_callback
, &fst
);
1217 KAUTH_DEBUG("ERROR - %s gets %d", p
->p_comm
, fst
.error
);
1221 if (fst
.sfsp
&& fst
.count
> fst
.maxcount
)
1222 *retval
= fst
.maxcount
;
1224 *retval
= fst
.count
;
1228 #if COMPAT_GETFSSTAT
1229 ogetfsstat(p
, uap
, retval
)
1231 register struct getfsstat_args
*uap
;
1239 * Change current working directory to a given file descriptor.
1243 fchdir(struct proc
*p
, struct fchdir_args
*uap
, __unused register_t
*retval
)
1245 register struct filedesc
*fdp
= p
->p_fd
;
1246 struct vnode
*vp
, *tdp
, *tvp
;
1249 struct vfs_context context
;
1251 context
.vc_proc
= p
;
1252 context
.vc_ucred
= kauth_cred_get();
1254 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1256 if ( (error
= vnode_getwithref(vp
)) ) {
1261 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
1263 if (vp
->v_type
!= VDIR
)
1266 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, &context
);
1267 while (!error
&& (mp
= vp
->v_mountedhere
) != NULL
) {
1268 if (vfs_busy(mp
, LK_NOWAIT
)) {
1272 error
= VFS_ROOT(mp
, &tdp
, &context
);
1281 if ( (error
= vnode_ref(vp
)) )
1303 * Change current working directory (``.'').
1307 chdir(struct proc
*p
, struct chdir_args
*uap
, __unused register_t
*retval
)
1309 register struct filedesc
*fdp
= p
->p_fd
;
1311 struct nameidata nd
;
1313 struct vfs_context context
;
1315 context
.vc_proc
= p
;
1316 context
.vc_ucred
= kauth_cred_get();
1318 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1319 UIO_USERSPACE
, uap
->path
, &context
);
1320 error
= change_dir(&nd
, &context
);
1323 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
1324 vnode_put(nd
.ni_vp
);
1328 * drop the iocount we picked up in change_dir
1330 vnode_put(nd
.ni_vp
);
1334 fdp
->fd_cdir
= nd
.ni_vp
;
1344 * Change notion of root (``/'') directory.
1348 chroot(struct proc
*p
, struct chroot_args
*uap
, __unused register_t
*retval
)
1350 register struct filedesc
*fdp
= p
->p_fd
;
1352 struct nameidata nd
;
1353 boolean_t shared_regions_active
;
1355 struct vfs_context context
;
1357 context
.vc_proc
= p
;
1358 context
.vc_ucred
= kauth_cred_get();
1360 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
1363 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1364 UIO_USERSPACE
, uap
->path
, &context
);
1365 error
= change_dir(&nd
, &context
);
1369 if(p
->p_flag
& P_NOSHLIB
) {
1370 shared_regions_active
= FALSE
;
1372 shared_regions_active
= TRUE
;
1374 if ((error
= clone_system_shared_regions(shared_regions_active
,
1375 TRUE
, /* chain_regions */
1377 vnode_put(nd
.ni_vp
);
1380 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
1381 vnode_put(nd
.ni_vp
);
1384 vnode_put(nd
.ni_vp
);
1388 fdp
->fd_rdir
= nd
.ni_vp
;
1389 fdp
->fd_flags
|= FD_CHROOT
;
1399 * Common routine for chroot and chdir.
1402 change_dir(struct nameidata
*ndp
, vfs_context_t ctx
)
1407 if ((error
= namei(ndp
)))
1411 if (vp
->v_type
!= VDIR
)
1414 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, ctx
);
1422 * Check permissions, allocate an open file structure,
1423 * and call the device open routine if any.
1426 #warning XXX implement uid, gid
1428 open1(vfs_context_t ctx
, user_addr_t upath
, int uflags
, struct vnode_attr
*vap
, register_t
*retval
)
1430 struct proc
*p
= vfs_context_proc(ctx
);
1431 register struct filedesc
*fdp
= p
->p_fd
;
1432 register struct fileproc
*fp
;
1433 register struct vnode
*vp
;
1435 struct fileproc
*nfp
;
1436 int type
, indx
, error
;
1438 struct nameidata nd
;
1442 if ((oflags
& O_ACCMODE
) == O_ACCMODE
)
1444 flags
= FFLAGS(uflags
);
1446 AUDIT_ARG(fflags
, oflags
);
1447 AUDIT_ARG(mode
, vap
->va_mode
);
1449 if ( (error
= falloc(p
, &nfp
, &indx
)) ) {
1453 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1454 UIO_USERSPACE
, upath
, ctx
);
1455 p
->p_dupfd
= -indx
- 1; /* XXX check for fdopen */
1457 if ((error
= vn_open_auth(&nd
, &flags
, vap
))) {
1458 if ((error
== ENODEV
|| error
== ENXIO
) && (p
->p_dupfd
>= 0)) { /* XXX from fdopen */
1459 if ((error
= dupfdopen(fdp
, indx
, p
->p_dupfd
, flags
, error
)) == 0) {
1460 fp_drop(p
, indx
, 0, 0);
1465 if (error
== ERESTART
)
1467 fp_free(p
, indx
, fp
);
1474 fp
->f_fglob
->fg_flag
= flags
& (FMASK
| O_EVTONLY
);
1475 fp
->f_fglob
->fg_type
= DTYPE_VNODE
;
1476 fp
->f_fglob
->fg_ops
= &vnops
;
1477 fp
->f_fglob
->fg_data
= (caddr_t
)vp
;
1479 if (flags
& (O_EXLOCK
| O_SHLOCK
)) {
1480 lf
.l_whence
= SEEK_SET
;
1483 if (flags
& O_EXLOCK
)
1484 lf
.l_type
= F_WRLCK
;
1486 lf
.l_type
= F_RDLCK
;
1488 if ((flags
& FNONBLOCK
) == 0)
1490 if ((error
= VNOP_ADVLOCK(vp
, (caddr_t
)fp
->f_fglob
, F_SETLK
, &lf
, type
, ctx
)))
1492 fp
->f_fglob
->fg_flag
|= FHASLOCK
;
1495 /* try to truncate by setting the size attribute */
1496 if ((flags
& O_TRUNC
) && ((error
= vnode_setsize(vp
, (off_t
)0, 0, ctx
)) != 0))
1502 *fdflags(p
, indx
) &= ~UF_RESERVED
;
1503 fp_drop(p
, indx
, fp
, 1);
1510 vn_close(vp
, fp
->f_fglob
->fg_flag
, fp
->f_fglob
->fg_cred
, p
);
1512 fp_free(p
, indx
, fp
);
1519 open_extended(struct proc
*p
, struct open_extended_args
*uap
, register_t
*retval
)
1521 struct vfs_context context
;
1522 register struct filedesc
*fdp
= p
->p_fd
;
1524 kauth_filesec_t xsecdst
;
1525 struct vnode_attr va
;
1529 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
1530 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
1533 context
.vc_proc
= p
;
1534 context
.vc_ucred
= kauth_cred_get();
1537 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
1538 VATTR_SET(&va
, va_mode
, cmode
);
1539 if (uap
->uid
!= KAUTH_UID_NONE
)
1540 VATTR_SET(&va
, va_uid
, uap
->uid
);
1541 if (uap
->gid
!= KAUTH_GID_NONE
)
1542 VATTR_SET(&va
, va_gid
, uap
->gid
);
1543 if (xsecdst
!= NULL
)
1544 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
1546 ciferror
= open1(&context
, uap
->path
, uap
->flags
, &va
, retval
);
1547 if (xsecdst
!= NULL
)
1548 kauth_filesec_free(xsecdst
);
1554 open(struct proc
*p
, struct open_args
*uap
, register_t
*retval
)
1556 struct vfs_context context
;
1557 register struct filedesc
*fdp
= p
->p_fd
;
1558 struct vnode_attr va
;
1561 context
.vc_proc
= p
;
1562 context
.vc_ucred
= kauth_cred_get();
1565 /* Mask off all but regular access permissions */
1566 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
1567 VATTR_SET(&va
, va_mode
, cmode
& ACCESSPERMS
);
1569 return(open1(&context
, uap
->path
, uap
->flags
, &va
, retval
));
1574 * Create a special file.
1576 static int mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
);
1579 mknod(struct proc
*p
, register struct mknod_args
*uap
, __unused register_t
*retval
)
1581 struct vnode_attr va
;
1582 struct vfs_context context
;
1585 struct nameidata nd
;
1588 context
.vc_proc
= p
;
1589 context
.vc_ucred
= kauth_cred_get();
1592 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1593 VATTR_SET(&va
, va_rdev
, uap
->dev
);
1595 /* If it's a mknod() of a FIFO, call mkfifo1() instead */
1596 if ((uap
->mode
& S_IFMT
) == S_IFIFO
)
1597 return(mkfifo1(&context
, uap
->path
, &va
));
1599 AUDIT_ARG(mode
, uap
->mode
);
1600 AUDIT_ARG(dev
, uap
->dev
);
1602 if ((error
= suser(context
.vc_ucred
, &p
->p_acflag
)))
1604 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1605 UIO_USERSPACE
, uap
->path
, &context
);
1617 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
1620 switch (uap
->mode
& S_IFMT
) {
1621 case S_IFMT
: /* used by badsect to flag bad sectors */
1622 VATTR_SET(&va
, va_type
, VBAD
);
1625 VATTR_SET(&va
, va_type
, VCHR
);
1628 VATTR_SET(&va
, va_type
, VBLK
);
1638 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, CREATE
, &context
);
1640 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, &va
, 0, &context
);
1646 int update_flags
= 0;
1648 // Make sure the name & parent pointers are hooked up
1649 if (vp
->v_name
== NULL
)
1650 update_flags
|= VNODE_UPDATE_NAME
;
1651 if (vp
->v_parent
== NULLVP
)
1652 update_flags
|= VNODE_UPDATE_PARENT
;
1655 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
1657 add_fsevent(FSE_CREATE_FILE
, &context
,
1664 * nameidone has to happen before we vnode_put(dvp)
1665 * since it may need to release the fs_nodelock on the dvp
1677 * Create a named pipe.
1680 mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
)
1684 struct nameidata nd
;
1686 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1687 UIO_USERSPACE
, upath
, ctx
);
1694 /* check that this is a new file and authorize addition */
1699 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
1702 VATTR_SET(vap
, va_type
, VFIFO
);
1704 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
);
1707 * nameidone has to happen before we vnode_put(dvp)
1708 * since it may need to release the fs_nodelock on the dvp
1720 mkfifo_extended(struct proc
*p
, struct mkfifo_extended_args
*uap
, __unused register_t
*retval
)
1723 kauth_filesec_t xsecdst
;
1724 struct vfs_context context
;
1725 struct vnode_attr va
;
1727 xsecdst
= KAUTH_FILESEC_NONE
;
1728 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
1729 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
1733 context
.vc_proc
= p
;
1734 context
.vc_ucred
= kauth_cred_get();
1737 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1738 if (uap
->uid
!= KAUTH_UID_NONE
)
1739 VATTR_SET(&va
, va_uid
, uap
->uid
);
1740 if (uap
->gid
!= KAUTH_GID_NONE
)
1741 VATTR_SET(&va
, va_gid
, uap
->gid
);
1742 if (xsecdst
!= KAUTH_FILESEC_NONE
)
1743 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
1745 ciferror
= mkfifo1(&context
, uap
->path
, &va
);
1747 if (xsecdst
!= KAUTH_FILESEC_NONE
)
1748 kauth_filesec_free(xsecdst
);
1754 mkfifo(struct proc
*p
, register struct mkfifo_args
*uap
, __unused register_t
*retval
)
1756 struct vfs_context context
;
1757 struct vnode_attr va
;
1759 context
.vc_proc
= p
;
1760 context
.vc_ucred
= kauth_cred_get();
1763 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1765 return(mkfifo1(&context
, uap
->path
, &va
));
1769 * Make a hard file link.
1773 link(struct proc
*p
, register struct link_args
*uap
, __unused register_t
*retval
)
1775 vnode_t vp
, dvp
, lvp
;
1776 struct nameidata nd
;
1777 struct vfs_context context
;
1780 int need_event
, has_listeners
;
1782 context
.vc_proc
= p
;
1783 context
.vc_ucred
= kauth_cred_get();
1784 vp
= dvp
= lvp
= NULLVP
;
1786 /* look up the object we are linking to */
1787 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1788 UIO_USERSPACE
, uap
->path
, &context
);
1796 /* we're not allowed to link to directories */
1797 if (vp
->v_type
== VDIR
) {
1798 error
= EPERM
; /* POSIX */
1802 /* or to anything that kauth doesn't want us to (eg. immutable items) */
1803 if ((error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_LINKTARGET
, &context
)) != 0)
1806 /* lookup the target node */
1807 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1808 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| AUDITVNPATH2
;
1809 nd
.ni_dirp
= uap
->link
;
1815 /* target node must not exist */
1816 if (lvp
!= NULLVP
) {
1820 /* cannot link across mountpoints */
1821 if (vnode_mount(vp
) != vnode_mount(dvp
)) {
1826 /* authorize creation of the target note */
1827 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
1830 /* and finally make the link */
1831 error
= VNOP_LINK(vp
, dvp
, &nd
.ni_cnd
, &context
);
1835 need_event
= need_fsevent(FSE_CREATE_FILE
, dvp
);
1836 has_listeners
= kauth_authorize_fileop_has_listeners();
1838 if (need_event
|| has_listeners
) {
1839 char *target_path
= NULL
;
1840 char *link_to_path
= NULL
;
1841 int len
, link_name_len
;
1843 /* build the path to the new link file */
1844 target_path
= get_pathbuff();
1846 vn_getpath(dvp
, target_path
, &len
);
1847 target_path
[len
-1] = '/';
1848 strcpy(&target_path
[len
], nd
.ni_cnd
.cn_nameptr
);
1849 len
+= nd
.ni_cnd
.cn_namelen
;
1851 if (has_listeners
) {
1852 /* build the path to file we are linking to */
1853 link_to_path
= get_pathbuff();
1854 link_name_len
= MAXPATHLEN
;
1855 vn_getpath(vp
, link_to_path
, &link_name_len
);
1857 /* call out to allow 3rd party notification of rename.
1858 * Ignore result of kauth_authorize_fileop call.
1860 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_LINK
,
1861 (uintptr_t)link_to_path
, (uintptr_t)target_path
);
1862 if (link_to_path
!= NULL
)
1863 release_pathbuff(link_to_path
);
1866 /* construct fsevent */
1867 if (get_fse_info(vp
, &finfo
, &context
) == 0) {
1868 // build the path to the destination of the link
1869 add_fsevent(FSE_CREATE_FILE
, &context
,
1870 FSE_ARG_STRING
, len
, target_path
,
1871 FSE_ARG_FINFO
, &finfo
,
1875 release_pathbuff(target_path
);
1879 * nameidone has to happen before we vnode_put(dvp)
1880 * since it may need to release the fs_nodelock on the dvp
1893 * Make a symbolic link.
1895 * We could add support for ACLs here too...
1899 symlink(struct proc
*p
, register struct symlink_args
*uap
, __unused register_t
*retval
)
1901 struct vnode_attr va
;
1904 struct nameidata nd
;
1905 struct vfs_context context
;
1909 context
.vc_proc
= p
;
1910 context
.vc_ucred
= kauth_cred_get();
1912 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1913 error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
);
1916 AUDIT_ARG(text
, path
); /* This is the link string */
1918 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1919 UIO_USERSPACE
, uap
->link
, &context
);
1928 VATTR_SET(&va
, va_type
, VLNK
);
1929 VATTR_SET(&va
, va_mode
, ACCESSPERMS
& ~p
->p_fd
->fd_cmask
);
1932 error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
);
1933 /* get default ownership, etc. */
1935 error
= vnode_authattr_new(dvp
, &va
, 0, &context
);
1937 error
= VNOP_SYMLINK(dvp
, &vp
, &nd
.ni_cnd
, &va
, path
, &context
);
1939 /* do fallback attribute handling */
1941 error
= vnode_setattr_fallback(vp
, &va
, &context
);
1944 int update_flags
= 0;
1947 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
1948 nd
.ni_cnd
.cn_flags
= 0;
1956 #if 0 /* XXX - kauth_todo - is KAUTH_FILEOP_SYMLINK needed? */
1957 /* call out to allow 3rd party notification of rename.
1958 * Ignore result of kauth_authorize_fileop call.
1960 if (kauth_authorize_fileop_has_listeners() &&
1962 char *new_link_path
= NULL
;
1965 /* build the path to the new link file */
1966 new_link_path
= get_pathbuff();
1968 vn_getpath(dvp
, new_link_path
, &len
);
1969 new_link_path
[len
- 1] = '/';
1970 strcpy(&new_link_path
[len
], nd
.ni_cnd
.cn_nameptr
);
1972 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_SYMLINK
,
1973 (uintptr_t)path
, (uintptr_t)new_link_path
);
1974 if (new_link_path
!= NULL
)
1975 release_pathbuff(new_link_path
);
1978 // Make sure the name & parent pointers are hooked up
1979 if (vp
->v_name
== NULL
)
1980 update_flags
|= VNODE_UPDATE_NAME
;
1981 if (vp
->v_parent
== NULLVP
)
1982 update_flags
|= VNODE_UPDATE_PARENT
;
1985 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
1987 add_fsevent(FSE_CREATE_FILE
, &context
,
1996 * nameidone has to happen before we vnode_put(dvp)
1997 * since it may need to release the fs_nodelock on the dvp
2005 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
2011 * Delete a whiteout from the filesystem.
2014 #warning XXX authorization not implmented for whiteouts
2016 undelete(struct proc
*p
, register struct undelete_args
*uap
, __unused register_t
*retval
)
2019 struct nameidata nd
;
2020 struct vfs_context context
;
2023 context
.vc_proc
= p
;
2024 context
.vc_ucred
= kauth_cred_get();
2026 NDINIT(&nd
, DELETE
, LOCKPARENT
|DOWHITEOUT
|AUDITVNPATH1
,
2027 UIO_USERSPACE
, uap
->path
, &context
);
2034 if (vp
== NULLVP
&& (nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
2035 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, DELETE
, &context
);
2040 * nameidone has to happen before we vnode_put(dvp)
2041 * since it may need to release the fs_nodelock on the dvp
2053 * Delete a name from the filesystem.
2057 _unlink(struct proc
*p
, struct unlink_args
*uap
, __unused register_t
*retval
, int nodelbusy
)
2061 struct nameidata nd
;
2062 struct vfs_context context
;
2063 struct componentname
*cnp
;
2066 context
.vc_proc
= p
;
2067 context
.vc_ucred
= kauth_cred_get();
2069 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
2070 UIO_USERSPACE
, uap
->path
, &context
);
2073 /* With Carbon delete semantics, busy files cannot be deleted */
2075 flags
|= VNODE_REMOVE_NODELETEBUSY
;
2083 if (vp
->v_type
== VDIR
) {
2084 error
= EPERM
; /* POSIX */
2087 * The root of a mounted filesystem cannot be deleted.
2089 if (vp
->v_flag
& VROOT
) {
2093 /* authorize the delete operation */
2095 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, &context
);
2102 if (need_fsevent(FSE_DELETE
, dvp
)) {
2103 path
= get_pathbuff();
2105 vn_getpath(vp
, path
, &len
);
2106 get_fse_info(vp
, &finfo
, &context
);
2108 error
= VNOP_REMOVE(dvp
, vp
, &nd
.ni_cnd
, flags
, &context
);
2110 if ( !error
&& path
!= NULL
) {
2111 add_fsevent(FSE_DELETE
, &context
,
2112 FSE_ARG_STRING
, len
, path
,
2113 FSE_ARG_FINFO
, &finfo
,
2117 release_pathbuff(path
);
2120 * nameidone has to happen before we vnode_put(dvp)
2121 * since it may need to release the fs_nodelock on the dvp
2130 * Delete a name from the filesystem using POSIX semantics.
2133 unlink(p
, uap
, retval
)
2135 struct unlink_args
*uap
;
2138 return _unlink(p
, uap
, retval
, 0);
2142 * Delete a name from the filesystem using Carbon semantics.
2145 delete(p
, uap
, retval
)
2147 struct delete_args
*uap
;
2150 return _unlink(p
, (struct unlink_args
*)uap
, retval
, 1);
2154 * Reposition read/write file offset.
2157 lseek(p
, uap
, retval
)
2159 register struct lseek_args
*uap
;
2162 struct fileproc
*fp
;
2164 struct vfs_context context
;
2165 off_t offset
= uap
->offset
, file_size
;
2168 if ( (error
= fp_getfvp(p
,uap
->fd
, &fp
, &vp
)) ) {
2169 if (error
== ENOTSUP
)
2173 if (vnode_isfifo(vp
)) {
2177 if ( (error
= vnode_getwithref(vp
)) ) {
2182 switch (uap
->whence
) {
2184 offset
+= fp
->f_fglob
->fg_offset
;
2187 context
.vc_proc
= p
;
2188 context
.vc_ucred
= kauth_cred_get();
2189 if ((error
= vnode_size(vp
, &file_size
, &context
)) != 0)
2191 offset
+= file_size
;
2199 if (uap
->offset
> 0 && offset
< 0) {
2200 /* Incremented/relative move past max size */
2204 * Allow negative offsets on character devices, per
2205 * POSIX 1003.1-2001. Most likely for writing disk
2208 if (offset
< 0 && vp
->v_type
!= VCHR
) {
2209 /* Decremented/relative move before start */
2213 fp
->f_fglob
->fg_offset
= offset
;
2214 *retval
= fp
->f_fglob
->fg_offset
;
2218 (void)vnode_put(vp
);
2225 * Check access permissions.
2228 access1(vnode_t vp
, vnode_t dvp
, int uflags
, vfs_context_t ctx
)
2230 kauth_action_t action
;
2234 * If just the regular access bits, convert them to something
2235 * that vnode_authorize will understand.
2237 if (!(uflags
& _ACCESS_EXTENDED_MASK
)) {
2240 action
|= KAUTH_VNODE_READ_DATA
; /* aka KAUTH_VNODE_LIST_DIRECTORY */
2241 if (uflags
& W_OK
) {
2242 if (vnode_isdir(vp
)) {
2243 action
|= KAUTH_VNODE_ADD_FILE
|
2244 KAUTH_VNODE_ADD_SUBDIRECTORY
;
2245 /* might want delete rights here too */
2247 action
|= KAUTH_VNODE_WRITE_DATA
;
2250 if (uflags
& X_OK
) {
2251 if (vnode_isdir(vp
)) {
2252 action
|= KAUTH_VNODE_SEARCH
;
2254 action
|= KAUTH_VNODE_EXECUTE
;
2258 /* take advantage of definition of uflags */
2259 action
= uflags
>> 8;
2262 /* action == 0 means only check for existence */
2264 error
= vnode_authorize(vp
, dvp
, action
| KAUTH_VNODE_ACCESS
, ctx
);
2274 /* XXX need to support the check-as uid argument */
2276 access_extended(__unused
struct proc
*p
, struct access_extended_args
*uap
, __unused register_t
*retval
)
2278 struct accessx_descriptor
*input
;
2280 int error
, limit
, nent
, i
, j
, wantdelete
;
2281 struct vfs_context context
;
2282 struct nameidata nd
;
2291 context
.vc_ucred
= NULL
;
2293 /* check input size and fetch descriptor array into allocated storage */
2294 if (uap
->size
> ACCESSX_MAX_TABLESIZE
)
2296 if (uap
->size
< sizeof(struct accessx_descriptor
))
2298 MALLOC(input
, struct accessx_descriptor
*, uap
->size
, M_TEMP
, M_WAITOK
);
2299 if (input
== NULL
) {
2303 error
= copyin(uap
->entries
, input
, uap
->size
);
2308 * Access is defined as checking against the process'
2309 * real identity, even if operations are checking the
2310 * effective identity. So we need to tweak the credential
2313 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
2314 context
.vc_proc
= current_proc();
2317 * Find out how many entries we have, so we can allocate the result array.
2319 limit
= uap
->size
/ sizeof(struct accessx_descriptor
);
2322 for (i
= 0; i
< nent
; i
++) {
2324 * Take the offset to the name string for this entry and convert to an
2325 * input array index, which would be one off the end of the array if this
2326 * was the lowest-addressed name string.
2328 j
= input
[i
].ad_name_offset
/ sizeof(struct accessx_descriptor
);
2334 /* implicit reference to previous name, not a real offset */
2336 /* first entry must have a name string */
2346 if (nent
> ACCESSX_MAX_DESCRIPTORS
) {
2350 MALLOC(result
, errno_t
*, nent
* sizeof(errno_t
), M_TEMP
, M_WAITOK
);
2351 if (result
== NULL
) {
2360 for (i
= 0; i
< nent
; i
++) {
2362 * Looking up a new name?
2364 if (input
[i
].ad_name_offset
!= 0) {
2365 /* discard old vnodes */
2375 /* scan forwards to see if we need the parent this time */
2376 wantdelete
= input
[i
].ad_flags
& _DELETE_OK
;
2377 for (j
= i
+ 1; (j
< nent
) && (input
[j
].ad_name_offset
== 0); j
++)
2378 if (input
[j
].ad_flags
& _DELETE_OK
)
2381 niopts
= FOLLOW
| AUDITVNPATH1
;
2382 /* need parent for vnode_authorize for deletion test */
2384 niopts
|= WANTPARENT
;
2387 NDINIT(&nd
, LOOKUP
, niopts
, UIO_SYSSPACE
, CAST_USER_ADDR_T((const char *)input
+ input
[i
].ad_name_offset
), &context
);
2398 * Handle lookup errors.
2408 /* run this access check */
2409 result
[i
] = access1(vp
, dvp
, input
[i
].ad_flags
, &context
);
2412 /* fatal lookup error */
2418 /* copy out results */
2419 error
= copyout(result
, uap
->results
, nent
* sizeof(errno_t
));
2423 FREE(input
, M_TEMP
);
2425 FREE(result
, M_TEMP
);
2430 if (context
.vc_ucred
)
2431 kauth_cred_rele(context
.vc_ucred
);
2436 access(__unused
struct proc
*p
, register struct access_args
*uap
, __unused register_t
*retval
)
2439 struct nameidata nd
;
2441 struct vfs_context context
;
2444 * Access is defined as checking against the process'
2445 * real identity, even if operations are checking the
2446 * effective identity. So we need to tweak the credential
2449 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
2450 context
.vc_proc
= current_proc();
2452 niopts
= FOLLOW
| AUDITVNPATH1
;
2453 /* need parent for vnode_authorize for deletion test */
2454 if (uap
->flags
& _DELETE_OK
)
2455 niopts
|= WANTPARENT
;
2456 NDINIT(&nd
, LOOKUP
, niopts
, UIO_USERSPACE
, uap
->path
, &context
);
2461 error
= access1(nd
.ni_vp
, nd
.ni_dvp
, uap
->flags
, &context
);
2463 vnode_put(nd
.ni_vp
);
2464 if (uap
->flags
& _DELETE_OK
)
2465 vnode_put(nd
.ni_dvp
);
2469 kauth_cred_rele(context
.vc_ucred
);
2475 stat2(vfs_context_t ctx
, struct nameidata
*ndp
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2478 struct user_stat user_sb
;
2481 kauth_filesec_t fsec
;
2482 size_t xsecurity_bufsize
;
2487 fsec
= KAUTH_FILESEC_NONE
;
2488 error
= vn_stat(ndp
->ni_vp
, &sb
, (xsecurity
!= USER_ADDR_NULL
? &fsec
: NULL
), ctx
);
2489 vnode_put(ndp
->ni_vp
);
2494 /* Zap spare fields */
2496 sb
.st_qspare
[0] = 0LL;
2497 sb
.st_qspare
[1] = 0LL;
2498 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
2499 munge_stat(&sb
, &user_sb
);
2500 my_size
= sizeof(user_sb
);
2501 sbp
= (caddr_t
)&user_sb
;
2504 my_size
= sizeof(sb
);
2507 if ((error
= copyout(sbp
, ub
, my_size
)) != 0)
2510 /* caller wants extended security information? */
2511 if (xsecurity
!= USER_ADDR_NULL
) {
2513 /* did we get any? */
2514 if (fsec
== KAUTH_FILESEC_NONE
) {
2515 if (susize(xsecurity_size
, 0) != 0) {
2520 /* find the user buffer size */
2521 xsecurity_bufsize
= fusize(xsecurity_size
);
2523 /* copy out the actual data size */
2524 if (susize(xsecurity_size
, KAUTH_FILESEC_COPYSIZE(fsec
)) != 0) {
2529 /* if the caller supplied enough room, copy out to it */
2530 if (xsecurity_bufsize
>= KAUTH_FILESEC_COPYSIZE(fsec
))
2531 error
= copyout(fsec
, xsecurity
, KAUTH_FILESEC_COPYSIZE(fsec
));
2535 if (fsec
!= KAUTH_FILESEC_NONE
)
2536 kauth_filesec_free(fsec
);
2541 * Get file status; this version follows links.
2544 stat1(struct proc
*p
, user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2546 struct nameidata nd
;
2547 struct vfs_context context
;
2549 context
.vc_proc
= p
;
2550 context
.vc_ucred
= kauth_cred_get();
2552 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2553 UIO_USERSPACE
, path
, &context
);
2554 return(stat2(&context
, &nd
, ub
, xsecurity
, xsecurity_size
));
2558 stat_extended(struct proc
*p
, struct stat_extended_args
*uap
, __unused register_t
*retval
)
2560 return (stat1(p
, uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
));
2564 stat(struct proc
*p
, struct stat_args
*uap
, __unused register_t
*retval
)
2566 return(stat1(p
, uap
->path
, uap
->ub
, 0, 0));
2570 * Get file status; this version does not follow links.
2573 lstat1(struct proc
*p
, user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2575 struct nameidata nd
;
2576 struct vfs_context context
;
2578 context
.vc_proc
= p
;
2579 context
.vc_ucred
= kauth_cred_get();
2581 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
2582 UIO_USERSPACE
, path
, &context
);
2584 return(stat2(&context
, &nd
, ub
, xsecurity
, xsecurity_size
));
2588 lstat_extended(struct proc
*p
, struct lstat_extended_args
*uap
, __unused register_t
*retval
)
2590 return (lstat1(p
, uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
));
2594 lstat(struct proc
*p
, struct lstat_args
*uap
, __unused register_t
*retval
)
2596 return(lstat1(p
, uap
->path
, uap
->ub
, 0, 0));
2600 * Get configurable pathname variables.
2604 pathconf(p
, uap
, retval
)
2606 register struct pathconf_args
*uap
;
2610 struct nameidata nd
;
2611 struct vfs_context context
;
2613 context
.vc_proc
= p
;
2614 context
.vc_ucred
= kauth_cred_get();
2616 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2617 UIO_USERSPACE
, uap
->path
, &context
);
2622 error
= vn_pathconf(nd
.ni_vp
, uap
->name
, retval
, &context
);
2624 vnode_put(nd
.ni_vp
);
2630 * Return target name of a symbolic link.
2634 readlink(p
, uap
, retval
)
2636 register struct readlink_args
*uap
;
2639 register struct vnode
*vp
;
2641 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
2643 struct nameidata nd
;
2644 struct vfs_context context
;
2645 char uio_buf
[ UIO_SIZEOF(1) ];
2647 context
.vc_proc
= p
;
2648 context
.vc_ucred
= kauth_cred_get();
2650 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
2651 UIO_USERSPACE
, uap
->path
, &context
);
2659 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
2660 &uio_buf
[0], sizeof(uio_buf
));
2661 uio_addiov(auio
, uap
->buf
, uap
->count
);
2662 if (vp
->v_type
!= VLNK
)
2665 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, &context
);
2667 error
= VNOP_READLINK(vp
, auio
, &context
);
2670 // LP64todo - fix this
2671 *retval
= uap
->count
- (int)uio_resid(auio
);
2676 * Change file flags.
2679 chflags1(vnode_t vp
, int flags
, vfs_context_t ctx
)
2681 struct vnode_attr va
;
2682 kauth_action_t action
;
2686 VATTR_SET(&va
, va_flags
, flags
);
2688 /* request authorisation, disregard immutability */
2689 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
2692 * Request that the auth layer disregard those file flags it's allowed to when
2693 * authorizing this operation; we need to do this in order to be able to
2694 * clear immutable flags.
2696 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
| KAUTH_VNODE_NOIMMUTABLE
, ctx
)) != 0))
2698 error
= vnode_setattr(vp
, &va
, ctx
);
2706 * Change flags of a file given a path name.
2710 chflags(struct proc
*p
, register struct chflags_args
*uap
, __unused register_t
*retval
)
2712 register struct vnode
*vp
;
2713 struct vfs_context context
;
2715 struct nameidata nd
;
2717 context
.vc_proc
= p
;
2718 context
.vc_ucred
= kauth_cred_get();
2720 AUDIT_ARG(fflags
, uap
->flags
);
2721 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2722 UIO_USERSPACE
, uap
->path
, &context
);
2729 error
= chflags1(vp
, uap
->flags
, &context
);
2735 * Change flags of a file given a file descriptor.
2739 fchflags(struct proc
*p
, register struct fchflags_args
*uap
, __unused register_t
*retval
)
2741 struct vfs_context context
;
2745 AUDIT_ARG(fd
, uap
->fd
);
2746 AUDIT_ARG(fflags
, uap
->flags
);
2747 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
2750 if ((error
= vnode_getwithref(vp
))) {
2755 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2757 context
.vc_proc
= p
;
2758 context
.vc_ucred
= kauth_cred_get();
2760 error
= chflags1(vp
, uap
->flags
, &context
);
2767 * Change security information on a filesystem object.
2770 chmod2(vfs_context_t ctx
, struct vnode
*vp
, struct vnode_attr
*vap
)
2772 kauth_action_t action
;
2775 AUDIT_ARG(mode
, (mode_t
)vap
->va_mode
);
2776 #warning XXX audit new args
2778 /* make sure that the caller is allowed to set this security information */
2779 if (((error
= vnode_authattr(vp
, vap
, &action
, ctx
)) != 0) ||
2780 ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
2781 if (error
== EACCES
)
2786 error
= vnode_setattr(vp
, vap
, ctx
);
2793 * Change mode of a file given path name.
2796 chmod1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
2798 struct nameidata nd
;
2801 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2802 UIO_USERSPACE
, path
, ctx
);
2803 if ((error
= namei(&nd
)))
2805 error
= chmod2(ctx
, nd
.ni_vp
, vap
);
2806 vnode_put(nd
.ni_vp
);
2812 chmod_extended(struct proc
*p
, struct chmod_extended_args
*uap
, __unused register_t
*retval
)
2814 struct vfs_context context
;
2816 struct vnode_attr va
;
2817 kauth_filesec_t xsecdst
;
2820 if (uap
->mode
!= -1)
2821 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2822 if (uap
->uid
!= KAUTH_UID_NONE
)
2823 VATTR_SET(&va
, va_uid
, uap
->uid
);
2824 if (uap
->gid
!= KAUTH_GID_NONE
)
2825 VATTR_SET(&va
, va_gid
, uap
->gid
);
2828 switch(uap
->xsecurity
) {
2829 /* explicit remove request */
2830 case CAST_USER_ADDR_T((void *)1): /* _FILESEC_REMOVE_ACL */
2831 VATTR_SET(&va
, va_acl
, NULL
);
2834 case USER_ADDR_NULL
:
2837 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
2839 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2840 KAUTH_DEBUG("CHMOD - setting ACL with %d entries", va
.va_acl
->acl_entrycount
);
2842 context
.vc_proc
= p
;
2843 context
.vc_ucred
= kauth_cred_get();
2845 error
= chmod1(&context
, uap
->path
, &va
);
2847 if (xsecdst
!= NULL
)
2848 kauth_filesec_free(xsecdst
);
2853 chmod(struct proc
*p
, register struct chmod_args
*uap
, __unused register_t
*retval
)
2855 struct vfs_context context
;
2856 struct vnode_attr va
;
2859 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2861 context
.vc_proc
= p
;
2862 context
.vc_ucred
= kauth_cred_get();
2864 return(chmod1(&context
, uap
->path
, &va
));
2868 * Change mode of a file given a file descriptor.
2871 fchmod1(struct proc
*p
, int fd
, struct vnode_attr
*vap
)
2875 struct vfs_context context
;
2877 context
.vc_proc
= p
;
2878 context
.vc_ucred
= kauth_cred_get();
2882 if ((error
= file_vnode(fd
, &vp
)) != 0)
2884 if ((error
= vnode_getwithref(vp
)) != 0) {
2888 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2890 error
= chmod2(&context
, vp
, vap
);
2891 (void)vnode_put(vp
);
2898 fchmod_extended(struct proc
*p
, struct fchmod_extended_args
*uap
, __unused register_t
*retval
)
2901 struct vnode_attr va
;
2902 kauth_filesec_t xsecdst
;
2905 if (uap
->mode
!= -1)
2906 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2907 if (uap
->uid
!= KAUTH_UID_NONE
)
2908 VATTR_SET(&va
, va_uid
, uap
->uid
);
2909 if (uap
->gid
!= KAUTH_GID_NONE
)
2910 VATTR_SET(&va
, va_gid
, uap
->gid
);
2913 switch(uap
->xsecurity
) {
2914 case USER_ADDR_NULL
:
2915 VATTR_SET(&va
, va_acl
, NULL
);
2917 case CAST_USER_ADDR_T(-1):
2920 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
2922 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2925 error
= fchmod1(p
, uap
->fd
, &va
);
2928 switch(uap
->xsecurity
) {
2929 case USER_ADDR_NULL
:
2930 case CAST_USER_ADDR_T(-1):
2933 if (xsecdst
!= NULL
)
2934 kauth_filesec_free(xsecdst
);
2940 fchmod(struct proc
*p
, register struct fchmod_args
*uap
, __unused register_t
*retval
)
2942 struct vnode_attr va
;
2945 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2947 return(fchmod1(p
, uap
->fd
, &va
));
2952 * Set ownership given a path name.
2956 chown1(vfs_context_t ctx
, register struct chown_args
*uap
, __unused register_t
*retval
, int follow
)
2958 register struct vnode
*vp
;
2959 struct vnode_attr va
;
2961 struct nameidata nd
;
2962 kauth_action_t action
;
2964 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
2966 NDINIT(&nd
, LOOKUP
, (follow
? FOLLOW
: 0) | AUDITVNPATH1
,
2967 UIO_USERSPACE
, uap
->path
, ctx
);
2976 * XXX A TEMPORARY HACK FOR NOW: Try to track console_user
2977 * by looking for chown() calls on /dev/console from a console process.
2979 if ((vp
) && (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
) && (vp
->v_specinfo
) &&
2980 (major(vp
->v_specinfo
->si_rdev
) == CONSMAJOR
) &&
2981 (minor(vp
->v_specinfo
->si_rdev
) == 0)) {
2982 console_user
= uap
->uid
;
2985 if (uap
->uid
!= VNOVAL
)
2986 VATTR_SET(&va
, va_uid
, uap
->uid
);
2987 if (uap
->gid
!= VNOVAL
)
2988 VATTR_SET(&va
, va_gid
, uap
->gid
);
2990 /* preflight and authorize attribute changes */
2991 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
2993 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
2995 error
= vnode_setattr(vp
, &va
, ctx
);
2999 * EACCES is only allowed from namei(); permissions failure should
3000 * return EPERM, so we need to translate the error code.
3002 if (error
== EACCES
)
3010 chown(struct proc
*p
, register struct chown_args
*uap
, register_t
*retval
)
3012 struct vfs_context context
;
3014 context
.vc_proc
= p
;
3015 context
.vc_ucred
= kauth_cred_get();
3017 return chown1(&context
, uap
, retval
, 1);
3021 lchown(struct proc
*p
, register struct lchown_args
*uap
, register_t
*retval
)
3023 struct vfs_context context
;
3025 context
.vc_proc
= p
;
3026 context
.vc_ucred
= kauth_cred_get();
3028 /* Argument list identical, but machine generated; cast for chown1() */
3029 return chown1(&context
, (struct chown_args
*)uap
, retval
, 0);
3033 * Set ownership given a file descriptor.
3037 fchown(struct proc
*p
, register struct fchown_args
*uap
, __unused register_t
*retval
)
3039 struct vnode_attr va
;
3040 struct vfs_context context
;
3043 kauth_action_t action
;
3045 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
3046 AUDIT_ARG(fd
, uap
->fd
);
3048 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
3051 if ( (error
= vnode_getwithref(vp
)) ) {
3055 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3058 if (uap
->uid
!= VNOVAL
)
3059 VATTR_SET(&va
, va_uid
, uap
->uid
);
3060 if (uap
->gid
!= VNOVAL
)
3061 VATTR_SET(&va
, va_gid
, uap
->gid
);
3063 context
.vc_proc
= p
;
3064 context
.vc_ucred
= kauth_cred_get();
3066 /* preflight and authorize attribute changes */
3067 if ((error
= vnode_authattr(vp
, &va
, &action
, &context
)) != 0)
3069 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0)) {
3070 if (error
== EACCES
)
3074 error
= vnode_setattr(vp
, &va
, &context
);
3077 (void)vnode_put(vp
);
3083 getutimes(usrtvp
, tsp
)
3085 struct timespec
*tsp
;
3087 struct user_timeval tv
[2];
3090 if (usrtvp
== USER_ADDR_NULL
) {
3091 struct timeval old_tv
;
3092 /* XXX Y2038 bug because of microtime argument */
3094 TIMEVAL_TO_TIMESPEC(&old_tv
, &tsp
[0]);
3097 if (IS_64BIT_PROCESS(current_proc())) {
3098 error
= copyin(usrtvp
, (void *)tv
, sizeof(tv
));
3100 struct timeval old_tv
[2];
3101 error
= copyin(usrtvp
, (void *)old_tv
, sizeof(old_tv
));
3102 tv
[0].tv_sec
= old_tv
[0].tv_sec
;
3103 tv
[0].tv_usec
= old_tv
[0].tv_usec
;
3104 tv
[1].tv_sec
= old_tv
[1].tv_sec
;
3105 tv
[1].tv_usec
= old_tv
[1].tv_usec
;
3109 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
3110 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
3116 setutimes(vfs_context_t ctx
, struct vnode
*vp
, const struct timespec
*ts
,
3120 struct vnode_attr va
;
3121 kauth_action_t action
;
3123 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3126 VATTR_SET(&va
, va_access_time
, ts
[0]);
3127 VATTR_SET(&va
, va_modify_time
, ts
[1]);
3129 va
.va_vaflags
|= VA_UTIMES_NULL
;
3131 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
3133 /* since we may not need to auth anything, check here */
3134 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
3136 error
= vnode_setattr(vp
, &va
, ctx
);
3143 * Set the access and modification times of a file.
3147 utimes(struct proc
*p
, register struct utimes_args
*uap
, __unused register_t
*retval
)
3149 struct timespec ts
[2];
3152 struct nameidata nd
;
3153 struct vfs_context context
;
3155 context
.vc_proc
= p
;
3156 context
.vc_ucred
= kauth_cred_get();
3158 /* AUDIT: Needed to change the order of operations to do the
3159 * name lookup first because auditing wants the path.
3161 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3162 UIO_USERSPACE
, uap
->path
, &context
);
3169 * Fetch the user-supplied time. If usrtvp is USER_ADDR_NULL, we fetch
3170 * the current time instead.
3173 if ((error
= getutimes(usrtvp
, ts
)) != 0)
3176 error
= setutimes(&context
, nd
.ni_vp
, ts
, usrtvp
== USER_ADDR_NULL
);
3179 vnode_put(nd
.ni_vp
);
3184 * Set the access and modification times of a file.
3188 futimes(struct proc
*p
, register struct futimes_args
*uap
, __unused register_t
*retval
)
3190 struct timespec ts
[2];
3194 struct vfs_context context
;
3196 context
.vc_proc
= p
;
3197 context
.vc_ucred
= kauth_cred_get();
3199 AUDIT_ARG(fd
, uap
->fd
);
3201 if ((error
= getutimes(usrtvp
, ts
)) != 0)
3203 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
3205 if((error
= vnode_getwithref(vp
))) {
3210 error
= setutimes(&context
, vp
, ts
, usrtvp
== 0);
3217 * Truncate a file given its path name.
3221 truncate(struct proc
*p
, register struct truncate_args
*uap
, __unused register_t
*retval
)
3223 register struct vnode
*vp
;
3224 struct vnode_attr va
;
3225 struct vfs_context context
;
3227 struct nameidata nd
;
3228 kauth_action_t action
;
3230 context
.vc_proc
= p
;
3231 context
.vc_ucred
= kauth_cred_get();
3233 if (uap
->length
< 0)
3235 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3236 UIO_USERSPACE
, uap
->path
, &context
);
3237 if ((error
= namei(&nd
)))
3244 VATTR_SET(&va
, va_data_size
, uap
->length
);
3245 if ((error
= vnode_authattr(vp
, &va
, &action
, &context
)) != 0)
3247 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0))
3249 error
= vnode_setattr(vp
, &va
, &context
);
3256 * Truncate a file given a file descriptor.
3260 ftruncate(p
, uap
, retval
)
3262 register struct ftruncate_args
*uap
;
3265 struct vfs_context context
;
3266 struct vnode_attr va
;
3268 struct fileproc
*fp
;
3272 context
.vc_proc
= current_proc();
3273 context
.vc_ucred
= kauth_cred_get();
3275 AUDIT_ARG(fd
, uap
->fd
);
3276 if (uap
->length
< 0)
3279 if ( (error
= fp_lookup(p
,fd
,&fp
,0)) ) {
3283 if (fp
->f_fglob
->fg_type
== DTYPE_PSXSHM
) {
3284 error
= pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
);
3287 if (fp
->f_fglob
->fg_type
!= DTYPE_VNODE
) {
3292 vp
= (struct vnode
*)fp
->f_fglob
->fg_data
;
3294 if ((fp
->f_fglob
->fg_flag
& FWRITE
) == 0) {
3295 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
3300 if ((error
= vnode_getwithref(vp
)) != 0) {
3304 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3307 VATTR_SET(&va
, va_data_size
, uap
->length
);
3308 error
= vnode_setattr(vp
, &va
, &context
);
3309 (void)vnode_put(vp
);
3317 * Sync an open file.
3321 fsync(struct proc
*p
, struct fsync_args
*uap
, __unused register_t
*retval
)
3324 struct fileproc
*fp
;
3325 struct vfs_context context
;
3328 if ( (error
= fp_getfvp(p
, uap
->fd
, &fp
, &vp
)) )
3330 if ( (error
= vnode_getwithref(vp
)) ) {
3334 context
.vc_proc
= p
;
3335 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
3337 error
= VNOP_FSYNC(vp
, MNT_WAIT
, &context
);
3339 (void)vnode_put(vp
);
3345 * Duplicate files. Source must be a file, target must be a file or
3348 * XXX Copyfile authorisation checking is woefully inadequate, and will not
3349 * perform inheritance correctly.
3353 copyfile(struct proc
*p
, register struct copyfile_args
*uap
, __unused register_t
*retval
)
3355 vnode_t tvp
, fvp
, tdvp
, sdvp
;
3356 struct nameidata fromnd
, tond
;
3358 struct vfs_context context
;
3360 context
.vc_proc
= p
;
3361 context
.vc_ucred
= kauth_cred_get();
3363 /* Check that the flags are valid. */
3365 if (uap
->flags
& ~CPF_MASK
) {
3369 NDINIT(&fromnd
, LOOKUP
, SAVESTART
| AUDITVNPATH1
,
3370 UIO_USERSPACE
, uap
->from
, &context
);
3371 if ((error
= namei(&fromnd
)))
3375 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
| AUDITVNPATH2
,
3376 UIO_USERSPACE
, uap
->to
, &context
);
3377 if ((error
= namei(&tond
))) {
3384 if (!(uap
->flags
& CPF_OVERWRITE
)) {
3389 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
3394 if ((error
= vnode_authorize(tdvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
3400 * If source is the same as the destination (that is the
3401 * same inode number) then there is nothing to do.
3402 * (fixed to have POSIX semantics - CSM 3/2/98)
3407 error
= VNOP_COPYFILE(fvp
,tdvp
,tvp
,&tond
.ni_cnd
,uap
->mode
,uap
->flags
,&context
);
3409 sdvp
= tond
.ni_startdir
;
3411 * nameidone has to happen before we vnode_put(tdvp)
3412 * since it may need to release the fs_nodelock on the tdvp
3423 if (fromnd
.ni_startdir
)
3424 vnode_put(fromnd
.ni_startdir
);
3434 * Rename files. Source and destination must either both be directories,
3435 * or both not be directories. If target is a directory, it must be empty.
3439 rename(proc_t p
, register struct rename_args
*uap
, __unused register_t
*retval
)
3443 struct nameidata fromnd
, tond
;
3444 struct vfs_context context
;
3447 char *oname
, *from_name
, *to_name
;
3448 int from_len
, to_len
;
3449 int holding_mntlock
;
3450 mount_t locked_mp
= NULL
;
3452 fse_info from_finfo
, to_finfo
;
3454 context
.vc_proc
= p
;
3455 context
.vc_ucred
= kauth_cred_get();
3456 holding_mntlock
= 0;
3462 NDINIT(&fromnd
, DELETE
, WANTPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->from
, &context
);
3464 if ( (error
= namei(&fromnd
)) )
3466 fdvp
= fromnd
.ni_dvp
;
3469 NDINIT(&tond
, RENAME
, WANTPARENT
| AUDITVNPATH2
, UIO_USERSPACE
, uap
->to
, &context
);
3470 if (fvp
->v_type
== VDIR
)
3471 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
3473 if ( (error
= namei(&tond
)) ) {
3475 * Translate error code for rename("dir1", "dir2/.").
3477 if (error
== EISDIR
&& fvp
->v_type
== VDIR
)
3485 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
3488 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
3501 * If tvp is a directory and not the same as fdvp, or tdvp is not the same as fdvp,
3502 * the node is moving between directories and we need rights to remove from the
3503 * old and add to the new.
3505 * If tvp already exists and is not a directory, we need to be allowed to delete it.
3507 * Note that we do not inherit when renaming. XXX this needs to be revisited to
3508 * implement the deferred-inherit bit.
3514 if ((tvp
!= NULL
) && vnode_isdir(tvp
)) {
3517 } else if (tdvp
!= fdvp
) {
3521 * must have delete rights to remove the old name even in the simple case of
3524 if ((error
= vnode_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
, &context
)) != 0)
3527 /* moving into tdvp or tvp, must have rights to add */
3528 if ((error
= vnode_authorize(((tvp
!= NULL
) && vnode_isdir(tvp
)) ? tvp
: tdvp
,
3530 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
3534 /* node staying in same directory, must be allowed to add new name */
3535 if ((error
= vnode_authorize(fdvp
, NULL
,
3536 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
3539 /* overwriting tvp */
3540 if ((tvp
!= NULL
) && !vnode_isdir(tvp
) &&
3541 ((error
= vnode_authorize(tvp
, tdvp
, KAUTH_VNODE_DELETE
, &context
)) != 0))
3544 /* XXX more checks? */
3547 /* authorization denied */
3552 * Allow the renaming of mount points.
3553 * - target must not exist
3554 * - target must reside in the same directory as source
3555 * - union mounts cannot be renamed
3556 * - "/" cannot be renamed
3558 if ((fvp
->v_flag
& VROOT
) &&
3559 (fvp
->v_type
== VDIR
) &&
3561 (fvp
->v_mountedhere
== NULL
) &&
3563 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
3564 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
3565 struct vnode
*coveredvp
;
3567 /* switch fvp to the covered vnode */
3568 coveredvp
= fvp
->v_mount
->mnt_vnodecovered
;
3569 if ( (vnode_getwithref(coveredvp
)) ) {
3579 * Check for cross-device rename.
3581 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
3582 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
3587 * Avoid renaming "." and "..".
3589 if (fvp
->v_type
== VDIR
&&
3591 (fromnd
.ni_cnd
.cn_namelen
== 1 && fromnd
.ni_cnd
.cn_nameptr
[0] == '.') ||
3592 ((fromnd
.ni_cnd
.cn_flags
| tond
.ni_cnd
.cn_flags
) & ISDOTDOT
)) ) {
3597 * The following edge case is caught here:
3598 * (to cannot be a descendent of from)
3611 if (tdvp
->v_parent
== fvp
) {
3617 * If source is the same as the destination (that is the
3618 * same inode number) then there is nothing to do...
3619 * EXCEPT if the underlying file system supports case
3620 * insensitivity and is case preserving. In this case
3621 * the file system needs to handle the special case of
3622 * getting the same vnode as target (fvp) and source (tvp).
3624 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
3625 * and _PC_CASE_PRESERVING can have this exception, and they need to
3626 * handle the special case of getting the same vnode as target and
3627 * source. NOTE: Then the target is unlocked going into vnop_rename,
3628 * so not to cause locking problems. There is a single reference on tvp.
3630 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
3631 * that correct behaviour then is just to remove the source (link)
3633 if (fvp
== tvp
&& fdvp
== tdvp
) {
3634 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
3635 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
3636 fromnd
.ni_cnd
.cn_namelen
)) {
3641 if (holding_mntlock
&& fvp
->v_mount
!= locked_mp
) {
3643 * we're holding a reference and lock
3644 * on locked_mp, but it no longer matches
3645 * what we want to do... so drop our hold
3647 mount_unlock_renames(locked_mp
);
3648 mount_drop(locked_mp
, 0);
3649 holding_mntlock
= 0;
3651 if (tdvp
!= fdvp
&& fvp
->v_type
== VDIR
) {
3653 * serialize renames that re-shape
3654 * the tree... if holding_mntlock is
3655 * set, then we're ready to go...
3657 * first need to drop the iocounts
3658 * we picked up, second take the
3659 * lock to serialize the access,
3660 * then finally start the lookup
3661 * process over with the lock held
3663 if (!holding_mntlock
) {
3665 * need to grab a reference on
3666 * the mount point before we
3667 * drop all the iocounts... once
3668 * the iocounts are gone, the mount
3671 locked_mp
= fvp
->v_mount
;
3672 mount_ref(locked_mp
, 0);
3675 * nameidone has to happen before we vnode_put(tvp)
3676 * since it may need to release the fs_nodelock on the tvp
3685 * nameidone has to happen before we vnode_put(fdvp)
3686 * since it may need to release the fs_nodelock on the fvp
3693 mount_lock_renames(locked_mp
);
3694 holding_mntlock
= 1;
3700 * when we dropped the iocounts to take
3701 * the lock, we allowed the identity of
3702 * the various vnodes to change... if they did,
3703 * we may no longer be dealing with a rename
3704 * that reshapes the tree... once we're holding
3705 * the iocounts, the vnodes can't change type
3706 * so we're free to drop the lock at this point
3709 if (holding_mntlock
) {
3710 mount_unlock_renames(locked_mp
);
3711 mount_drop(locked_mp
, 0);
3712 holding_mntlock
= 0;
3715 // save these off so we can later verify that fvp is the same
3716 oname
= fvp
->v_name
;
3717 oparent
= fvp
->v_parent
;
3719 if (need_fsevent(FSE_RENAME
, fvp
)) {
3720 get_fse_info(fvp
, &from_finfo
, &context
);
3723 get_fse_info(tvp
, &to_finfo
, &context
);
3725 from_name
= get_pathbuff();
3726 from_len
= MAXPATHLEN
;
3727 vn_getpath(fvp
, from_name
, &from_len
);
3729 to_name
= get_pathbuff();
3730 to_len
= MAXPATHLEN
;
3732 if (tvp
&& tvp
->v_type
!= VDIR
) {
3733 vn_getpath(tvp
, to_name
, &to_len
);
3735 vn_getpath(tdvp
, to_name
, &to_len
);
3736 // if the path is not just "/", then append a "/"
3738 to_name
[to_len
-1] = '/';
3742 strcpy(&to_name
[to_len
], tond
.ni_cnd
.cn_nameptr
);
3743 to_len
+= tond
.ni_cnd
.cn_namelen
+ 1;
3744 to_name
[to_len
] = '\0';
3750 error
= VNOP_RENAME(fdvp
, fvp
, &fromnd
.ni_cnd
,
3751 tdvp
, tvp
, &tond
.ni_cnd
,
3754 if (holding_mntlock
) {
3756 * we can drop our serialization
3759 mount_unlock_renames(locked_mp
);
3760 mount_drop(locked_mp
, 0);
3761 holding_mntlock
= 0;
3764 if (to_name
!= NULL
)
3765 release_pathbuff(to_name
);
3766 if (from_name
!= NULL
)
3767 release_pathbuff(from_name
);
3768 from_name
= to_name
= NULL
;
3773 /* call out to allow 3rd party notification of rename.
3774 * Ignore result of kauth_authorize_fileop call.
3776 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_RENAME
,
3777 (uintptr_t)from_name
, (uintptr_t)to_name
);
3779 if (from_name
!= NULL
&& to_name
!= NULL
) {
3781 add_fsevent(FSE_RENAME
, &context
,
3782 FSE_ARG_STRING
, from_len
, from_name
,
3783 FSE_ARG_FINFO
, &from_finfo
,
3784 FSE_ARG_STRING
, to_len
, to_name
,
3785 FSE_ARG_FINFO
, &to_finfo
,
3788 add_fsevent(FSE_RENAME
, &context
,
3789 FSE_ARG_STRING
, from_len
, from_name
,
3790 FSE_ARG_FINFO
, &from_finfo
,
3791 FSE_ARG_STRING
, to_len
, to_name
,
3795 if (to_name
!= NULL
)
3796 release_pathbuff(to_name
);
3797 if (from_name
!= NULL
)
3798 release_pathbuff(from_name
);
3799 from_name
= to_name
= NULL
;
3802 * update filesystem's mount point data
3805 char *cp
, *pathend
, *mpname
;
3811 mp
= fvp
->v_mountedhere
;
3813 if (vfs_busy(mp
, LK_NOWAIT
)) {
3817 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
3819 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
3821 /* find current mount point prefix */
3822 pathend
= &mp
->mnt_vfsstat
.f_mntonname
[0];
3823 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
3827 /* find last component of target name */
3828 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
3832 /* append name to prefix */
3833 maxlen
= MAXPATHLEN
- (pathend
- mp
->mnt_vfsstat
.f_mntonname
);
3834 bzero(pathend
, maxlen
);
3835 strncpy(pathend
, mpname
, maxlen
- 1);
3837 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
3842 * fix up name & parent pointers. note that we first
3843 * check that fvp has the same name/parent pointers it
3844 * had before the rename call... this is a 'weak' check
3847 if (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
) {
3850 update_flags
= VNODE_UPDATE_NAME
;
3853 update_flags
|= VNODE_UPDATE_PARENT
;
3855 vnode_update_identity(fvp
, tdvp
, tond
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_namelen
, tond
.ni_cnd
.cn_hash
, update_flags
);
3858 if (holding_mntlock
) {
3859 mount_unlock_renames(locked_mp
);
3860 mount_drop(locked_mp
, 0);
3864 * nameidone has to happen before we vnode_put(tdvp)
3865 * since it may need to release the fs_nodelock on the tdvp
3875 * nameidone has to happen before we vnode_put(fdvp)
3876 * since it may need to release the fs_nodelock on the fdvp
3888 * Make a directory file.
3892 mkdir1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
3896 int update_flags
= 0;
3897 struct nameidata nd
;
3899 AUDIT_ARG(mode
, vap
->va_mode
);
3900 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
3901 UIO_USERSPACE
, path
, ctx
);
3902 nd
.ni_cnd
.cn_flags
|= WILLBEDIR
;
3914 /* authorize addition of a directory to the parent */
3915 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
)) != 0)
3918 VATTR_SET(vap
, va_type
, VDIR
);
3920 /* make the directory */
3921 if ((error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
)) != 0)
3924 // Make sure the name & parent pointers are hooked up
3925 if (vp
->v_name
== NULL
)
3926 update_flags
|= VNODE_UPDATE_NAME
;
3927 if (vp
->v_parent
== NULLVP
)
3928 update_flags
|= VNODE_UPDATE_PARENT
;
3931 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
3933 add_fsevent(FSE_CREATE_DIR
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
3937 * nameidone has to happen before we vnode_put(dvp)
3938 * since it may need to release the fs_nodelock on the dvp
3951 mkdir_extended(struct proc
*p
, register struct mkdir_extended_args
*uap
, __unused register_t
*retval
)
3953 struct vfs_context context
;
3955 kauth_filesec_t xsecdst
;
3956 struct vnode_attr va
;
3959 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
3960 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
3963 context
.vc_proc
= p
;
3964 context
.vc_ucred
= kauth_cred_get();
3967 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
3968 if (xsecdst
!= NULL
)
3969 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
3971 ciferror
= mkdir1(&context
, uap
->path
, &va
);
3972 if (xsecdst
!= NULL
)
3973 kauth_filesec_free(xsecdst
);
3978 mkdir(struct proc
*p
, register struct mkdir_args
*uap
, __unused register_t
*retval
)
3980 struct vfs_context context
;
3981 struct vnode_attr va
;
3983 context
.vc_proc
= p
;
3984 context
.vc_ucred
= kauth_cred_get();
3987 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
3989 return(mkdir1(&context
, uap
->path
, &va
));
3993 * Remove a directory file.
3997 rmdir(struct proc
*p
, struct rmdir_args
*uap
, __unused register_t
*retval
)
4001 struct nameidata nd
;
4002 struct vfs_context context
;
4004 context
.vc_proc
= p
;
4005 context
.vc_ucred
= kauth_cred_get();
4007 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
4008 UIO_USERSPACE
, uap
->path
, &context
);
4015 if (vp
->v_type
!= VDIR
) {
4017 * rmdir only deals with directories
4020 } else if (dvp
== vp
) {
4022 * No rmdir "." please.
4025 } else if (vp
->v_flag
& VROOT
) {
4027 * The root of a mounted filesystem cannot be deleted.
4031 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, &context
);
4038 if (need_fsevent(FSE_DELETE
, dvp
)) {
4039 path
= get_pathbuff();
4041 vn_getpath(vp
, path
, &len
);
4042 get_fse_info(vp
, &finfo
, &context
);
4044 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, &context
);
4046 if (!error
&& path
!= NULL
) {
4047 add_fsevent(FSE_DELETE
, &context
,
4048 FSE_ARG_STRING
, len
, path
,
4049 FSE_ARG_FINFO
, &finfo
,
4053 release_pathbuff(path
);
4056 * nameidone has to happen before we vnode_put(dvp)
4057 * since it may need to release the fs_nodelock on the dvp
4069 * Read a block of directory entries in a file system independent format.
4072 getdirentries(p
, uap
, retval
)
4074 register struct getdirentries_args
*uap
;
4078 struct vfs_context context
;
4079 struct fileproc
*fp
;
4081 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4085 char uio_buf
[ UIO_SIZEOF(1) ];
4087 AUDIT_ARG(fd
, uap
->fd
);
4088 error
= fp_getfvp(p
, fd
, &fp
, &vp
);
4092 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
4093 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4097 if ( (error
= vnode_getwithref(vp
)) ) {
4101 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4104 if (vp
->v_type
!= VDIR
) {
4105 (void)vnode_put(vp
);
4109 context
.vc_proc
= p
;
4110 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
4112 loff
= fp
->f_fglob
->fg_offset
;
4113 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
4114 &uio_buf
[0], sizeof(uio_buf
));
4115 uio_addiov(auio
, uap
->buf
, uap
->count
);
4117 error
= VNOP_READDIR(vp
, auio
, 0, &eofflag
, (int *)NULL
, &context
);
4118 fp
->f_fglob
->fg_offset
= uio_offset(auio
);
4120 (void)vnode_put(vp
);
4126 if ((uap
->count
== uio_resid(auio
)) &&
4127 (vp
->v_op
== union_vnodeop_p
)) {
4130 lvp
= union_dircache(vp
, p
);
4131 if (lvp
!= NULLVP
) {
4132 struct vnode_attr va
;
4134 * If the directory is opaque,
4135 * then don't show lower entries
4138 VATTR_WANTED(&va
, va_flags
);
4139 error
= vnode_getattr(vp
, &va
, &context
);
4140 if (va
.va_flags
& OPAQUE
) {
4146 if (lvp
!= NULLVP
) {
4147 error
= VNOP_OPEN(lvp
, FREAD
, &context
);
4153 fp
->f_fglob
->fg_data
= (caddr_t
) lvp
;
4154 fp
->f_fglob
->fg_offset
= 0;
4155 error
= VNOP_CLOSE(vp
, FREAD
, &context
);
4167 if (((user_ssize_t
)uap
->count
== uio_resid(auio
)) &&
4168 (vp
->v_flag
& VROOT
) &&
4169 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
4170 struct vnode
*tvp
= vp
;
4171 vp
= vp
->v_mount
->mnt_vnodecovered
;
4172 vnode_getwithref(vp
);
4174 fp
->f_fglob
->fg_data
= (caddr_t
) vp
;
4175 fp
->f_fglob
->fg_offset
= 0;
4181 error
= copyout((caddr_t
)&loff
, uap
->basep
, sizeof(long));
4182 // LP64todo - fix this
4183 *retval
= uap
->count
- uio_resid(auio
);
4190 * Set the mode mask for creation of filesystem nodes.
4192 #warning XXX implement xsecurity
4194 #define UMASK_NOXSECURITY (void *)1 /* leave existing xsecurity alone */
4196 umask1(struct proc
*p
, int newmask
, __unused kauth_filesec_t fsec
, register_t
*retval
)
4198 register struct filedesc
*fdp
;
4200 AUDIT_ARG(mask
, newmask
);
4202 *retval
= fdp
->fd_cmask
;
4203 fdp
->fd_cmask
= newmask
& ALLPERMS
;
4209 umask_extended(struct proc
*p
, struct umask_extended_args
*uap
, register_t
*retval
)
4212 kauth_filesec_t xsecdst
;
4214 xsecdst
= KAUTH_FILESEC_NONE
;
4215 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
4216 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
4219 xsecdst
= KAUTH_FILESEC_NONE
;
4222 ciferror
= umask1(p
, uap
->newmask
, xsecdst
, retval
);
4224 if (xsecdst
!= KAUTH_FILESEC_NONE
)
4225 kauth_filesec_free(xsecdst
);
4230 umask(struct proc
*p
, struct umask_args
*uap
, register_t
*retval
)
4232 return(umask1(p
, uap
->newmask
, UMASK_NOXSECURITY
, retval
));
4236 * Void all references to file by ripping underlying filesystem
4241 revoke(struct proc
*p
, register struct revoke_args
*uap
, __unused register_t
*retval
)
4243 register struct vnode
*vp
;
4244 struct vnode_attr va
;
4245 struct vfs_context context
;
4247 struct nameidata nd
;
4249 context
.vc_proc
= p
;
4250 context
.vc_ucred
= kauth_cred_get();
4252 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4253 UIO_USERSPACE
, uap
->path
, &context
);
4262 VATTR_WANTED(&va
, va_uid
);
4263 if ((error
= vnode_getattr(vp
, &va
, &context
)))
4265 if (kauth_cred_getuid(context
.vc_ucred
) != va
.va_uid
&&
4266 (error
= suser(context
.vc_ucred
, &p
->p_acflag
)))
4268 if (vp
->v_usecount
> 1 || (vp
->v_flag
& VALIASED
))
4269 VNOP_REVOKE(vp
, REVOKEALL
, &context
);
4277 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
4278 * The following system calls are designed to support features
4279 * which are specific to the HFS & HFS Plus volume formats
4282 #ifdef __APPLE_API_OBSOLETE
4284 /************************************************/
4285 /* *** Following calls will be deleted soon *** */
4286 /************************************************/
4289 * Make a complex file. A complex file is one with multiple forks (data streams)
4293 mkcomplex(__unused
struct proc
*p
, __unused
struct mkcomplex_args
*uap
, __unused register_t
*retval
)
4299 * Extended stat call which returns volumeid and vnodeid as well as other info
4303 statv(__unused
struct proc
*p
,
4304 __unused
struct statv_args
*uap
,
4305 __unused register_t
*retval
)
4307 return (ENOTSUP
); /* We'll just return an error for now */
4309 } /* end of statv system call */
4312 * Extended lstat call which returns volumeid and vnodeid as well as other info
4316 lstatv(__unused
struct proc
*p
,
4317 __unused
struct lstatv_args
*uap
,
4318 __unused register_t
*retval
)
4320 return (ENOTSUP
); /* We'll just return an error for now */
4321 } /* end of lstatv system call */
4324 * Extended fstat call which returns volumeid and vnodeid as well as other info
4328 fstatv(__unused
struct proc
*p
,
4329 __unused
struct fstatv_args
*uap
,
4330 __unused register_t
*retval
)
4332 return (ENOTSUP
); /* We'll just return an error for now */
4333 } /* end of fstatv system call */
4336 /************************************************/
4337 /* *** Preceding calls will be deleted soon *** */
4338 /************************************************/
4340 #endif /* __APPLE_API_OBSOLETE */
4343 * Obtain attribute information on objects in a directory while enumerating
4344 * the directory. This call does not yet support union mounted directories.
4346 * 1.union mounted directories.
4351 getdirentriesattr (struct proc
*p
, struct getdirentriesattr_args
*uap
, register_t
*retval
)
4354 struct fileproc
*fp
;
4356 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4357 uint64_t actualcount
;
4362 struct attrlist attributelist
;
4363 struct vfs_context context
;
4365 char uio_buf
[ UIO_SIZEOF(1) ];
4366 kauth_action_t action
;
4370 /* Get the attributes into kernel space */
4371 if ((error
= copyin(uap
->alist
, (caddr_t
) &attributelist
, sizeof (attributelist
))))
4373 actualcount
= fuulong(uap
->count
);
4374 if (actualcount
== -1ULL)
4377 if ( (error
= fp_getfvp(p
, fd
, &fp
, &vp
)) )
4380 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
4381 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4385 if ( (error
= vnode_getwithref(vp
)) )
4388 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4390 if (vp
->v_type
!= VDIR
) {
4391 (void)vnode_put(vp
);
4396 /* set up the uio structure which will contain the users return buffer */
4397 loff
= fp
->f_fglob
->fg_offset
;
4398 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
4399 &uio_buf
[0], sizeof(uio_buf
));
4400 uio_addiov(auio
, uap
->buffer
, uap
->buffersize
);
4402 context
.vc_proc
= p
;
4403 context
.vc_ucred
= kauth_cred_get();
4404 tmpcount
= (u_long
) actualcount
;
4407 * If the only item requested is file names, we can let that past with
4408 * just LIST_DIRECTORY. If they want any other attributes, that means
4409 * they need SEARCH as well.
4411 action
= KAUTH_VNODE_LIST_DIRECTORY
;
4412 if ((attributelist
.commonattr
& ~ATTR_CMN_NAME
) ||
4413 attributelist
.fileattr
|| attributelist
.dirattr
)
4414 action
|= KAUTH_VNODE_SEARCH
;
4416 if ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) == 0)
4417 error
= VNOP_READDIRATTR(vp
, &attributelist
, auio
,
4418 tmpcount
, uap
->options
, &newstate
, &eofflag
,
4419 &tmpcount
, &context
);
4420 (void)vnode_put(vp
);
4421 actualcount
= tmpcount
;
4425 fp
->f_fglob
->fg_offset
= uio_offset(auio
); /* should be multiple of dirent, not variable */
4427 if ((error
= suulong(uap
->count
, actualcount
)) != 0)
4429 if ((error
= suulong(uap
->newstate
, (uint64_t)newstate
)) != 0)
4431 if ((error
= suulong(uap
->basep
, (uint64_t)loff
)) != 0)
4434 *retval
= eofflag
; /* similar to getdirentries */
4438 return (error
); /* return error earlier, an retval of 0 or 1 now */
4440 } /* end of getdirentryattr system call */
4443 * Exchange data between two files
4448 exchangedata (struct proc
*p
, register struct exchangedata_args
*uap
, __unused register_t
*retval
)
4451 struct nameidata fnd
, snd
;
4452 struct vfs_context context
;
4453 struct vnode
*fvp
, *svp
;
4459 fse_info f_finfo
, s_finfo
;
4461 context
.vc_proc
= p
;
4462 context
.vc_ucred
= kauth_cred_get();
4465 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4467 NDINIT(&fnd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4468 UIO_USERSPACE
, uap
->path1
, &context
);
4470 error
= namei(&fnd
);
4477 NDINIT(&snd
, LOOKUP
, nameiflags
| AUDITVNPATH2
,
4478 UIO_USERSPACE
, uap
->path2
, &context
);
4480 error
= namei(&snd
);
4489 * if the files are the same, return an inval error
4497 * if the files are on different volumes, return an error
4499 if (svp
->v_mount
!= fvp
->v_mount
) {
4503 if (((error
= vnode_authorize(fvp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0) ||
4504 ((error
= vnode_authorize(svp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0))
4507 if (need_fsevent(FSE_EXCHANGE
, fvp
) || kauth_authorize_fileop_has_listeners()) {
4508 fpath
= get_pathbuff();
4509 spath
= get_pathbuff();
4512 if (vn_getpath(fvp
, fpath
, &flen
) != 0 || fpath
[0] == '\0') {
4513 printf("exchange: vn_getpath(fvp=0x%x) failed <<%s>>\n",
4516 if (vn_getpath(svp
, spath
, &slen
) != 0 || spath
[0] == '\0') {
4517 printf("exchange: vn_getpath(svp=0x%x) failed <<%s>>\n",
4520 get_fse_info(fvp
, &f_finfo
, &context
);
4521 get_fse_info(svp
, &s_finfo
, &context
);
4523 /* Ok, make the call */
4524 error
= VNOP_EXCHANGE(fvp
, svp
, 0, &context
);
4529 if (fpath
!= NULL
&& spath
!= NULL
) {
4530 /* call out to allow 3rd party notification of exchangedata.
4531 * Ignore result of kauth_authorize_fileop call.
4533 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_EXCHANGE
,
4534 (uintptr_t)fpath
, (uintptr_t)spath
);
4538 tmpname
= fvp
->v_name
;
4539 fvp
->v_name
= svp
->v_name
;
4540 svp
->v_name
= tmpname
;
4542 if (fvp
->v_parent
!= svp
->v_parent
) {
4545 tmp
= fvp
->v_parent
;
4546 fvp
->v_parent
= svp
->v_parent
;
4547 svp
->v_parent
= tmp
;
4549 name_cache_unlock();
4551 if (fpath
!= NULL
&& spath
!= NULL
) {
4552 add_fsevent(FSE_EXCHANGE
, &context
,
4553 FSE_ARG_STRING
, flen
, fpath
,
4554 FSE_ARG_FINFO
, &f_finfo
,
4555 FSE_ARG_STRING
, slen
, spath
,
4556 FSE_ARG_FINFO
, &s_finfo
,
4561 release_pathbuff(spath
);
4563 release_pathbuff(fpath
);
4573 #ifdef __APPLE_API_OBSOLETE
4575 /************************************************/
4576 /* *** Following calls will be deleted soon *** */
4577 /************************************************/
4580 * Check users access to a file
4584 #warning "checkuseraccess copies a cred in from user space but"
4585 #warning "user space has no way of knowing what one looks like"
4586 #warning "this code should use the access_extended spoof-as functionality"
4588 checkuseraccess (struct proc
*p
, register struct checkuseraccess_args
*uap
, __unused register_t
*retval
)
4590 register struct vnode
*vp
;
4592 struct nameidata nd
;
4593 struct ucred cred
; /* XXX ILLEGAL */
4594 int flags
; /*what will actually get passed to access*/
4596 struct vfs_context context
;
4598 /* Make sure that the number of groups is correct before we do anything */
4600 if ((uap
->ngroups
<= 0) || (uap
->ngroups
> NGROUPS
))
4603 /* Verify that the caller is root */
4605 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
4608 /* Fill in the credential structure */
4611 cred
.cr_uid
= uap
->userid
;
4612 cred
.cr_ngroups
= uap
->ngroups
;
4613 if ((error
= copyin(CAST_USER_ADDR_T(uap
->groups
), (caddr_t
) &(cred
.cr_groups
), (sizeof(gid_t
))*uap
->ngroups
)))
4616 context
.vc_proc
= p
;
4617 context
.vc_ucred
= &cred
;
4619 /* Get our hands on the file */
4621 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4622 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4623 UIO_USERSPACE
, CAST_USER_ADDR_T(uap
->path
), &context
);
4625 if ((error
= namei(&nd
)))
4630 /* Flags == 0 means only check for existence. */
4634 if (uap
->accessrequired
) {
4635 if (uap
->accessrequired
& R_OK
)
4636 flags
|= KAUTH_VNODE_READ_DATA
;
4637 if (uap
->accessrequired
& W_OK
)
4638 flags
|= KAUTH_VNODE_WRITE_DATA
;
4639 if (uap
->accessrequired
& X_OK
)
4640 flags
|= KAUTH_VNODE_EXECUTE
;
4642 error
= vnode_authorize(vp
, NULL
, flags
, &context
);
4651 } /* end of checkuseraccess system call */
4653 /************************************************/
4654 /* *** Preceding calls will be deleted soon *** */
4655 /************************************************/
4657 #endif /* __APPLE_API_OBSOLETE */
4664 searchfs (struct proc
*p
, register struct searchfs_args
*uap
, __unused register_t
*retval
)
4666 register struct vnode
*vp
;
4669 struct nameidata nd
;
4670 struct user_fssearchblock searchblock
;
4671 struct searchstate
*state
;
4672 struct attrlist
*returnattrs
;
4673 void *searchparams1
,*searchparams2
;
4675 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4679 struct vfs_context context
;
4680 char uio_buf
[ UIO_SIZEOF(1) ];
4682 context
.vc_proc
= p
;
4683 context
.vc_ucred
= kauth_cred_get();
4685 /* Start by copying in fsearchblock paramater list */
4686 if (IS_64BIT_PROCESS(p
)) {
4687 error
= copyin(uap
->searchblock
, (caddr_t
) &searchblock
, sizeof(searchblock
));
4690 struct fssearchblock tmp_searchblock
;
4691 error
= copyin(uap
->searchblock
, (caddr_t
) &tmp_searchblock
, sizeof(tmp_searchblock
));
4692 // munge into 64-bit version
4693 searchblock
.returnattrs
= CAST_USER_ADDR_T(tmp_searchblock
.returnattrs
);
4694 searchblock
.returnbuffer
= CAST_USER_ADDR_T(tmp_searchblock
.returnbuffer
);
4695 searchblock
.returnbuffersize
= tmp_searchblock
.returnbuffersize
;
4696 searchblock
.maxmatches
= tmp_searchblock
.maxmatches
;
4697 searchblock
.timelimit
= tmp_searchblock
.timelimit
;
4698 searchblock
.searchparams1
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams1
);
4699 searchblock
.sizeofsearchparams1
= tmp_searchblock
.sizeofsearchparams1
;
4700 searchblock
.searchparams2
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams2
);
4701 searchblock
.sizeofsearchparams2
= tmp_searchblock
.sizeofsearchparams2
;
4702 searchblock
.searchattrs
= tmp_searchblock
.searchattrs
;
4707 /* Do a sanity check on sizeofsearchparams1 and sizeofsearchparams2.
4709 if (searchblock
.sizeofsearchparams1
> SEARCHFS_MAX_SEARCHPARMS
||
4710 searchblock
.sizeofsearchparams2
> SEARCHFS_MAX_SEARCHPARMS
)
4713 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
4714 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
4715 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
4718 mallocsize
= searchblock
.sizeofsearchparams1
+ searchblock
.sizeofsearchparams2
+
4719 sizeof(struct attrlist
) + sizeof(struct searchstate
);
4721 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
4723 /* Now set up the various pointers to the correct place in our newly allocated memory */
4725 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
4726 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
4727 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
4729 /* Now copy in the stuff given our local variables. */
4731 if ((error
= copyin(searchblock
.searchparams1
, searchparams1
, searchblock
.sizeofsearchparams1
)))
4734 if ((error
= copyin(searchblock
.searchparams2
, searchparams2
, searchblock
.sizeofsearchparams2
)))
4737 if ((error
= copyin(searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
))))
4740 if ((error
= copyin(uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
))))
4743 /* set up the uio structure which will contain the users return buffer */
4745 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
4746 &uio_buf
[0], sizeof(uio_buf
));
4747 uio_addiov(auio
, searchblock
.returnbuffer
, searchblock
.returnbuffersize
);
4750 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4751 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4752 UIO_USERSPACE
, uap
->path
, &context
);
4763 * If searchblock.maxmatches == 0, then skip the search. This has happened
4764 * before and sometimes the underlyning code doesnt deal with it well.
4766 if (searchblock
.maxmatches
== 0) {
4772 Allright, we have everything we need, so lets make that call.
4774 We keep special track of the return value from the file system:
4775 EAGAIN is an acceptable error condition that shouldn't keep us
4776 from copying out any results...
4779 fserror
= VNOP_SEARCHFS(vp
,
4782 &searchblock
.searchattrs
,
4783 searchblock
.maxmatches
,
4784 &searchblock
.timelimit
,
4797 /* Now copy out the stuff that needs copying out. That means the number of matches, the
4798 search state. Everything was already put into he return buffer by the vop call. */
4800 if ((error
= copyout((caddr_t
) state
, uap
->state
, sizeof(struct searchstate
))) != 0)
4803 if ((error
= suulong(uap
->nummatches
, (uint64_t)nummatches
)) != 0)
4810 FREE(searchparams1
,M_TEMP
);
4815 } /* end of searchfs system call */
4819 * Make a filesystem-specific control call:
4823 fsctl (struct proc
*p
, struct fsctl_args
*uap
, __unused register_t
*retval
)
4827 struct nameidata nd
;
4829 u_long cmd
= uap
->cmd
;
4830 register u_int size
;
4831 #define STK_PARAMS 128
4832 char stkbuf
[STK_PARAMS
];
4834 struct vfs_context context
;
4836 context
.vc_proc
= p
;
4837 context
.vc_ucred
= kauth_cred_get();
4839 size
= IOCPARM_LEN(cmd
);
4840 if (size
> IOCPARM_MAX
) return (EINVAL
);
4842 is64bit
= proc_is64bit(p
);
4845 if (size
> sizeof (stkbuf
)) {
4846 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
4854 error
= copyin(uap
->data
, data
, size
);
4855 if (error
) goto FSCtl_Exit
;
4858 *(user_addr_t
*)data
= uap
->data
;
4861 *(uint32_t *)data
= (uint32_t)uap
->data
;
4864 } else if ((cmd
& IOC_OUT
) && size
) {
4866 * Zero the buffer so the user always
4867 * gets back something deterministic.
4870 } else if (cmd
& IOC_VOID
) {
4872 *(user_addr_t
*)data
= uap
->data
;
4875 *(uint32_t *)data
= (uint32_t)uap
->data
;
4879 /* Get the vnode for the file we are getting info on: */
4881 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4882 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, uap
->path
, &context
);
4883 if ((error
= namei(&nd
))) goto FSCtl_Exit
;
4885 /* Invoke the filesystem-specific code */
4886 error
= VNOP_IOCTL(nd
.ni_vp
, IOCBASECMD(cmd
), data
, uap
->options
, &context
);
4888 vnode_put(nd
.ni_vp
);
4892 * Copy any data to user, size was
4893 * already set and checked above.
4895 if (error
== 0 && (cmd
& IOC_OUT
) && size
)
4896 error
= copyout(data
, uap
->data
, size
);
4899 if (memp
) kfree(memp
, size
);
4903 /* end of fsctl system call */
4906 * An in-kernel sync for power management to call.
4908 __private_extern__
int
4913 struct sync_args data
;
4918 error
= sync(current_proc(), &data
, &retval
[0]);
4922 } /* end of sync_internal call */
4926 * Retrieve the data of an extended attribute.
4929 getxattr(struct proc
*p
, struct getxattr_args
*uap
, user_ssize_t
*retval
)
4932 struct nameidata nd
;
4933 char attrname
[XATTR_MAXNAMELEN
+1];
4934 struct vfs_context context
;
4936 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4937 size_t attrsize
= 0;
4941 char uio_buf
[ UIO_SIZEOF(1) ];
4943 context
.vc_proc
= p
;
4944 context
.vc_ucred
= kauth_cred_get();
4946 if (uap
->options
& XATTR_NOSECURITY
)
4949 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
4950 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
4951 if ((error
= namei(&nd
))) {
4957 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
4960 if (xattr_protected(attrname
)) {
4964 if (uap
->value
&& uap
->size
> 0) {
4965 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
4966 &uio_buf
[0], sizeof(uio_buf
));
4967 uio_addiov(auio
, uap
->value
, uap
->size
);
4970 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, &context
);
4975 *retval
= uap
->size
- uio_resid(auio
);
4977 *retval
= (user_ssize_t
)attrsize
;
4984 * Retrieve the data of an extended attribute.
4987 fgetxattr(struct proc
*p
, struct fgetxattr_args
*uap
, user_ssize_t
*retval
)
4990 char attrname
[XATTR_MAXNAMELEN
+1];
4991 struct vfs_context context
;
4993 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4994 size_t attrsize
= 0;
4997 char uio_buf
[ UIO_SIZEOF(1) ];
4999 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5002 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5005 if ( (error
= vnode_getwithref(vp
)) ) {
5009 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5012 if (xattr_protected(attrname
)) {
5016 if (uap
->value
&& uap
->size
> 0) {
5017 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
5018 &uio_buf
[0], sizeof(uio_buf
));
5019 uio_addiov(auio
, uap
->value
, uap
->size
);
5021 context
.vc_proc
= p
;
5022 context
.vc_ucred
= kauth_cred_get();
5024 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, &context
);
5026 (void)vnode_put(vp
);
5030 *retval
= uap
->size
- uio_resid(auio
);
5032 *retval
= (user_ssize_t
)attrsize
;
5038 * Set the data of an extended attribute.
5041 setxattr(struct proc
*p
, struct setxattr_args
*uap
, int *retval
)
5044 struct nameidata nd
;
5045 char attrname
[XATTR_MAXNAMELEN
+1];
5046 struct vfs_context context
;
5048 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5052 char uio_buf
[ UIO_SIZEOF(1) ];
5054 context
.vc_proc
= p
;
5055 context
.vc_ucred
= kauth_cred_get();
5057 if (uap
->options
& XATTR_NOSECURITY
)
5060 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5063 if (xattr_protected(attrname
))
5065 if (uap
->value
== 0 || uap
->size
== 0) {
5069 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5070 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5071 if ((error
= namei(&nd
))) {
5077 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
5078 &uio_buf
[0], sizeof(uio_buf
));
5079 uio_addiov(auio
, uap
->value
, uap
->size
);
5081 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, &context
);
5088 * Set the data of an extended attribute.
5091 fsetxattr(struct proc
*p
, struct fsetxattr_args
*uap
, int *retval
)
5094 char attrname
[XATTR_MAXNAMELEN
+1];
5095 struct vfs_context context
;
5097 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5100 char uio_buf
[ UIO_SIZEOF(1) ];
5102 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5105 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5108 if (xattr_protected(attrname
))
5110 if (uap
->value
== 0 || uap
->size
== 0) {
5113 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5116 if ( (error
= vnode_getwithref(vp
)) ) {
5120 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
5121 &uio_buf
[0], sizeof(uio_buf
));
5122 uio_addiov(auio
, uap
->value
, uap
->size
);
5123 context
.vc_proc
= p
;
5124 context
.vc_ucred
= kauth_cred_get();
5126 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, &context
);
5134 * Remove an extended attribute.
5136 #warning "code duplication"
5138 removexattr(struct proc
*p
, struct removexattr_args
*uap
, int *retval
)
5141 struct nameidata nd
;
5142 char attrname
[XATTR_MAXNAMELEN
+1];
5143 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5144 struct vfs_context context
;
5149 context
.vc_proc
= p
;
5150 context
.vc_ucred
= kauth_cred_get();
5152 if (uap
->options
& XATTR_NOSECURITY
)
5155 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
5159 if (xattr_protected(attrname
))
5161 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5162 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5163 if ((error
= namei(&nd
))) {
5169 error
= vn_removexattr(vp
, attrname
, uap
->options
, &context
);
5176 * Remove an extended attribute.
5178 #warning "code duplication"
5180 fremovexattr(struct proc
*p
, struct fremovexattr_args
*uap
, int *retval
)
5183 char attrname
[XATTR_MAXNAMELEN
+1];
5184 struct vfs_context context
;
5188 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5191 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
5195 if (xattr_protected(attrname
))
5197 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5200 if ( (error
= vnode_getwithref(vp
)) ) {
5204 context
.vc_proc
= p
;
5205 context
.vc_ucred
= kauth_cred_get();
5207 error
= vn_removexattr(vp
, attrname
, uap
->options
, &context
);
5215 * Retrieve the list of extended attribute names.
5217 #warning "code duplication"
5219 listxattr(struct proc
*p
, struct listxattr_args
*uap
, user_ssize_t
*retval
)
5222 struct nameidata nd
;
5223 struct vfs_context context
;
5225 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5226 size_t attrsize
= 0;
5229 char uio_buf
[ UIO_SIZEOF(1) ];
5231 context
.vc_proc
= p
;
5232 context
.vc_ucred
= kauth_cred_get();
5234 if (uap
->options
& XATTR_NOSECURITY
)
5237 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5238 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5239 if ((error
= namei(&nd
))) {
5244 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
5245 // LP64todo - fix this!
5246 auio
= uio_createwithbuffer(1, 0, spacetype
,
5247 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
5248 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
5251 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, &context
);
5255 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
5257 *retval
= (user_ssize_t
)attrsize
;
5263 * Retrieve the list of extended attribute names.
5265 #warning "code duplication"
5267 flistxattr(struct proc
*p
, struct flistxattr_args
*uap
, user_ssize_t
*retval
)
5270 struct vfs_context context
;
5272 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5273 size_t attrsize
= 0;
5275 char uio_buf
[ UIO_SIZEOF(1) ];
5277 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5280 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5283 if ( (error
= vnode_getwithref(vp
)) ) {
5287 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
5288 // LP64todo - fix this!
5289 auio
= uio_createwithbuffer(1, 0, spacetype
,
5290 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
5291 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
5293 context
.vc_proc
= p
;
5294 context
.vc_ucred
= kauth_cred_get();
5296 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, &context
);
5301 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
5303 *retval
= (user_ssize_t
)attrsize
;
5309 * Common routine to handle various flavors of statfs data heading out
5313 munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
5314 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
5315 boolean_t partial_copy
)
5318 int my_size
, copy_size
;
5321 struct user_statfs sfs
;
5322 my_size
= copy_size
= sizeof(sfs
);
5323 bzero(&sfs
, my_size
);
5324 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
5325 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
5326 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
5327 sfs
.f_bsize
= (user_long_t
)sfsp
->f_bsize
;
5328 sfs
.f_iosize
= (user_long_t
)sfsp
->f_iosize
;
5329 sfs
.f_blocks
= (user_long_t
)sfsp
->f_blocks
;
5330 sfs
.f_bfree
= (user_long_t
)sfsp
->f_bfree
;
5331 sfs
.f_bavail
= (user_long_t
)sfsp
->f_bavail
;
5332 sfs
.f_files
= (user_long_t
)sfsp
->f_files
;
5333 sfs
.f_ffree
= (user_long_t
)sfsp
->f_ffree
;
5334 sfs
.f_fsid
= sfsp
->f_fsid
;
5335 sfs
.f_owner
= sfsp
->f_owner
;
5336 strncpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
-1);
5337 strncpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
-1);
5338 strncpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
-1);
5341 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
5343 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
5347 my_size
= copy_size
= sizeof(sfs
);
5348 bzero(&sfs
, my_size
);
5350 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
5351 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
5352 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
5355 * It's possible for there to be more than 2^^31 blocks in the filesystem, so we
5356 * have to fudge the numbers here in that case. We inflate the blocksize in order
5357 * to reflect the filesystem size as best we can.
5359 if ((sfsp
->f_blocks
> LONG_MAX
)
5360 /* Hack for 4061702 . I think the real fix is for Carbon to
5361 * look for some volume capability and not depend on hidden
5362 * semantics agreed between a FS and carbon.
5363 * f_blocks, f_bfree, and f_bavail set to -1 is the trigger
5364 * for Carbon to set bNoVolumeSizes volume attribute.
5365 * Without this the webdavfs files cannot be copied onto
5366 * disk as they look huge. This change should not affect
5367 * XSAN as they should not setting these to -1..
5369 && (sfsp
->f_blocks
!= 0xffffffffffffffff)
5370 && (sfsp
->f_bfree
!= 0xffffffffffffffff)
5371 && (sfsp
->f_bavail
!= 0xffffffffffffffff)) {
5375 * Work out how far we have to shift the block count down to make it fit.
5376 * Note that it's possible to have to shift so far that the resulting
5377 * blocksize would be unreportably large. At that point, we will clip
5378 * any values that don't fit.
5380 * For safety's sake, we also ensure that f_iosize is never reported as
5381 * being smaller than f_bsize.
5383 for (shift
= 0; shift
< 32; shift
++) {
5384 if ((sfsp
->f_blocks
>> shift
) <= LONG_MAX
)
5386 if ((sfsp
->f_bsize
<< (shift
+ 1)) > LONG_MAX
)
5389 #define __SHIFT_OR_CLIP(x, s) ((((x) >> (s)) > LONG_MAX) ? LONG_MAX : ((x) >> (s)))
5390 sfs
.f_blocks
= (long)__SHIFT_OR_CLIP(sfsp
->f_blocks
, shift
);
5391 sfs
.f_bfree
= (long)__SHIFT_OR_CLIP(sfsp
->f_bfree
, shift
);
5392 sfs
.f_bavail
= (long)__SHIFT_OR_CLIP(sfsp
->f_bavail
, shift
);
5393 #undef __SHIFT_OR_CLIP
5394 sfs
.f_bsize
= (long)(sfsp
->f_bsize
<< shift
);
5395 sfs
.f_iosize
= lmax(sfsp
->f_iosize
, sfsp
->f_bsize
);
5397 /* filesystem is small enough to be reported honestly */
5398 sfs
.f_bsize
= (long)sfsp
->f_bsize
;
5399 sfs
.f_iosize
= (long)sfsp
->f_iosize
;
5400 sfs
.f_blocks
= (long)sfsp
->f_blocks
;
5401 sfs
.f_bfree
= (long)sfsp
->f_bfree
;
5402 sfs
.f_bavail
= (long)sfsp
->f_bavail
;
5404 sfs
.f_files
= (long)sfsp
->f_files
;
5405 sfs
.f_ffree
= (long)sfsp
->f_ffree
;
5406 sfs
.f_fsid
= sfsp
->f_fsid
;
5407 sfs
.f_owner
= sfsp
->f_owner
;
5408 strncpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
-1);
5409 strncpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
-1);
5410 strncpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
-1);
5413 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
5415 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
5418 if (sizep
!= NULL
) {
5425 * copy stat structure into user_stat structure.
5427 void munge_stat(struct stat
*sbp
, struct user_stat
*usbp
)
5429 usbp
->st_dev
= sbp
->st_dev
;
5430 usbp
->st_ino
= sbp
->st_ino
;
5431 usbp
->st_mode
= sbp
->st_mode
;
5432 usbp
->st_nlink
= sbp
->st_nlink
;
5433 usbp
->st_uid
= sbp
->st_uid
;
5434 usbp
->st_gid
= sbp
->st_gid
;
5435 usbp
->st_rdev
= sbp
->st_rdev
;
5436 #ifndef _POSIX_SOURCE
5437 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
5438 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
5439 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
5440 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
5441 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
5442 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
5444 usbp
->st_atime
= sbp
->st_atime
;
5445 usbp
->st_atimensec
= sbp
->st_atimensec
;
5446 usbp
->st_mtime
= sbp
->st_mtime
;
5447 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
5448 usbp
->st_ctime
= sbp
->st_ctime
;
5449 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
5451 usbp
->st_size
= sbp
->st_size
;
5452 usbp
->st_blocks
= sbp
->st_blocks
;
5453 usbp
->st_blksize
= sbp
->st_blksize
;
5454 usbp
->st_flags
= sbp
->st_flags
;
5455 usbp
->st_gen
= sbp
->st_gen
;
5456 usbp
->st_lspare
= sbp
->st_lspare
;
5457 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
5458 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];