2 * Copyright (c) 1995-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1989, 1993
24 * The Regents of the University of California. All rights reserved.
25 * (c) UNIX System Laboratories, Inc.
26 * All or some portions of this file are derived from material licensed
27 * to the University of California by American Telephone and Telegraph
28 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
29 * the permission of UNIX System Laboratories, Inc.
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed by the University of
42 * California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * @(#)vfs_syscalls.c 8.41 (Berkeley) 6/15/95
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/namei.h>
65 #include <sys/filedesc.h>
66 #include <sys/kernel.h>
67 #include <sys/file_internal.h>
69 #include <sys/vnode_internal.h>
70 #include <sys/mount_internal.h>
71 #include <sys/proc_internal.h>
72 #include <sys/kauth.h>
73 #include <sys/uio_internal.h>
74 #include <sys/malloc.h>
76 #include <sys/dirent.h>
78 #include <sys/sysctl.h>
80 #include <sys/quota.h>
81 #include <sys/kdebug.h>
82 #include <sys/fsevents.h>
83 #include <sys/sysproto.h>
84 #include <sys/xattr.h>
85 #include <sys/ubc_internal.h>
86 #include <machine/cons.h>
87 #include <machine/limits.h>
88 #include <miscfs/specfs/specdev.h>
90 #include <bsm/audit_kernel.h>
91 #include <bsm/audit_kevents.h>
93 #include <mach/mach_types.h>
94 #include <kern/kern_types.h>
95 #include <kern/kalloc.h>
97 #include <vm/vm_pageout.h>
99 #include <architecture/byte_order.h>
100 #include <libkern/OSAtomic.h>
104 * The currently logged-in user, for ownership of files/directories whose on-disk
105 * permissions are ignored:
109 static int change_dir(struct nameidata
*ndp
, vfs_context_t ctx
);
110 static void checkdirs(struct vnode
*olddp
, vfs_context_t ctx
);
111 void enablequotas(struct mount
*mp
, vfs_context_t ctx
);
112 static int getfsstat_callback(mount_t mp
, void * arg
);
113 static int getutimes(user_addr_t usrtvp
, struct timespec
*tsp
);
114 static int setutimes(vfs_context_t ctx
, struct vnode
*vp
, const struct timespec
*ts
, int nullflag
);
115 static int sync_callback(mount_t
, void *);
116 static int munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
117 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
118 boolean_t partial_copy
);
120 __private_extern__
int sync_internal(void);
122 #ifdef __APPLE_API_OBSOLETE
124 int fd
; /* file descriptor of the target file */
125 struct vstat
*vsb
; /* vstat structure for returned info */
128 const char *path
; /* pathname of the target file */
129 struct vstat
*vsb
; /* vstat structure for returned info */
131 struct mkcomplex_args
{
132 const char *path
; /* pathname of the file to be created */
133 mode_t mode
; /* access mode for the newly created file */
134 u_long type
; /* format of the complex file */
137 const char *path
; /* pathname of the target file */
138 struct vstat
*vsb
; /* vstat structure for returned info */
141 int fstatv(struct proc
*p
, struct fstatv_args
*uap
, register_t
*retval
);
142 int lstatv(struct proc
*p
, struct lstatv_args
*uap
, register_t
*retval
);
143 int mkcomplex(struct proc
*p
, struct mkcomplex_args
*uap
, register_t
*retval
);
144 int statv(struct proc
*p
, struct statv_args
*uap
, register_t
*retval
);
146 #endif /* __APPLE_API_OBSOLETE */
149 extern int (**union_vnodeop_p
)(void *);
150 extern struct vnode
*union_dircache(struct vnode
*, struct proc
*);
153 /* counts number of mount and unmount operations */
154 unsigned int vfs_nummntops
=0;
156 extern struct fileops vnops
;
158 extern void mount_list_add(mount_t mp
);
159 extern void mount_list_remove(mount_t mp
);
160 extern int mount_refdrain(mount_t mp
);
161 extern int vcount(struct vnode
*vp
);
165 * Virtual File System System Calls
169 * Mount a file system.
173 mount(struct proc
*p
, register struct mount_args
*uap
, __unused register_t
*retval
)
176 struct vnode
*devvp
= NULLVP
;
177 struct vnode
*device_vnode
= NULLVP
;
179 struct vfstable
*vfsp
;
181 struct vnode_attr va
;
182 struct vfs_context context
;
184 struct nameidata nd1
;
185 char fstypename
[MFSNAMELEN
];
187 user_addr_t devpath
= USER_ADDR_NULL
;
188 user_addr_t fsmountargs
= uap
->data
;
194 AUDIT_ARG(fflags
, uap
->flags
);
197 context
.vc_ucred
= kauth_cred_get();
198 is_64bit
= proc_is64bit(p
);
201 * Get vnode to be covered
203 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
204 UIO_USERSPACE
, uap
->path
, &context
);
210 if ((vp
->v_flag
& VROOT
) &&
211 (vp
->v_mount
->mnt_flag
& MNT_ROOTFS
))
212 uap
->flags
|= MNT_UPDATE
;
214 if (uap
->flags
& MNT_UPDATE
) {
215 if ((vp
->v_flag
& VROOT
) == 0) {
221 /* unmount in progress return error */
223 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
229 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
231 * We only allow the filesystem to be reloaded if it
232 * is currently mounted read-only.
234 if ((uap
->flags
& MNT_RELOAD
) &&
235 ((mp
->mnt_flag
& MNT_RDONLY
) == 0)) {
236 lck_rw_done(&mp
->mnt_rwlock
);
241 * Only root, or the user that did the original mount is
242 * permitted to update it.
244 if (mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(context
.vc_ucred
) &&
245 (error
= suser(context
.vc_ucred
, &p
->p_acflag
))) {
246 lck_rw_done(&mp
->mnt_rwlock
);
250 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV,
251 * and MNT_NOEXEC if mount point is already MNT_NOEXEC.
253 if (suser(context
.vc_ucred
, NULL
)) {
254 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
255 if (mp
->mnt_flag
& MNT_NOEXEC
)
256 uap
->flags
|= MNT_NOEXEC
;
261 uap
->flags
& (MNT_RELOAD
| MNT_FORCE
| MNT_UPDATE
);
263 vfsp
= mp
->mnt_vtable
;
267 * If the user is not root, ensure that they own the directory
268 * onto which we are attempting to mount.
271 VATTR_WANTED(&va
, va_uid
);
272 if ((error
= vnode_getattr(vp
, &va
, &context
)) ||
273 (va
.va_uid
!= kauth_cred_getuid(context
.vc_ucred
) &&
274 (error
= suser(context
.vc_ucred
, &p
->p_acflag
)))) {
278 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV, and
279 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
281 if (suser(context
.vc_ucred
, NULL
)) {
282 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
283 if (vp
->v_mount
->mnt_flag
& MNT_NOEXEC
)
284 uap
->flags
|= MNT_NOEXEC
;
286 if ( (error
= VNOP_FSYNC(vp
, MNT_WAIT
, &context
)) )
289 if ( (error
= buf_invalidateblks(vp
, BUF_WRITE_DATA
, 0, 0)) )
292 if (vp
->v_type
!= VDIR
) {
296 if ( (error
= copyinstr(uap
->type
, fstypename
, MFSNAMELEN
, &dummy
)) )
299 /* XXXAUDIT: Should we capture the type on the error path as well? */
300 AUDIT_ARG(text
, fstypename
);
302 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
303 if (!strcmp(vfsp
->vfc_name
, fstypename
))
310 if (ISSET(vp
->v_flag
, VMOUNT
) && (vp
->v_mountedhere
!= NULL
)) {
314 SET(vp
->v_flag
, VMOUNT
);
317 * Allocate and initialize the filesystem.
319 MALLOC_ZONE(mp
, struct mount
*, (u_long
)sizeof(struct mount
),
321 bzero((char *)mp
, (u_long
)sizeof(struct mount
));
324 /* Initialize the default IO constraints */
325 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
326 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
327 mp
->mnt_maxsegreadsize
= mp
->mnt_maxreadcnt
;
328 mp
->mnt_maxsegwritesize
= mp
->mnt_maxwritecnt
;
329 mp
->mnt_devblocksize
= DEV_BSIZE
;
331 TAILQ_INIT(&mp
->mnt_vnodelist
);
332 TAILQ_INIT(&mp
->mnt_workerqueue
);
333 TAILQ_INIT(&mp
->mnt_newvnodes
);
335 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
336 mp
->mnt_op
= vfsp
->vfc_vfsops
;
337 mp
->mnt_vtable
= vfsp
;
339 vfsp
->vfc_refcount
++;
341 //mp->mnt_stat.f_type = vfsp->vfc_typenum;
342 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
343 strncpy(mp
->mnt_vfsstat
.f_fstypename
, vfsp
->vfc_name
, MFSTYPENAMELEN
);
344 strncpy(mp
->mnt_vfsstat
.f_mntonname
, nd
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
345 mp
->mnt_vnodecovered
= vp
;
346 mp
->mnt_vfsstat
.f_owner
= kauth_cred_getuid(context
.vc_ucred
);
348 /* XXX 3762912 hack to support HFS filesystem 'owner' - filesystem may update later */
349 vfs_setowner(mp
, KAUTH_UID_NONE
, KAUTH_GID_NONE
);
353 * Set the mount level flags.
355 if (uap
->flags
& MNT_RDONLY
)
356 mp
->mnt_flag
|= MNT_RDONLY
;
357 else if (mp
->mnt_flag
& MNT_RDONLY
)
358 mp
->mnt_kern_flag
|= MNTK_WANTRDWR
;
359 mp
->mnt_flag
&= ~(MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
360 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
361 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
);
362 mp
->mnt_flag
|= uap
->flags
& (MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
363 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
364 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
|
367 if (vfsp
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
369 if ( (error
= copyin(fsmountargs
, (caddr_t
)&devpath
, sizeof(devpath
))) )
371 fsmountargs
+= sizeof(devpath
);
374 if ( (error
= copyin(fsmountargs
, (caddr_t
)&tmp
, sizeof(tmp
))) )
376 /* munge into LP64 addr */
377 devpath
= CAST_USER_ADDR_T(tmp
);
378 fsmountargs
+= sizeof(tmp
);
381 /* if it is not update and device name needs to be parsed */
383 NDINIT(&nd1
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, devpath
, &context
);
384 if ( (error
= namei(&nd1
)) )
387 strncpy(mp
->mnt_vfsstat
.f_mntfromname
, nd1
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
392 if (devvp
->v_type
!= VBLK
) {
396 if (major(devvp
->v_rdev
) >= nblkdev
) {
401 * If mount by non-root, then verify that user has necessary
402 * permissions on the device.
404 if (suser(context
.vc_ucred
, NULL
) != 0) {
405 accessmode
= KAUTH_VNODE_READ_DATA
;
406 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
407 accessmode
|= KAUTH_VNODE_WRITE_DATA
;
408 if ((error
= vnode_authorize(devvp
, NULL
, accessmode
, &context
)) != 0)
412 if (devpath
&& ((uap
->flags
& MNT_UPDATE
) == 0)) {
413 if ( (error
= vnode_ref(devvp
)) )
416 * Disallow multiple mounts of the same device.
417 * Disallow mounting of a device that is currently in use
418 * (except for root, which might share swap device for miniroot).
419 * Flush out any old buffers remaining from a previous use.
421 if ( (error
= vfs_mountedon(devvp
)) )
424 if (vcount(devvp
) > 1 && !(vfs_flags(mp
) & MNT_ROOTFS
)) {
428 if ( (error
= VNOP_FSYNC(devvp
, MNT_WAIT
, &context
)) ) {
432 if ( (error
= buf_invalidateblks(devvp
, BUF_WRITE_DATA
, 0, 0)) )
435 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
436 if ( (error
= VNOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, &context
)) )
439 mp
->mnt_devvp
= devvp
;
440 device_vnode
= devvp
;
442 if ((mp
->mnt_flag
& MNT_RDONLY
) && (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)) {
444 * If upgrade to read-write by non-root, then verify
445 * that user has necessary permissions on the device.
447 device_vnode
= mp
->mnt_devvp
;
448 if (device_vnode
&& suser(context
.vc_ucred
, NULL
)) {
449 if ((error
= vnode_authorize(device_vnode
, NULL
,
450 KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0)
454 device_vnode
= NULLVP
;
460 * Mount the filesystem.
462 error
= VFS_MOUNT(mp
, device_vnode
, fsmountargs
, &context
);
464 if (uap
->flags
& MNT_UPDATE
) {
465 if (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)
466 mp
->mnt_flag
&= ~MNT_RDONLY
;
468 (MNT_UPDATE
| MNT_RELOAD
| MNT_FORCE
);
469 mp
->mnt_kern_flag
&=~ MNTK_WANTRDWR
;
472 vfs_event_signal(NULL
, VQ_UPDATE
, (intptr_t)NULL
);
473 lck_rw_done(&mp
->mnt_rwlock
);
475 enablequotas(mp
,&context
);
479 * Put the new filesystem on the mount list after root.
482 CLR(vp
->v_flag
, VMOUNT
);
485 vp
->v_mountedhere
= mp
;
490 vfs_event_signal(NULL
, VQ_MOUNT
, (intptr_t)NULL
);
491 checkdirs(vp
, &context
);
492 lck_rw_done(&mp
->mnt_rwlock
);
495 * there is no cleanup code here so I have made it void
496 * we need to revisit this
498 (void)VFS_START(mp
, 0, &context
);
500 /* increment the operations count */
501 OSAddAtomic(1, (SInt32
*)&vfs_nummntops
);
502 enablequotas(mp
,&context
);
505 device_vnode
->v_specflags
|= SI_MOUNTEDON
;
508 * cache the IO attributes for the underlying physical media...
509 * an error return indicates the underlying driver doesn't
510 * support all the queries necessary... however, reasonable
511 * defaults will have been set, so no reason to bail or care
513 vfs_init_io_attributes(device_vnode
, mp
);
516 CLR(vp
->v_flag
, VMOUNT
);
518 mp
->mnt_vtable
->vfc_refcount
--;
522 VNOP_CLOSE(device_vnode
, ronly
? FREAD
: FREAD
|FWRITE
, &context
);
523 vnode_rele(device_vnode
);
525 lck_rw_done(&mp
->mnt_rwlock
);
526 mount_lock_destroy(mp
);
527 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
532 * drop I/O count on covered 'vp' and
533 * on the device vp if there was one
535 if (devpath
&& devvp
)
544 if (devpath
&& devvp
)
548 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
557 enablequotas(struct mount
*mp
, vfs_context_t context
)
559 struct nameidata qnd
;
561 char qfpath
[MAXPATHLEN
];
562 const char *qfname
= QUOTAFILENAME
;
563 const char *qfopsname
= QUOTAOPSNAME
;
564 const char *qfextension
[] = INITQFNAMES
;
566 if ((strcmp(mp
->mnt_vfsstat
.f_fstypename
, "hfs") != 0 )
567 && (strcmp( mp
->mnt_vfsstat
.f_fstypename
, "ufs") != 0))
571 * Enable filesystem disk quotas if necessary.
572 * We ignore errors as this should not interfere with final mount
574 for (type
=0; type
< MAXQUOTAS
; type
++) {
575 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfopsname
, qfextension
[type
]);
576 NDINIT(&qnd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE32
, CAST_USER_ADDR_T(qfpath
), context
);
577 if (namei(&qnd
) != 0)
578 continue; /* option file to trigger quotas is not present */
579 vnode_put(qnd
.ni_vp
);
581 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfname
, qfextension
[type
]);
583 (void) VFS_QUOTACTL(mp
, QCMD(Q_QUOTAON
, type
), 0, qfpath
, context
);
589 * Scan all active processes to see if any of them have a current
590 * or root directory onto which the new filesystem has just been
591 * mounted. If so, replace them with the new mount point.
594 checkdirs(olddp
, context
)
596 vfs_context_t context
;
598 struct filedesc
*fdp
;
602 struct vnode
*fdp_cvp
;
603 struct vnode
*fdp_rvp
;
604 int cdir_changed
= 0;
605 int rdir_changed
= 0;
606 boolean_t funnel_state
;
608 if (olddp
->v_usecount
== 1)
610 if (VFS_ROOT(olddp
->v_mountedhere
, &newdp
, context
))
611 panic("mount: lost mount");
612 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
614 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
617 if (fdp
== (struct filedesc
*)0) {
621 fdp_cvp
= fdp
->fd_cdir
;
622 fdp_rvp
= fdp
->fd_rdir
;
625 if (fdp_cvp
== olddp
) {
632 if (fdp_rvp
== olddp
) {
639 if (cdir_changed
|| rdir_changed
) {
641 fdp
->fd_cdir
= fdp_cvp
;
642 fdp
->fd_rdir
= fdp_rvp
;
646 if (rootvnode
== olddp
) {
652 thread_funnel_set(kernel_flock
, funnel_state
);
658 * Unmount a file system.
660 * Note: unmount takes a path to the vnode mounted on as argument,
661 * not special file (as before).
665 unmount(struct proc
*p
, register struct unmount_args
*uap
, __unused register_t
*retval
)
667 register struct vnode
*vp
;
671 struct vfs_context context
;
674 context
.vc_ucred
= kauth_cred_get();
676 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
677 UIO_USERSPACE
, uap
->path
, &context
);
686 * Must be the root of the filesystem
688 if ((vp
->v_flag
& VROOT
) == 0) {
693 return (safedounmount(mp
, uap
->flags
, p
));
697 * Do the actual file system unmount, prevent some common foot shooting.
699 * XXX Should take a "vfs_context_t" instead of a "struct proc *"
702 safedounmount(mp
, flags
, p
)
710 * Only root, or the user that did the original mount is
711 * permitted to unmount this filesystem.
713 if ((mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(kauth_cred_get())) &&
714 (error
= suser(kauth_cred_get(), &p
->p_acflag
)))
718 * Don't allow unmounting the root file system.
720 if (mp
->mnt_flag
& MNT_ROOTFS
)
721 return (EBUSY
); /* the root is always busy */
723 return (dounmount(mp
, flags
, p
));
727 * Do the actual file system unmount.
730 dounmount(mp
, flags
, p
)
731 register struct mount
*mp
;
735 struct vnode
*coveredvp
= (vnode_t
)0;
738 struct vfs_context context
;
739 int forcedunmount
= 0;
743 context
.vc_ucred
= kauth_cred_get();
745 if (flags
& MNT_FORCE
)
748 /* XXX post jaguar fix LK_DRAIN - then clean this up */
749 if ((flags
& MNT_FORCE
)) {
750 mp
->mnt_kern_flag
|= MNTK_FRCUNMOUNT
;
751 mp
->mnt_lflag
|= MNT_LFORCE
;
753 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
754 mp
->mnt_lflag
|= MNT_LWAIT
;
755 msleep((caddr_t
)mp
, &mp
->mnt_mlock
, (PVFS
| PDROP
), "dounmount", 0 );
757 * The prior unmount attempt has probably succeeded.
758 * Do not dereference mp here - returning EBUSY is safest.
762 mp
->mnt_kern_flag
|= MNTK_UNMOUNT
;
763 mp
->mnt_lflag
|= MNT_LUNMOUNT
;
764 mp
->mnt_flag
&=~ MNT_ASYNC
;
766 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
767 fsevent_unmount(mp
); /* has to come first! */
769 if (forcedunmount
== 0) {
770 ubc_umount(mp
); /* release cached vnodes */
771 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
772 error
= VFS_SYNC(mp
, MNT_WAIT
, &context
);
775 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
776 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
777 mp
->mnt_lflag
&= ~MNT_LFORCE
;
784 lflags
|= FORCECLOSE
;
785 error
= vflush(mp
, NULLVP
, SKIPSWAP
| SKIPSYSTEM
| SKIPROOT
| lflags
);
786 if ((forcedunmount
== 0) && error
) {
788 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
789 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
790 mp
->mnt_lflag
&= ~MNT_LFORCE
;
794 /* make sure there are no one in the mount iterations or lookup */
797 error
= VFS_UNMOUNT(mp
, flags
, &context
);
801 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
802 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
803 mp
->mnt_lflag
&= ~MNT_LFORCE
;
807 /* increment the operations count */
809 OSAddAtomic(1, (SInt32
*)&vfs_nummntops
);
811 if ( mp
->mnt_devvp
&& mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
812 mp
->mnt_devvp
->v_specflags
&= ~SI_MOUNTEDON
;
813 VNOP_CLOSE(mp
->mnt_devvp
, mp
->mnt_flag
& MNT_RDONLY
? FREAD
: FREAD
|FWRITE
,
815 vnode_rele(mp
->mnt_devvp
);
817 lck_rw_done(&mp
->mnt_rwlock
);
818 mount_list_remove(mp
);
819 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
821 /* mark the mount point hook in the vp but not drop the ref yet */
822 if ((coveredvp
= mp
->mnt_vnodecovered
) != NULLVP
) {
823 vnode_getwithref(coveredvp
);
824 vnode_lock(coveredvp
);
825 coveredvp
->v_mountedhere
= (struct mount
*)0;
826 vnode_unlock(coveredvp
);
827 vnode_put(coveredvp
);
831 mp
->mnt_vtable
->vfc_refcount
--;
834 cache_purgevfs(mp
); /* remove cache entries for this file sys */
835 vfs_event_signal(NULL
, VQ_UNMOUNT
, (intptr_t)NULL
);
837 mp
->mnt_lflag
|= MNT_LDEAD
;
839 if (mp
->mnt_lflag
& MNT_LWAIT
) {
842 * in case we block in mount_refdrain
843 * which will drop the mount lock
844 * and allow anyone blocked in vfs_busy
845 * to wakeup and see the LDEAD state
847 mp
->mnt_lflag
&= ~MNT_LWAIT
;
852 if (mp
->mnt_lflag
& MNT_LWAIT
) {
853 mp
->mnt_lflag
&= ~MNT_LWAIT
;
857 lck_rw_done(&mp
->mnt_rwlock
);
862 if ((coveredvp
!= NULLVP
)) {
863 vnode_getwithref(coveredvp
);
864 vnode_rele(coveredvp
);
865 vnode_lock(coveredvp
);
866 if(mp
->mnt_crossref
== 0) {
867 vnode_unlock(coveredvp
);
868 mount_lock_destroy(mp
);
869 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
871 coveredvp
->v_lflag
|= VL_MOUNTDEAD
;
872 vnode_unlock(coveredvp
);
874 vnode_put(coveredvp
);
875 } else if (mp
->mnt_flag
& MNT_ROOTFS
) {
876 mount_lock_destroy(mp
);
877 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
879 panic("dounmount: no coveredvp");
885 mount_dropcrossref(mount_t mp
, vnode_t dp
, int need_put
)
889 if (mp
->mnt_crossref
< 0)
890 panic("mount cross refs -ve");
891 if (((dp
->v_lflag
& VL_MOUNTDEAD
) == VL_MOUNTDEAD
) && (mp
->mnt_crossref
== 0)) {
892 dp
->v_lflag
&= ~VL_MOUNTDEAD
;
894 vnode_put_locked(dp
);
896 mount_lock_destroy(mp
);
897 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
901 vnode_put_locked(dp
);
907 * Sync each mounted filesystem.
911 struct ctldebug debug0
= { "syncprt", &syncprt
};
914 int print_vmpage_stat
=0;
917 sync_callback(mount_t mp
, __unused
void * arg
)
919 struct proc
* p
= current_proc();
921 struct vfs_context context
;
924 context
.vc_ucred
= kauth_cred_get();
926 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
927 asyncflag
= mp
->mnt_flag
& MNT_ASYNC
;
928 mp
->mnt_flag
&= ~MNT_ASYNC
;
929 VFS_SYNC(mp
, MNT_NOWAIT
, &context
);
931 mp
->mnt_flag
|= MNT_ASYNC
;
933 return(VFS_RETURNED
);
937 extern unsigned int vp_pagein
, vp_pgodirty
, vp_pgoclean
;
938 extern unsigned int dp_pgins
, dp_pgouts
;
942 sync(__unused
struct proc
*p
, __unused
struct sync_args
*uap
, __unused register_t
*retval
)
945 vfs_iterate(LK_NOWAIT
, sync_callback
, (void *)0);
947 if(print_vmpage_stat
) {
948 vm_countdirtypages();
949 printf("VP: %d: %d: %d: %d: %d\n", vp_pgodirty
, vp_pgoclean
, vp_pagein
,
950 dp_pgins
, dp_pgouts
);
956 #endif /* DIAGNOSTIC */
961 * Change filesystem quotas.
965 quotactl(struct proc
*p
, register struct quotactl_args
*uap
, __unused register_t
*retval
)
967 register struct mount
*mp
;
968 int error
, quota_cmd
, quota_status
;
972 struct vfs_context context
;
973 struct dqblk my_dqblk
;
976 context
.vc_ucred
= kauth_cred_get();
978 AUDIT_ARG(uid
, uap
->uid
, 0, 0, 0);
979 AUDIT_ARG(cmd
, uap
->cmd
);
980 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
981 UIO_USERSPACE
, uap
->path
, &context
);
985 mp
= nd
.ni_vp
->v_mount
;
989 /* copyin any data we will need for downstream code */
990 quota_cmd
= uap
->cmd
>> SUBCMDSHIFT
;
994 /* uap->arg specifies a file from which to take the quotas */
995 fnamelen
= MAXPATHLEN
;
996 datap
= kalloc(MAXPATHLEN
);
997 error
= copyinstr(uap
->arg
, datap
, MAXPATHLEN
, &fnamelen
);
1000 /* uap->arg is a pointer to a dqblk structure. */
1001 datap
= (caddr_t
) &my_dqblk
;
1005 /* uap->arg is a pointer to a dqblk structure. */
1006 datap
= (caddr_t
) &my_dqblk
;
1007 if (proc_is64bit(p
)) {
1008 struct user_dqblk my_dqblk64
;
1009 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk64
, sizeof (my_dqblk64
));
1011 munge_dqblk(&my_dqblk
, &my_dqblk64
, FALSE
);
1015 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk
, sizeof (my_dqblk
));
1019 /* uap->arg is a pointer to an integer */
1020 datap
= (caddr_t
) "a_status
;
1028 error
= VFS_QUOTACTL(mp
, uap
->cmd
, uap
->uid
, datap
, &context
);
1031 switch (quota_cmd
) {
1034 kfree(datap
, MAXPATHLEN
);
1037 /* uap->arg is a pointer to a dqblk structure we need to copy out to */
1039 if (proc_is64bit(p
)) {
1040 struct user_dqblk my_dqblk64
;
1041 munge_dqblk(&my_dqblk
, &my_dqblk64
, TRUE
);
1042 error
= copyout((caddr_t
)&my_dqblk64
, uap
->arg
, sizeof (my_dqblk64
));
1045 error
= copyout(datap
, uap
->arg
, sizeof (struct dqblk
));
1050 /* uap->arg is a pointer to an integer */
1052 error
= copyout(datap
, uap
->arg
, sizeof(quota_status
));
1063 * Get filesystem statistics.
1067 statfs(struct proc
*p
, register struct statfs_args
*uap
, __unused register_t
*retval
)
1070 struct vfsstatfs
*sp
;
1072 struct nameidata nd
;
1073 struct vfs_context context
;
1076 context
.vc_proc
= p
;
1077 context
.vc_ucred
= kauth_cred_get();
1079 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1080 UIO_USERSPACE
, uap
->path
, &context
);
1086 sp
= &mp
->mnt_vfsstat
;
1089 error
= vfs_update_vfsstat(mp
, &context
);
1094 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1099 * Get filesystem statistics.
1103 fstatfs(struct proc
*p
, register struct fstatfs_args
*uap
, __unused register_t
*retval
)
1107 struct vfsstatfs
*sp
;
1109 struct vfs_context context
;
1111 context
.vc_proc
= p
;
1112 context
.vc_ucred
= kauth_cred_get();
1114 AUDIT_ARG(fd
, uap
->fd
);
1116 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1119 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
1126 sp
= &mp
->mnt_vfsstat
;
1127 if ((error
= vfs_update_vfsstat(mp
, &context
)) != 0) {
1133 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1139 struct getfsstat_struct
{
1149 getfsstat_callback(mount_t mp
, void * arg
)
1152 struct getfsstat_struct
*fstp
= (struct getfsstat_struct
*)arg
;
1153 struct vfsstatfs
*sp
;
1154 struct proc
* p
= current_proc();
1156 struct vfs_context context
;
1158 context
.vc_proc
= p
;
1159 context
.vc_ucred
= kauth_cred_get();
1161 if (fstp
->sfsp
&& fstp
->count
< fstp
->maxcount
) {
1162 sp
= &mp
->mnt_vfsstat
;
1164 * If MNT_NOWAIT is specified, do not refresh the
1165 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
1167 if (((fstp
->flags
& MNT_NOWAIT
) == 0 || (fstp
->flags
& MNT_WAIT
)) &&
1168 (error
= vfs_update_vfsstat(mp
, &context
))) {
1169 KAUTH_DEBUG("vfs_update_vfsstat returned %d", error
);
1170 return(VFS_RETURNED
);
1174 * Need to handle LP64 version of struct statfs
1176 error
= munge_statfs(mp
, sp
, fstp
->sfsp
, &my_size
, IS_64BIT_PROCESS(p
), FALSE
);
1178 fstp
->error
= error
;
1179 return(VFS_RETURNED_DONE
);
1181 fstp
->sfsp
+= my_size
;
1184 return(VFS_RETURNED
);
1188 * Get statistics on all filesystems.
1191 getfsstat(__unused proc_t p
, struct getfsstat_args
*uap
, int *retval
)
1194 int count
, maxcount
;
1195 struct getfsstat_struct fst
;
1197 if (IS_64BIT_PROCESS(p
)) {
1198 maxcount
= uap
->bufsize
/ sizeof(struct user_statfs
);
1201 maxcount
= uap
->bufsize
/ sizeof(struct statfs
);
1207 fst
.flags
= uap
->flags
;
1210 fst
.maxcount
= maxcount
;
1213 vfs_iterate(0, getfsstat_callback
, &fst
);
1216 KAUTH_DEBUG("ERROR - %s gets %d", p
->p_comm
, fst
.error
);
1220 if (fst
.sfsp
&& fst
.count
> fst
.maxcount
)
1221 *retval
= fst
.maxcount
;
1223 *retval
= fst
.count
;
1227 #if COMPAT_GETFSSTAT
1228 ogetfsstat(p
, uap
, retval
)
1230 register struct getfsstat_args
*uap
;
1238 * Change current working directory to a given file descriptor.
1242 fchdir(struct proc
*p
, struct fchdir_args
*uap
, __unused register_t
*retval
)
1244 register struct filedesc
*fdp
= p
->p_fd
;
1245 struct vnode
*vp
, *tdp
, *tvp
;
1248 struct vfs_context context
;
1250 context
.vc_proc
= p
;
1251 context
.vc_ucred
= kauth_cred_get();
1253 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1255 if ( (error
= vnode_getwithref(vp
)) ) {
1260 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
1262 if (vp
->v_type
!= VDIR
)
1265 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, &context
);
1266 while (!error
&& (mp
= vp
->v_mountedhere
) != NULL
) {
1267 if (vfs_busy(mp
, LK_NOWAIT
)) {
1271 error
= VFS_ROOT(mp
, &tdp
, &context
);
1280 if ( (error
= vnode_ref(vp
)) )
1302 * Change current working directory (``.'').
1306 chdir(struct proc
*p
, struct chdir_args
*uap
, __unused register_t
*retval
)
1308 register struct filedesc
*fdp
= p
->p_fd
;
1310 struct nameidata nd
;
1312 struct vfs_context context
;
1314 context
.vc_proc
= p
;
1315 context
.vc_ucred
= kauth_cred_get();
1317 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1318 UIO_USERSPACE
, uap
->path
, &context
);
1319 error
= change_dir(&nd
, &context
);
1322 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
1323 vnode_put(nd
.ni_vp
);
1327 * drop the iocount we picked up in change_dir
1329 vnode_put(nd
.ni_vp
);
1333 fdp
->fd_cdir
= nd
.ni_vp
;
1343 * Change notion of root (``/'') directory.
1347 chroot(struct proc
*p
, struct chroot_args
*uap
, __unused register_t
*retval
)
1349 register struct filedesc
*fdp
= p
->p_fd
;
1351 struct nameidata nd
;
1352 boolean_t shared_regions_active
;
1354 struct vfs_context context
;
1356 context
.vc_proc
= p
;
1357 context
.vc_ucred
= kauth_cred_get();
1359 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
1362 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1363 UIO_USERSPACE
, uap
->path
, &context
);
1364 error
= change_dir(&nd
, &context
);
1368 if(p
->p_flag
& P_NOSHLIB
) {
1369 shared_regions_active
= FALSE
;
1371 shared_regions_active
= TRUE
;
1373 if ((error
= clone_system_shared_regions(shared_regions_active
,
1374 TRUE
, /* chain_regions */
1376 vnode_put(nd
.ni_vp
);
1379 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
1380 vnode_put(nd
.ni_vp
);
1383 vnode_put(nd
.ni_vp
);
1387 fdp
->fd_rdir
= nd
.ni_vp
;
1388 fdp
->fd_flags
|= FD_CHROOT
;
1398 * Common routine for chroot and chdir.
1401 change_dir(struct nameidata
*ndp
, vfs_context_t ctx
)
1406 if ((error
= namei(ndp
)))
1410 if (vp
->v_type
!= VDIR
)
1413 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, ctx
);
1421 * Check permissions, allocate an open file structure,
1422 * and call the device open routine if any.
1425 #warning XXX implement uid, gid
1427 open1(vfs_context_t ctx
, user_addr_t upath
, int uflags
, struct vnode_attr
*vap
, register_t
*retval
)
1429 struct proc
*p
= vfs_context_proc(ctx
);
1430 register struct filedesc
*fdp
= p
->p_fd
;
1431 register struct fileproc
*fp
;
1432 register struct vnode
*vp
;
1434 struct fileproc
*nfp
;
1435 int type
, indx
, error
;
1437 struct nameidata nd
;
1441 if ((oflags
& O_ACCMODE
) == O_ACCMODE
)
1443 flags
= FFLAGS(uflags
);
1445 AUDIT_ARG(fflags
, oflags
);
1446 AUDIT_ARG(mode
, vap
->va_mode
);
1448 if ( (error
= falloc(p
, &nfp
, &indx
)) ) {
1452 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1453 UIO_USERSPACE
, upath
, ctx
);
1454 p
->p_dupfd
= -indx
- 1; /* XXX check for fdopen */
1456 if ((error
= vn_open_auth(&nd
, &flags
, vap
))) {
1457 if ((error
== ENODEV
|| error
== ENXIO
) && (p
->p_dupfd
>= 0)) { /* XXX from fdopen */
1458 if ((error
= dupfdopen(fdp
, indx
, p
->p_dupfd
, flags
, error
)) == 0) {
1459 fp_drop(p
, indx
, 0, 0);
1464 if (error
== ERESTART
)
1466 fp_free(p
, indx
, fp
);
1473 fp
->f_fglob
->fg_flag
= flags
& (FMASK
| O_EVTONLY
);
1474 fp
->f_fglob
->fg_type
= DTYPE_VNODE
;
1475 fp
->f_fglob
->fg_ops
= &vnops
;
1476 fp
->f_fglob
->fg_data
= (caddr_t
)vp
;
1478 if (flags
& (O_EXLOCK
| O_SHLOCK
)) {
1479 lf
.l_whence
= SEEK_SET
;
1482 if (flags
& O_EXLOCK
)
1483 lf
.l_type
= F_WRLCK
;
1485 lf
.l_type
= F_RDLCK
;
1487 if ((flags
& FNONBLOCK
) == 0)
1489 if ((error
= VNOP_ADVLOCK(vp
, (caddr_t
)fp
->f_fglob
, F_SETLK
, &lf
, type
, ctx
)))
1491 fp
->f_fglob
->fg_flag
|= FHASLOCK
;
1494 /* try to truncate by setting the size attribute */
1495 if ((flags
& O_TRUNC
) && ((error
= vnode_setsize(vp
, (off_t
)0, 0, ctx
)) != 0))
1501 *fdflags(p
, indx
) &= ~UF_RESERVED
;
1502 fp_drop(p
, indx
, fp
, 1);
1509 vn_close(vp
, fp
->f_fglob
->fg_flag
, fp
->f_fglob
->fg_cred
, p
);
1511 fp_free(p
, indx
, fp
);
1518 open_extended(struct proc
*p
, struct open_extended_args
*uap
, register_t
*retval
)
1520 struct vfs_context context
;
1521 register struct filedesc
*fdp
= p
->p_fd
;
1523 kauth_filesec_t xsecdst
;
1524 struct vnode_attr va
;
1528 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
1529 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
1532 context
.vc_proc
= p
;
1533 context
.vc_ucred
= kauth_cred_get();
1536 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
1537 VATTR_SET(&va
, va_mode
, cmode
);
1538 if (uap
->uid
!= KAUTH_UID_NONE
)
1539 VATTR_SET(&va
, va_uid
, uap
->uid
);
1540 if (uap
->gid
!= KAUTH_GID_NONE
)
1541 VATTR_SET(&va
, va_gid
, uap
->gid
);
1542 if (xsecdst
!= NULL
)
1543 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
1545 ciferror
= open1(&context
, uap
->path
, uap
->flags
, &va
, retval
);
1546 if (xsecdst
!= NULL
)
1547 kauth_filesec_free(xsecdst
);
1553 open(struct proc
*p
, struct open_args
*uap
, register_t
*retval
)
1555 struct vfs_context context
;
1556 register struct filedesc
*fdp
= p
->p_fd
;
1557 struct vnode_attr va
;
1560 context
.vc_proc
= p
;
1561 context
.vc_ucred
= kauth_cred_get();
1564 /* Mask off all but regular access permissions */
1565 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
1566 VATTR_SET(&va
, va_mode
, cmode
& ACCESSPERMS
);
1568 return(open1(&context
, uap
->path
, uap
->flags
, &va
, retval
));
1573 * Create a special file.
1575 static int mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
);
1578 mknod(struct proc
*p
, register struct mknod_args
*uap
, __unused register_t
*retval
)
1580 struct vnode_attr va
;
1581 struct vfs_context context
;
1584 struct nameidata nd
;
1587 context
.vc_proc
= p
;
1588 context
.vc_ucred
= kauth_cred_get();
1591 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1592 VATTR_SET(&va
, va_rdev
, uap
->dev
);
1594 /* If it's a mknod() of a FIFO, call mkfifo1() instead */
1595 if ((uap
->mode
& S_IFMT
) == S_IFIFO
)
1596 return(mkfifo1(&context
, uap
->path
, &va
));
1598 AUDIT_ARG(mode
, uap
->mode
);
1599 AUDIT_ARG(dev
, uap
->dev
);
1601 if ((error
= suser(context
.vc_ucred
, &p
->p_acflag
)))
1603 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1604 UIO_USERSPACE
, uap
->path
, &context
);
1616 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
1619 switch (uap
->mode
& S_IFMT
) {
1620 case S_IFMT
: /* used by badsect to flag bad sectors */
1621 VATTR_SET(&va
, va_type
, VBAD
);
1624 VATTR_SET(&va
, va_type
, VCHR
);
1627 VATTR_SET(&va
, va_type
, VBLK
);
1637 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, CREATE
, &context
);
1639 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, &va
, 0, &context
);
1645 int update_flags
= 0;
1647 // Make sure the name & parent pointers are hooked up
1648 if (vp
->v_name
== NULL
)
1649 update_flags
|= VNODE_UPDATE_NAME
;
1650 if (vp
->v_parent
== NULLVP
)
1651 update_flags
|= VNODE_UPDATE_PARENT
;
1654 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
1656 add_fsevent(FSE_CREATE_FILE
, &context
,
1663 * nameidone has to happen before we vnode_put(dvp)
1664 * since it may need to release the fs_nodelock on the dvp
1676 * Create a named pipe.
1679 mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
)
1683 struct nameidata nd
;
1685 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1686 UIO_USERSPACE
, upath
, ctx
);
1693 /* check that this is a new file and authorize addition */
1698 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
1701 VATTR_SET(vap
, va_type
, VFIFO
);
1703 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
);
1706 * nameidone has to happen before we vnode_put(dvp)
1707 * since it may need to release the fs_nodelock on the dvp
1719 mkfifo_extended(struct proc
*p
, struct mkfifo_extended_args
*uap
, __unused register_t
*retval
)
1722 kauth_filesec_t xsecdst
;
1723 struct vfs_context context
;
1724 struct vnode_attr va
;
1726 xsecdst
= KAUTH_FILESEC_NONE
;
1727 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
1728 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
1732 context
.vc_proc
= p
;
1733 context
.vc_ucred
= kauth_cred_get();
1736 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1737 if (uap
->uid
!= KAUTH_UID_NONE
)
1738 VATTR_SET(&va
, va_uid
, uap
->uid
);
1739 if (uap
->gid
!= KAUTH_GID_NONE
)
1740 VATTR_SET(&va
, va_gid
, uap
->gid
);
1741 if (xsecdst
!= KAUTH_FILESEC_NONE
)
1742 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
1744 ciferror
= mkfifo1(&context
, uap
->path
, &va
);
1746 if (xsecdst
!= KAUTH_FILESEC_NONE
)
1747 kauth_filesec_free(xsecdst
);
1753 mkfifo(struct proc
*p
, register struct mkfifo_args
*uap
, __unused register_t
*retval
)
1755 struct vfs_context context
;
1756 struct vnode_attr va
;
1758 context
.vc_proc
= p
;
1759 context
.vc_ucred
= kauth_cred_get();
1762 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1764 return(mkfifo1(&context
, uap
->path
, &va
));
1768 * Make a hard file link.
1772 link(struct proc
*p
, register struct link_args
*uap
, __unused register_t
*retval
)
1774 vnode_t vp
, dvp
, lvp
;
1775 struct nameidata nd
;
1776 struct vfs_context context
;
1779 int need_event
, has_listeners
;
1781 context
.vc_proc
= p
;
1782 context
.vc_ucred
= kauth_cred_get();
1783 vp
= dvp
= lvp
= NULLVP
;
1785 /* look up the object we are linking to */
1786 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1787 UIO_USERSPACE
, uap
->path
, &context
);
1795 /* we're not allowed to link to directories */
1796 if (vp
->v_type
== VDIR
) {
1797 error
= EPERM
; /* POSIX */
1801 /* or to anything that kauth doesn't want us to (eg. immutable items) */
1802 if ((error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_LINKTARGET
, &context
)) != 0)
1805 /* lookup the target node */
1806 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1807 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| AUDITVNPATH2
;
1808 nd
.ni_dirp
= uap
->link
;
1814 /* target node must not exist */
1815 if (lvp
!= NULLVP
) {
1819 /* cannot link across mountpoints */
1820 if (vnode_mount(vp
) != vnode_mount(dvp
)) {
1825 /* authorize creation of the target note */
1826 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
1829 /* and finally make the link */
1830 error
= VNOP_LINK(vp
, dvp
, &nd
.ni_cnd
, &context
);
1834 need_event
= need_fsevent(FSE_CREATE_FILE
, dvp
);
1835 has_listeners
= kauth_authorize_fileop_has_listeners();
1837 if (need_event
|| has_listeners
) {
1838 char *target_path
= NULL
;
1839 char *link_to_path
= NULL
;
1840 int len
, link_name_len
;
1842 /* build the path to the new link file */
1843 target_path
= get_pathbuff();
1845 vn_getpath(dvp
, target_path
, &len
);
1846 target_path
[len
-1] = '/';
1847 strcpy(&target_path
[len
], nd
.ni_cnd
.cn_nameptr
);
1848 len
+= nd
.ni_cnd
.cn_namelen
;
1850 if (has_listeners
) {
1851 /* build the path to file we are linking to */
1852 link_to_path
= get_pathbuff();
1853 link_name_len
= MAXPATHLEN
;
1854 vn_getpath(vp
, link_to_path
, &link_name_len
);
1856 /* call out to allow 3rd party notification of rename.
1857 * Ignore result of kauth_authorize_fileop call.
1859 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_LINK
,
1860 (uintptr_t)link_to_path
, (uintptr_t)target_path
);
1861 if (link_to_path
!= NULL
)
1862 release_pathbuff(link_to_path
);
1865 /* construct fsevent */
1866 if (get_fse_info(vp
, &finfo
, &context
) == 0) {
1867 // build the path to the destination of the link
1868 add_fsevent(FSE_CREATE_FILE
, &context
,
1869 FSE_ARG_STRING
, len
, target_path
,
1870 FSE_ARG_FINFO
, &finfo
,
1874 release_pathbuff(target_path
);
1878 * nameidone has to happen before we vnode_put(dvp)
1879 * since it may need to release the fs_nodelock on the dvp
1892 * Make a symbolic link.
1894 * We could add support for ACLs here too...
1898 symlink(struct proc
*p
, register struct symlink_args
*uap
, __unused register_t
*retval
)
1900 struct vnode_attr va
;
1903 struct nameidata nd
;
1904 struct vfs_context context
;
1908 context
.vc_proc
= p
;
1909 context
.vc_ucred
= kauth_cred_get();
1911 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1912 error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
);
1915 AUDIT_ARG(text
, path
); /* This is the link string */
1917 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1918 UIO_USERSPACE
, uap
->link
, &context
);
1927 VATTR_SET(&va
, va_type
, VLNK
);
1928 VATTR_SET(&va
, va_mode
, ACCESSPERMS
& ~p
->p_fd
->fd_cmask
);
1931 error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
);
1932 /* get default ownership, etc. */
1934 error
= vnode_authattr_new(dvp
, &va
, 0, &context
);
1936 error
= VNOP_SYMLINK(dvp
, &vp
, &nd
.ni_cnd
, &va
, path
, &context
);
1938 /* do fallback attribute handling */
1940 error
= vnode_setattr_fallback(vp
, &va
, &context
);
1943 int update_flags
= 0;
1946 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
1947 nd
.ni_cnd
.cn_flags
= 0;
1955 #if 0 /* XXX - kauth_todo - is KAUTH_FILEOP_SYMLINK needed? */
1956 /* call out to allow 3rd party notification of rename.
1957 * Ignore result of kauth_authorize_fileop call.
1959 if (kauth_authorize_fileop_has_listeners() &&
1961 char *new_link_path
= NULL
;
1964 /* build the path to the new link file */
1965 new_link_path
= get_pathbuff();
1967 vn_getpath(dvp
, new_link_path
, &len
);
1968 new_link_path
[len
- 1] = '/';
1969 strcpy(&new_link_path
[len
], nd
.ni_cnd
.cn_nameptr
);
1971 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_SYMLINK
,
1972 (uintptr_t)path
, (uintptr_t)new_link_path
);
1973 if (new_link_path
!= NULL
)
1974 release_pathbuff(new_link_path
);
1977 // Make sure the name & parent pointers are hooked up
1978 if (vp
->v_name
== NULL
)
1979 update_flags
|= VNODE_UPDATE_NAME
;
1980 if (vp
->v_parent
== NULLVP
)
1981 update_flags
|= VNODE_UPDATE_PARENT
;
1984 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
1986 add_fsevent(FSE_CREATE_FILE
, &context
,
1995 * nameidone has to happen before we vnode_put(dvp)
1996 * since it may need to release the fs_nodelock on the dvp
2004 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
2010 * Delete a whiteout from the filesystem.
2013 #warning XXX authorization not implmented for whiteouts
2015 undelete(struct proc
*p
, register struct undelete_args
*uap
, __unused register_t
*retval
)
2018 struct nameidata nd
;
2019 struct vfs_context context
;
2022 context
.vc_proc
= p
;
2023 context
.vc_ucred
= kauth_cred_get();
2025 NDINIT(&nd
, DELETE
, LOCKPARENT
|DOWHITEOUT
|AUDITVNPATH1
,
2026 UIO_USERSPACE
, uap
->path
, &context
);
2033 if (vp
== NULLVP
&& (nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
2034 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, DELETE
, &context
);
2039 * nameidone has to happen before we vnode_put(dvp)
2040 * since it may need to release the fs_nodelock on the dvp
2052 * Delete a name from the filesystem.
2056 _unlink(struct proc
*p
, struct unlink_args
*uap
, __unused register_t
*retval
, int nodelbusy
)
2060 struct nameidata nd
;
2061 struct vfs_context context
;
2062 struct componentname
*cnp
;
2065 context
.vc_proc
= p
;
2066 context
.vc_ucred
= kauth_cred_get();
2068 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
2069 UIO_USERSPACE
, uap
->path
, &context
);
2072 /* With Carbon delete semantics, busy files cannot be deleted */
2074 flags
|= VNODE_REMOVE_NODELETEBUSY
;
2082 if (vp
->v_type
== VDIR
) {
2083 error
= EPERM
; /* POSIX */
2086 * The root of a mounted filesystem cannot be deleted.
2088 if (vp
->v_flag
& VROOT
) {
2092 /* authorize the delete operation */
2094 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, &context
);
2101 if (need_fsevent(FSE_DELETE
, dvp
)) {
2102 path
= get_pathbuff();
2104 vn_getpath(vp
, path
, &len
);
2105 get_fse_info(vp
, &finfo
, &context
);
2107 error
= VNOP_REMOVE(dvp
, vp
, &nd
.ni_cnd
, flags
, &context
);
2109 if ( !error
&& path
!= NULL
) {
2110 add_fsevent(FSE_DELETE
, &context
,
2111 FSE_ARG_STRING
, len
, path
,
2112 FSE_ARG_FINFO
, &finfo
,
2116 release_pathbuff(path
);
2119 * nameidone has to happen before we vnode_put(dvp)
2120 * since it may need to release the fs_nodelock on the dvp
2129 * Delete a name from the filesystem using POSIX semantics.
2132 unlink(p
, uap
, retval
)
2134 struct unlink_args
*uap
;
2137 return _unlink(p
, uap
, retval
, 0);
2141 * Delete a name from the filesystem using Carbon semantics.
2144 delete(p
, uap
, retval
)
2146 struct delete_args
*uap
;
2149 return _unlink(p
, (struct unlink_args
*)uap
, retval
, 1);
2153 * Reposition read/write file offset.
2156 lseek(p
, uap
, retval
)
2158 register struct lseek_args
*uap
;
2161 struct fileproc
*fp
;
2163 struct vfs_context context
;
2164 off_t offset
= uap
->offset
, file_size
;
2167 if ( (error
= fp_getfvp(p
,uap
->fd
, &fp
, &vp
)) ) {
2168 if (error
== ENOTSUP
)
2172 if (vnode_isfifo(vp
)) {
2176 if ( (error
= vnode_getwithref(vp
)) ) {
2181 switch (uap
->whence
) {
2183 offset
+= fp
->f_fglob
->fg_offset
;
2186 context
.vc_proc
= p
;
2187 context
.vc_ucred
= kauth_cred_get();
2188 if ((error
= vnode_size(vp
, &file_size
, &context
)) != 0)
2190 offset
+= file_size
;
2198 if (uap
->offset
> 0 && offset
< 0) {
2199 /* Incremented/relative move past max size */
2203 * Allow negative offsets on character devices, per
2204 * POSIX 1003.1-2001. Most likely for writing disk
2207 if (offset
< 0 && vp
->v_type
!= VCHR
) {
2208 /* Decremented/relative move before start */
2212 fp
->f_fglob
->fg_offset
= offset
;
2213 *retval
= fp
->f_fglob
->fg_offset
;
2217 (void)vnode_put(vp
);
2224 * Check access permissions.
2227 access1(vnode_t vp
, vnode_t dvp
, int uflags
, vfs_context_t ctx
)
2229 kauth_action_t action
;
2233 * If just the regular access bits, convert them to something
2234 * that vnode_authorize will understand.
2236 if (!(uflags
& _ACCESS_EXTENDED_MASK
)) {
2239 action
|= KAUTH_VNODE_READ_DATA
; /* aka KAUTH_VNODE_LIST_DIRECTORY */
2240 if (uflags
& W_OK
) {
2241 if (vnode_isdir(vp
)) {
2242 action
|= KAUTH_VNODE_ADD_FILE
|
2243 KAUTH_VNODE_ADD_SUBDIRECTORY
;
2244 /* might want delete rights here too */
2246 action
|= KAUTH_VNODE_WRITE_DATA
;
2249 if (uflags
& X_OK
) {
2250 if (vnode_isdir(vp
)) {
2251 action
|= KAUTH_VNODE_SEARCH
;
2253 action
|= KAUTH_VNODE_EXECUTE
;
2257 /* take advantage of definition of uflags */
2258 action
= uflags
>> 8;
2261 /* action == 0 means only check for existence */
2263 error
= vnode_authorize(vp
, dvp
, action
| KAUTH_VNODE_ACCESS
, ctx
);
2273 /* XXX need to support the check-as uid argument */
2275 access_extended(__unused
struct proc
*p
, struct access_extended_args
*uap
, __unused register_t
*retval
)
2277 struct accessx_descriptor
*input
;
2279 int error
, limit
, nent
, i
, j
, wantdelete
;
2280 struct vfs_context context
;
2281 struct nameidata nd
;
2290 context
.vc_ucred
= NULL
;
2292 /* check input size and fetch descriptor array into allocated storage */
2293 if (uap
->size
> ACCESSX_MAX_TABLESIZE
)
2295 if (uap
->size
< sizeof(struct accessx_descriptor
))
2297 MALLOC(input
, struct accessx_descriptor
*, uap
->size
, M_TEMP
, M_WAITOK
);
2298 if (input
== NULL
) {
2302 error
= copyin(uap
->entries
, input
, uap
->size
);
2307 * Access is defined as checking against the process'
2308 * real identity, even if operations are checking the
2309 * effective identity. So we need to tweak the credential
2312 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
2313 context
.vc_proc
= current_proc();
2316 * Find out how many entries we have, so we can allocate the result array.
2318 limit
= uap
->size
/ sizeof(struct accessx_descriptor
);
2321 for (i
= 0; i
< nent
; i
++) {
2323 * Take the offset to the name string for this entry and convert to an
2324 * input array index, which would be one off the end of the array if this
2325 * was the lowest-addressed name string.
2327 j
= input
[i
].ad_name_offset
/ sizeof(struct accessx_descriptor
);
2333 /* implicit reference to previous name, not a real offset */
2335 /* first entry must have a name string */
2345 if (nent
> ACCESSX_MAX_DESCRIPTORS
) {
2349 MALLOC(result
, errno_t
*, nent
* sizeof(errno_t
), M_TEMP
, M_WAITOK
);
2350 if (result
== NULL
) {
2359 for (i
= 0; i
< nent
; i
++) {
2361 * Looking up a new name?
2363 if (input
[i
].ad_name_offset
!= 0) {
2364 /* discard old vnodes */
2374 /* scan forwards to see if we need the parent this time */
2375 wantdelete
= input
[i
].ad_flags
& _DELETE_OK
;
2376 for (j
= i
+ 1; (j
< nent
) && (input
[j
].ad_name_offset
== 0); j
++)
2377 if (input
[j
].ad_flags
& _DELETE_OK
)
2380 niopts
= FOLLOW
| AUDITVNPATH1
;
2381 /* need parent for vnode_authorize for deletion test */
2383 niopts
|= WANTPARENT
;
2386 NDINIT(&nd
, LOOKUP
, niopts
, UIO_SYSSPACE
, CAST_USER_ADDR_T((const char *)input
+ input
[i
].ad_name_offset
), &context
);
2397 * Handle lookup errors.
2407 /* run this access check */
2408 result
[i
] = access1(vp
, dvp
, input
[i
].ad_flags
, &context
);
2411 /* fatal lookup error */
2417 /* copy out results */
2418 error
= copyout(result
, uap
->results
, nent
* sizeof(errno_t
));
2422 FREE(input
, M_TEMP
);
2424 FREE(result
, M_TEMP
);
2429 if (context
.vc_ucred
)
2430 kauth_cred_rele(context
.vc_ucred
);
2435 access(__unused
struct proc
*p
, register struct access_args
*uap
, __unused register_t
*retval
)
2438 struct nameidata nd
;
2440 struct vfs_context context
;
2443 * Access is defined as checking against the process'
2444 * real identity, even if operations are checking the
2445 * effective identity. So we need to tweak the credential
2448 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
2449 context
.vc_proc
= current_proc();
2451 niopts
= FOLLOW
| AUDITVNPATH1
;
2452 /* need parent for vnode_authorize for deletion test */
2453 if (uap
->flags
& _DELETE_OK
)
2454 niopts
|= WANTPARENT
;
2455 NDINIT(&nd
, LOOKUP
, niopts
, UIO_USERSPACE
, uap
->path
, &context
);
2460 error
= access1(nd
.ni_vp
, nd
.ni_dvp
, uap
->flags
, &context
);
2462 vnode_put(nd
.ni_vp
);
2463 if (uap
->flags
& _DELETE_OK
)
2464 vnode_put(nd
.ni_dvp
);
2468 kauth_cred_rele(context
.vc_ucred
);
2474 stat2(vfs_context_t ctx
, struct nameidata
*ndp
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2477 struct user_stat user_sb
;
2480 kauth_filesec_t fsec
;
2481 size_t xsecurity_bufsize
;
2486 fsec
= KAUTH_FILESEC_NONE
;
2487 error
= vn_stat(ndp
->ni_vp
, &sb
, (xsecurity
!= USER_ADDR_NULL
? &fsec
: NULL
), ctx
);
2488 vnode_put(ndp
->ni_vp
);
2493 /* Zap spare fields */
2495 sb
.st_qspare
[0] = 0LL;
2496 sb
.st_qspare
[1] = 0LL;
2497 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
2498 munge_stat(&sb
, &user_sb
);
2499 my_size
= sizeof(user_sb
);
2500 sbp
= (caddr_t
)&user_sb
;
2503 my_size
= sizeof(sb
);
2506 if ((error
= copyout(sbp
, ub
, my_size
)) != 0)
2509 /* caller wants extended security information? */
2510 if (xsecurity
!= USER_ADDR_NULL
) {
2512 /* did we get any? */
2513 if (fsec
== KAUTH_FILESEC_NONE
) {
2514 if (susize(xsecurity_size
, 0) != 0) {
2519 /* find the user buffer size */
2520 xsecurity_bufsize
= fusize(xsecurity_size
);
2522 /* copy out the actual data size */
2523 if (susize(xsecurity_size
, KAUTH_FILESEC_COPYSIZE(fsec
)) != 0) {
2528 /* if the caller supplied enough room, copy out to it */
2529 if (xsecurity_bufsize
>= KAUTH_FILESEC_COPYSIZE(fsec
))
2530 error
= copyout(fsec
, xsecurity
, KAUTH_FILESEC_COPYSIZE(fsec
));
2534 if (fsec
!= KAUTH_FILESEC_NONE
)
2535 kauth_filesec_free(fsec
);
2540 * Get file status; this version follows links.
2543 stat1(struct proc
*p
, user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2545 struct nameidata nd
;
2546 struct vfs_context context
;
2548 context
.vc_proc
= p
;
2549 context
.vc_ucred
= kauth_cred_get();
2551 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2552 UIO_USERSPACE
, path
, &context
);
2553 return(stat2(&context
, &nd
, ub
, xsecurity
, xsecurity_size
));
2557 stat_extended(struct proc
*p
, struct stat_extended_args
*uap
, __unused register_t
*retval
)
2559 return (stat1(p
, uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
));
2563 stat(struct proc
*p
, struct stat_args
*uap
, __unused register_t
*retval
)
2565 return(stat1(p
, uap
->path
, uap
->ub
, 0, 0));
2569 * Get file status; this version does not follow links.
2572 lstat1(struct proc
*p
, user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2574 struct nameidata nd
;
2575 struct vfs_context context
;
2577 context
.vc_proc
= p
;
2578 context
.vc_ucred
= kauth_cred_get();
2580 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
2581 UIO_USERSPACE
, path
, &context
);
2583 return(stat2(&context
, &nd
, ub
, xsecurity
, xsecurity_size
));
2587 lstat_extended(struct proc
*p
, struct lstat_extended_args
*uap
, __unused register_t
*retval
)
2589 return (lstat1(p
, uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
));
2593 lstat(struct proc
*p
, struct lstat_args
*uap
, __unused register_t
*retval
)
2595 return(lstat1(p
, uap
->path
, uap
->ub
, 0, 0));
2599 * Get configurable pathname variables.
2603 pathconf(p
, uap
, retval
)
2605 register struct pathconf_args
*uap
;
2609 struct nameidata nd
;
2610 struct vfs_context context
;
2612 context
.vc_proc
= p
;
2613 context
.vc_ucred
= kauth_cred_get();
2615 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2616 UIO_USERSPACE
, uap
->path
, &context
);
2621 error
= vn_pathconf(nd
.ni_vp
, uap
->name
, retval
, &context
);
2623 vnode_put(nd
.ni_vp
);
2629 * Return target name of a symbolic link.
2633 readlink(p
, uap
, retval
)
2635 register struct readlink_args
*uap
;
2638 register struct vnode
*vp
;
2640 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
2642 struct nameidata nd
;
2643 struct vfs_context context
;
2644 char uio_buf
[ UIO_SIZEOF(1) ];
2646 context
.vc_proc
= p
;
2647 context
.vc_ucred
= kauth_cred_get();
2649 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
2650 UIO_USERSPACE
, uap
->path
, &context
);
2658 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
2659 &uio_buf
[0], sizeof(uio_buf
));
2660 uio_addiov(auio
, uap
->buf
, uap
->count
);
2661 if (vp
->v_type
!= VLNK
)
2664 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, &context
);
2666 error
= VNOP_READLINK(vp
, auio
, &context
);
2669 // LP64todo - fix this
2670 *retval
= uap
->count
- (int)uio_resid(auio
);
2675 * Change file flags.
2678 chflags1(vnode_t vp
, int flags
, vfs_context_t ctx
)
2680 struct vnode_attr va
;
2681 kauth_action_t action
;
2685 VATTR_SET(&va
, va_flags
, flags
);
2687 /* request authorisation, disregard immutability */
2688 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
2691 * Request that the auth layer disregard those file flags it's allowed to when
2692 * authorizing this operation; we need to do this in order to be able to
2693 * clear immutable flags.
2695 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
| KAUTH_VNODE_NOIMMUTABLE
, ctx
)) != 0))
2697 error
= vnode_setattr(vp
, &va
, ctx
);
2705 * Change flags of a file given a path name.
2709 chflags(struct proc
*p
, register struct chflags_args
*uap
, __unused register_t
*retval
)
2711 register struct vnode
*vp
;
2712 struct vfs_context context
;
2714 struct nameidata nd
;
2716 context
.vc_proc
= p
;
2717 context
.vc_ucred
= kauth_cred_get();
2719 AUDIT_ARG(fflags
, uap
->flags
);
2720 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2721 UIO_USERSPACE
, uap
->path
, &context
);
2728 error
= chflags1(vp
, uap
->flags
, &context
);
2734 * Change flags of a file given a file descriptor.
2738 fchflags(struct proc
*p
, register struct fchflags_args
*uap
, __unused register_t
*retval
)
2740 struct vfs_context context
;
2744 AUDIT_ARG(fd
, uap
->fd
);
2745 AUDIT_ARG(fflags
, uap
->flags
);
2746 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
2749 if ((error
= vnode_getwithref(vp
))) {
2754 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2756 context
.vc_proc
= p
;
2757 context
.vc_ucred
= kauth_cred_get();
2759 error
= chflags1(vp
, uap
->flags
, &context
);
2766 * Change security information on a filesystem object.
2769 chmod2(vfs_context_t ctx
, struct vnode
*vp
, struct vnode_attr
*vap
)
2771 kauth_action_t action
;
2774 AUDIT_ARG(mode
, (mode_t
)vap
->va_mode
);
2775 #warning XXX audit new args
2777 /* make sure that the caller is allowed to set this security information */
2778 if (((error
= vnode_authattr(vp
, vap
, &action
, ctx
)) != 0) ||
2779 ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
2780 if (error
== EACCES
)
2785 error
= vnode_setattr(vp
, vap
, ctx
);
2792 * Change mode of a file given path name.
2795 chmod1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
2797 struct nameidata nd
;
2800 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2801 UIO_USERSPACE
, path
, ctx
);
2802 if ((error
= namei(&nd
)))
2804 error
= chmod2(ctx
, nd
.ni_vp
, vap
);
2805 vnode_put(nd
.ni_vp
);
2811 chmod_extended(struct proc
*p
, struct chmod_extended_args
*uap
, __unused register_t
*retval
)
2813 struct vfs_context context
;
2815 struct vnode_attr va
;
2816 kauth_filesec_t xsecdst
;
2819 if (uap
->mode
!= -1)
2820 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2821 if (uap
->uid
!= KAUTH_UID_NONE
)
2822 VATTR_SET(&va
, va_uid
, uap
->uid
);
2823 if (uap
->gid
!= KAUTH_GID_NONE
)
2824 VATTR_SET(&va
, va_gid
, uap
->gid
);
2827 switch(uap
->xsecurity
) {
2828 /* explicit remove request */
2829 case CAST_USER_ADDR_T((void *)1): /* _FILESEC_REMOVE_ACL */
2830 VATTR_SET(&va
, va_acl
, NULL
);
2833 case USER_ADDR_NULL
:
2836 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
2838 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2839 KAUTH_DEBUG("CHMOD - setting ACL with %d entries", va
.va_acl
->acl_entrycount
);
2841 context
.vc_proc
= p
;
2842 context
.vc_ucred
= kauth_cred_get();
2844 error
= chmod1(&context
, uap
->path
, &va
);
2846 if (xsecdst
!= NULL
)
2847 kauth_filesec_free(xsecdst
);
2852 chmod(struct proc
*p
, register struct chmod_args
*uap
, __unused register_t
*retval
)
2854 struct vfs_context context
;
2855 struct vnode_attr va
;
2858 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2860 context
.vc_proc
= p
;
2861 context
.vc_ucred
= kauth_cred_get();
2863 return(chmod1(&context
, uap
->path
, &va
));
2867 * Change mode of a file given a file descriptor.
2870 fchmod1(struct proc
*p
, int fd
, struct vnode_attr
*vap
)
2874 struct vfs_context context
;
2876 context
.vc_proc
= p
;
2877 context
.vc_ucred
= kauth_cred_get();
2881 if ((error
= file_vnode(fd
, &vp
)) != 0)
2883 if ((error
= vnode_getwithref(vp
)) != 0) {
2887 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2889 error
= chmod2(&context
, vp
, vap
);
2890 (void)vnode_put(vp
);
2897 fchmod_extended(struct proc
*p
, struct fchmod_extended_args
*uap
, __unused register_t
*retval
)
2900 struct vnode_attr va
;
2901 kauth_filesec_t xsecdst
;
2904 if (uap
->mode
!= -1)
2905 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2906 if (uap
->uid
!= KAUTH_UID_NONE
)
2907 VATTR_SET(&va
, va_uid
, uap
->uid
);
2908 if (uap
->gid
!= KAUTH_GID_NONE
)
2909 VATTR_SET(&va
, va_gid
, uap
->gid
);
2912 switch(uap
->xsecurity
) {
2913 case USER_ADDR_NULL
:
2914 VATTR_SET(&va
, va_acl
, NULL
);
2916 case CAST_USER_ADDR_T(-1):
2919 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
2921 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2924 error
= fchmod1(p
, uap
->fd
, &va
);
2927 switch(uap
->xsecurity
) {
2928 case USER_ADDR_NULL
:
2929 case CAST_USER_ADDR_T(-1):
2932 if (xsecdst
!= NULL
)
2933 kauth_filesec_free(xsecdst
);
2939 fchmod(struct proc
*p
, register struct fchmod_args
*uap
, __unused register_t
*retval
)
2941 struct vnode_attr va
;
2944 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2946 return(fchmod1(p
, uap
->fd
, &va
));
2951 * Set ownership given a path name.
2955 chown1(vfs_context_t ctx
, register struct chown_args
*uap
, __unused register_t
*retval
, int follow
)
2957 register struct vnode
*vp
;
2958 struct vnode_attr va
;
2960 struct nameidata nd
;
2961 kauth_action_t action
;
2963 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
2965 NDINIT(&nd
, LOOKUP
, (follow
? FOLLOW
: 0) | AUDITVNPATH1
,
2966 UIO_USERSPACE
, uap
->path
, ctx
);
2975 * XXX A TEMPORARY HACK FOR NOW: Try to track console_user
2976 * by looking for chown() calls on /dev/console from a console process.
2978 if ((vp
) && (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
) && (vp
->v_specinfo
) &&
2979 (major(vp
->v_specinfo
->si_rdev
) == CONSMAJOR
) &&
2980 (minor(vp
->v_specinfo
->si_rdev
) == 0)) {
2981 console_user
= uap
->uid
;
2984 if (uap
->uid
!= VNOVAL
)
2985 VATTR_SET(&va
, va_uid
, uap
->uid
);
2986 if (uap
->gid
!= VNOVAL
)
2987 VATTR_SET(&va
, va_gid
, uap
->gid
);
2989 /* preflight and authorize attribute changes */
2990 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
2992 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
2994 error
= vnode_setattr(vp
, &va
, ctx
);
2998 * EACCES is only allowed from namei(); permissions failure should
2999 * return EPERM, so we need to translate the error code.
3001 if (error
== EACCES
)
3009 chown(struct proc
*p
, register struct chown_args
*uap
, register_t
*retval
)
3011 struct vfs_context context
;
3013 context
.vc_proc
= p
;
3014 context
.vc_ucred
= kauth_cred_get();
3016 return chown1(&context
, uap
, retval
, 1);
3020 lchown(struct proc
*p
, register struct lchown_args
*uap
, register_t
*retval
)
3022 struct vfs_context context
;
3024 context
.vc_proc
= p
;
3025 context
.vc_ucred
= kauth_cred_get();
3027 /* Argument list identical, but machine generated; cast for chown1() */
3028 return chown1(&context
, (struct chown_args
*)uap
, retval
, 0);
3032 * Set ownership given a file descriptor.
3036 fchown(struct proc
*p
, register struct fchown_args
*uap
, __unused register_t
*retval
)
3038 struct vnode_attr va
;
3039 struct vfs_context context
;
3042 kauth_action_t action
;
3044 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
3045 AUDIT_ARG(fd
, uap
->fd
);
3047 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
3050 if ( (error
= vnode_getwithref(vp
)) ) {
3054 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3057 if (uap
->uid
!= VNOVAL
)
3058 VATTR_SET(&va
, va_uid
, uap
->uid
);
3059 if (uap
->gid
!= VNOVAL
)
3060 VATTR_SET(&va
, va_gid
, uap
->gid
);
3062 context
.vc_proc
= p
;
3063 context
.vc_ucred
= kauth_cred_get();
3065 /* preflight and authorize attribute changes */
3066 if ((error
= vnode_authattr(vp
, &va
, &action
, &context
)) != 0)
3068 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0)) {
3069 if (error
== EACCES
)
3073 error
= vnode_setattr(vp
, &va
, &context
);
3076 (void)vnode_put(vp
);
3082 getutimes(usrtvp
, tsp
)
3084 struct timespec
*tsp
;
3086 struct user_timeval tv
[2];
3089 if (usrtvp
== USER_ADDR_NULL
) {
3090 struct timeval old_tv
;
3091 /* XXX Y2038 bug because of microtime argument */
3093 TIMEVAL_TO_TIMESPEC(&old_tv
, &tsp
[0]);
3096 if (IS_64BIT_PROCESS(current_proc())) {
3097 error
= copyin(usrtvp
, (void *)tv
, sizeof(tv
));
3099 struct timeval old_tv
[2];
3100 error
= copyin(usrtvp
, (void *)old_tv
, sizeof(old_tv
));
3101 tv
[0].tv_sec
= old_tv
[0].tv_sec
;
3102 tv
[0].tv_usec
= old_tv
[0].tv_usec
;
3103 tv
[1].tv_sec
= old_tv
[1].tv_sec
;
3104 tv
[1].tv_usec
= old_tv
[1].tv_usec
;
3108 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
3109 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
3115 setutimes(vfs_context_t ctx
, struct vnode
*vp
, const struct timespec
*ts
,
3119 struct vnode_attr va
;
3120 kauth_action_t action
;
3122 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3125 VATTR_SET(&va
, va_access_time
, ts
[0]);
3126 VATTR_SET(&va
, va_modify_time
, ts
[1]);
3128 va
.va_vaflags
|= VA_UTIMES_NULL
;
3130 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
3132 /* since we may not need to auth anything, check here */
3133 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
3135 error
= vnode_setattr(vp
, &va
, ctx
);
3142 * Set the access and modification times of a file.
3146 utimes(struct proc
*p
, register struct utimes_args
*uap
, __unused register_t
*retval
)
3148 struct timespec ts
[2];
3151 struct nameidata nd
;
3152 struct vfs_context context
;
3154 context
.vc_proc
= p
;
3155 context
.vc_ucred
= kauth_cred_get();
3157 /* AUDIT: Needed to change the order of operations to do the
3158 * name lookup first because auditing wants the path.
3160 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3161 UIO_USERSPACE
, uap
->path
, &context
);
3168 * Fetch the user-supplied time. If usrtvp is USER_ADDR_NULL, we fetch
3169 * the current time instead.
3172 if ((error
= getutimes(usrtvp
, ts
)) != 0)
3175 error
= setutimes(&context
, nd
.ni_vp
, ts
, usrtvp
== USER_ADDR_NULL
);
3178 vnode_put(nd
.ni_vp
);
3183 * Set the access and modification times of a file.
3187 futimes(struct proc
*p
, register struct futimes_args
*uap
, __unused register_t
*retval
)
3189 struct timespec ts
[2];
3193 struct vfs_context context
;
3195 context
.vc_proc
= p
;
3196 context
.vc_ucred
= kauth_cred_get();
3198 AUDIT_ARG(fd
, uap
->fd
);
3200 if ((error
= getutimes(usrtvp
, ts
)) != 0)
3202 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
3204 if((error
= vnode_getwithref(vp
))) {
3209 error
= setutimes(&context
, vp
, ts
, usrtvp
== 0);
3216 * Truncate a file given its path name.
3220 truncate(struct proc
*p
, register struct truncate_args
*uap
, __unused register_t
*retval
)
3222 register struct vnode
*vp
;
3223 struct vnode_attr va
;
3224 struct vfs_context context
;
3226 struct nameidata nd
;
3227 kauth_action_t action
;
3229 context
.vc_proc
= p
;
3230 context
.vc_ucred
= kauth_cred_get();
3232 if (uap
->length
< 0)
3234 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3235 UIO_USERSPACE
, uap
->path
, &context
);
3236 if ((error
= namei(&nd
)))
3243 VATTR_SET(&va
, va_data_size
, uap
->length
);
3244 if ((error
= vnode_authattr(vp
, &va
, &action
, &context
)) != 0)
3246 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0))
3248 error
= vnode_setattr(vp
, &va
, &context
);
3255 * Truncate a file given a file descriptor.
3259 ftruncate(p
, uap
, retval
)
3261 register struct ftruncate_args
*uap
;
3264 struct vfs_context context
;
3265 struct vnode_attr va
;
3267 struct fileproc
*fp
;
3271 context
.vc_proc
= current_proc();
3272 context
.vc_ucred
= kauth_cred_get();
3274 AUDIT_ARG(fd
, uap
->fd
);
3275 if (uap
->length
< 0)
3278 if ( (error
= fp_lookup(p
,fd
,&fp
,0)) ) {
3282 if (fp
->f_fglob
->fg_type
== DTYPE_PSXSHM
) {
3283 error
= pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
);
3286 if (fp
->f_fglob
->fg_type
!= DTYPE_VNODE
) {
3291 vp
= (struct vnode
*)fp
->f_fglob
->fg_data
;
3293 if ((fp
->f_fglob
->fg_flag
& FWRITE
) == 0) {
3294 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
3299 if ((error
= vnode_getwithref(vp
)) != 0) {
3303 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3306 VATTR_SET(&va
, va_data_size
, uap
->length
);
3307 error
= vnode_setattr(vp
, &va
, &context
);
3308 (void)vnode_put(vp
);
3316 * Sync an open file.
3320 fsync(struct proc
*p
, struct fsync_args
*uap
, __unused register_t
*retval
)
3323 struct fileproc
*fp
;
3324 struct vfs_context context
;
3327 if ( (error
= fp_getfvp(p
, uap
->fd
, &fp
, &vp
)) )
3329 if ( (error
= vnode_getwithref(vp
)) ) {
3333 context
.vc_proc
= p
;
3334 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
3336 error
= VNOP_FSYNC(vp
, MNT_WAIT
, &context
);
3338 (void)vnode_put(vp
);
3344 * Duplicate files. Source must be a file, target must be a file or
3347 * XXX Copyfile authorisation checking is woefully inadequate, and will not
3348 * perform inheritance correctly.
3352 copyfile(struct proc
*p
, register struct copyfile_args
*uap
, __unused register_t
*retval
)
3354 vnode_t tvp
, fvp
, tdvp
, sdvp
;
3355 struct nameidata fromnd
, tond
;
3357 struct vfs_context context
;
3359 context
.vc_proc
= p
;
3360 context
.vc_ucred
= kauth_cred_get();
3362 /* Check that the flags are valid. */
3364 if (uap
->flags
& ~CPF_MASK
) {
3368 NDINIT(&fromnd
, LOOKUP
, SAVESTART
| AUDITVNPATH1
,
3369 UIO_USERSPACE
, uap
->from
, &context
);
3370 if ((error
= namei(&fromnd
)))
3374 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
| AUDITVNPATH2
,
3375 UIO_USERSPACE
, uap
->to
, &context
);
3376 if ((error
= namei(&tond
))) {
3383 if (!(uap
->flags
& CPF_OVERWRITE
)) {
3388 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
3393 if ((error
= vnode_authorize(tdvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
3399 * If source is the same as the destination (that is the
3400 * same inode number) then there is nothing to do.
3401 * (fixed to have POSIX semantics - CSM 3/2/98)
3406 error
= VNOP_COPYFILE(fvp
,tdvp
,tvp
,&tond
.ni_cnd
,uap
->mode
,uap
->flags
,&context
);
3408 sdvp
= tond
.ni_startdir
;
3410 * nameidone has to happen before we vnode_put(tdvp)
3411 * since it may need to release the fs_nodelock on the tdvp
3422 if (fromnd
.ni_startdir
)
3423 vnode_put(fromnd
.ni_startdir
);
3433 * Rename files. Source and destination must either both be directories,
3434 * or both not be directories. If target is a directory, it must be empty.
3438 rename(proc_t p
, register struct rename_args
*uap
, __unused register_t
*retval
)
3442 struct nameidata fromnd
, tond
;
3443 struct vfs_context context
;
3446 char *oname
, *from_name
, *to_name
;
3447 int from_len
, to_len
;
3448 int holding_mntlock
;
3449 mount_t locked_mp
= NULL
;
3451 fse_info from_finfo
, to_finfo
;
3453 context
.vc_proc
= p
;
3454 context
.vc_ucred
= kauth_cred_get();
3455 holding_mntlock
= 0;
3461 NDINIT(&fromnd
, DELETE
, WANTPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->from
, &context
);
3463 if ( (error
= namei(&fromnd
)) )
3465 fdvp
= fromnd
.ni_dvp
;
3468 NDINIT(&tond
, RENAME
, WANTPARENT
| AUDITVNPATH2
, UIO_USERSPACE
, uap
->to
, &context
);
3469 if (fvp
->v_type
== VDIR
)
3470 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
3472 if ( (error
= namei(&tond
)) ) {
3474 * Translate error code for rename("dir1", "dir2/.").
3476 if (error
== EISDIR
&& fvp
->v_type
== VDIR
)
3484 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
3487 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
3500 * If tvp is a directory and not the same as fdvp, or tdvp is not the same as fdvp,
3501 * the node is moving between directories and we need rights to remove from the
3502 * old and add to the new.
3504 * If tvp already exists and is not a directory, we need to be allowed to delete it.
3506 * Note that we do not inherit when renaming. XXX this needs to be revisited to
3507 * implement the deferred-inherit bit.
3513 if ((tvp
!= NULL
) && vnode_isdir(tvp
)) {
3516 } else if (tdvp
!= fdvp
) {
3520 * must have delete rights to remove the old name even in the simple case of
3523 if ((error
= vnode_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
, &context
)) != 0)
3526 /* moving into tdvp or tvp, must have rights to add */
3527 if ((error
= vnode_authorize(((tvp
!= NULL
) && vnode_isdir(tvp
)) ? tvp
: tdvp
,
3529 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
3533 /* node staying in same directory, must be allowed to add new name */
3534 if ((error
= vnode_authorize(fdvp
, NULL
,
3535 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
3538 /* overwriting tvp */
3539 if ((tvp
!= NULL
) && !vnode_isdir(tvp
) &&
3540 ((error
= vnode_authorize(tvp
, tdvp
, KAUTH_VNODE_DELETE
, &context
)) != 0))
3543 /* XXX more checks? */
3546 /* authorization denied */
3551 * Allow the renaming of mount points.
3552 * - target must not exist
3553 * - target must reside in the same directory as source
3554 * - union mounts cannot be renamed
3555 * - "/" cannot be renamed
3557 if ((fvp
->v_flag
& VROOT
) &&
3558 (fvp
->v_type
== VDIR
) &&
3560 (fvp
->v_mountedhere
== NULL
) &&
3562 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
3563 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
3564 struct vnode
*coveredvp
;
3566 /* switch fvp to the covered vnode */
3567 coveredvp
= fvp
->v_mount
->mnt_vnodecovered
;
3568 if ( (vnode_getwithref(coveredvp
)) ) {
3578 * Check for cross-device rename.
3580 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
3581 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
3586 * Avoid renaming "." and "..".
3588 if (fvp
->v_type
== VDIR
&&
3590 (fromnd
.ni_cnd
.cn_namelen
== 1 && fromnd
.ni_cnd
.cn_nameptr
[0] == '.') ||
3591 ((fromnd
.ni_cnd
.cn_flags
| tond
.ni_cnd
.cn_flags
) & ISDOTDOT
)) ) {
3596 * The following edge case is caught here:
3597 * (to cannot be a descendent of from)
3610 if (tdvp
->v_parent
== fvp
) {
3616 * If source is the same as the destination (that is the
3617 * same inode number) then there is nothing to do...
3618 * EXCEPT if the underlying file system supports case
3619 * insensitivity and is case preserving. In this case
3620 * the file system needs to handle the special case of
3621 * getting the same vnode as target (fvp) and source (tvp).
3623 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
3624 * and _PC_CASE_PRESERVING can have this exception, and they need to
3625 * handle the special case of getting the same vnode as target and
3626 * source. NOTE: Then the target is unlocked going into vnop_rename,
3627 * so not to cause locking problems. There is a single reference on tvp.
3629 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
3630 * that correct behaviour then is just to remove the source (link)
3632 if (fvp
== tvp
&& fdvp
== tdvp
) {
3633 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
3634 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
3635 fromnd
.ni_cnd
.cn_namelen
)) {
3640 if (holding_mntlock
&& fvp
->v_mount
!= locked_mp
) {
3642 * we're holding a reference and lock
3643 * on locked_mp, but it no longer matches
3644 * what we want to do... so drop our hold
3646 mount_unlock_renames(locked_mp
);
3647 mount_drop(locked_mp
, 0);
3648 holding_mntlock
= 0;
3650 if (tdvp
!= fdvp
&& fvp
->v_type
== VDIR
) {
3652 * serialize renames that re-shape
3653 * the tree... if holding_mntlock is
3654 * set, then we're ready to go...
3656 * first need to drop the iocounts
3657 * we picked up, second take the
3658 * lock to serialize the access,
3659 * then finally start the lookup
3660 * process over with the lock held
3662 if (!holding_mntlock
) {
3664 * need to grab a reference on
3665 * the mount point before we
3666 * drop all the iocounts... once
3667 * the iocounts are gone, the mount
3670 locked_mp
= fvp
->v_mount
;
3671 mount_ref(locked_mp
, 0);
3674 * nameidone has to happen before we vnode_put(tvp)
3675 * since it may need to release the fs_nodelock on the tvp
3684 * nameidone has to happen before we vnode_put(fdvp)
3685 * since it may need to release the fs_nodelock on the fvp
3692 mount_lock_renames(locked_mp
);
3693 holding_mntlock
= 1;
3699 * when we dropped the iocounts to take
3700 * the lock, we allowed the identity of
3701 * the various vnodes to change... if they did,
3702 * we may no longer be dealing with a rename
3703 * that reshapes the tree... once we're holding
3704 * the iocounts, the vnodes can't change type
3705 * so we're free to drop the lock at this point
3708 if (holding_mntlock
) {
3709 mount_unlock_renames(locked_mp
);
3710 mount_drop(locked_mp
, 0);
3711 holding_mntlock
= 0;
3714 // save these off so we can later verify that fvp is the same
3715 oname
= fvp
->v_name
;
3716 oparent
= fvp
->v_parent
;
3718 if (need_fsevent(FSE_RENAME
, fvp
)) {
3719 get_fse_info(fvp
, &from_finfo
, &context
);
3722 get_fse_info(tvp
, &to_finfo
, &context
);
3724 from_name
= get_pathbuff();
3725 from_len
= MAXPATHLEN
;
3726 vn_getpath(fvp
, from_name
, &from_len
);
3728 to_name
= get_pathbuff();
3729 to_len
= MAXPATHLEN
;
3731 if (tvp
&& tvp
->v_type
!= VDIR
) {
3732 vn_getpath(tvp
, to_name
, &to_len
);
3734 vn_getpath(tdvp
, to_name
, &to_len
);
3735 // if the path is not just "/", then append a "/"
3737 to_name
[to_len
-1] = '/';
3741 strcpy(&to_name
[to_len
], tond
.ni_cnd
.cn_nameptr
);
3742 to_len
+= tond
.ni_cnd
.cn_namelen
+ 1;
3743 to_name
[to_len
] = '\0';
3749 error
= VNOP_RENAME(fdvp
, fvp
, &fromnd
.ni_cnd
,
3750 tdvp
, tvp
, &tond
.ni_cnd
,
3753 if (holding_mntlock
) {
3755 * we can drop our serialization
3758 mount_unlock_renames(locked_mp
);
3759 mount_drop(locked_mp
, 0);
3760 holding_mntlock
= 0;
3763 if (to_name
!= NULL
)
3764 release_pathbuff(to_name
);
3765 if (from_name
!= NULL
)
3766 release_pathbuff(from_name
);
3767 from_name
= to_name
= NULL
;
3772 /* call out to allow 3rd party notification of rename.
3773 * Ignore result of kauth_authorize_fileop call.
3775 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_RENAME
,
3776 (uintptr_t)from_name
, (uintptr_t)to_name
);
3778 if (from_name
!= NULL
&& to_name
!= NULL
) {
3780 add_fsevent(FSE_RENAME
, &context
,
3781 FSE_ARG_STRING
, from_len
, from_name
,
3782 FSE_ARG_FINFO
, &from_finfo
,
3783 FSE_ARG_STRING
, to_len
, to_name
,
3784 FSE_ARG_FINFO
, &to_finfo
,
3787 add_fsevent(FSE_RENAME
, &context
,
3788 FSE_ARG_STRING
, from_len
, from_name
,
3789 FSE_ARG_FINFO
, &from_finfo
,
3790 FSE_ARG_STRING
, to_len
, to_name
,
3794 if (to_name
!= NULL
)
3795 release_pathbuff(to_name
);
3796 if (from_name
!= NULL
)
3797 release_pathbuff(from_name
);
3798 from_name
= to_name
= NULL
;
3801 * update filesystem's mount point data
3804 char *cp
, *pathend
, *mpname
;
3810 mp
= fvp
->v_mountedhere
;
3812 if (vfs_busy(mp
, LK_NOWAIT
)) {
3816 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
3818 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
3820 /* find current mount point prefix */
3821 pathend
= &mp
->mnt_vfsstat
.f_mntonname
[0];
3822 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
3826 /* find last component of target name */
3827 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
3831 /* append name to prefix */
3832 maxlen
= MAXPATHLEN
- (pathend
- mp
->mnt_vfsstat
.f_mntonname
);
3833 bzero(pathend
, maxlen
);
3834 strncpy(pathend
, mpname
, maxlen
- 1);
3836 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
3841 * fix up name & parent pointers. note that we first
3842 * check that fvp has the same name/parent pointers it
3843 * had before the rename call... this is a 'weak' check
3846 if (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
) {
3849 update_flags
= VNODE_UPDATE_NAME
;
3852 update_flags
|= VNODE_UPDATE_PARENT
;
3854 vnode_update_identity(fvp
, tdvp
, tond
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_namelen
, tond
.ni_cnd
.cn_hash
, update_flags
);
3857 if (holding_mntlock
) {
3858 mount_unlock_renames(locked_mp
);
3859 mount_drop(locked_mp
, 0);
3863 * nameidone has to happen before we vnode_put(tdvp)
3864 * since it may need to release the fs_nodelock on the tdvp
3874 * nameidone has to happen before we vnode_put(fdvp)
3875 * since it may need to release the fs_nodelock on the fdvp
3887 * Make a directory file.
3891 mkdir1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
3895 int update_flags
= 0;
3896 struct nameidata nd
;
3898 AUDIT_ARG(mode
, vap
->va_mode
);
3899 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
3900 UIO_USERSPACE
, path
, ctx
);
3901 nd
.ni_cnd
.cn_flags
|= WILLBEDIR
;
3913 /* authorize addition of a directory to the parent */
3914 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
)) != 0)
3917 VATTR_SET(vap
, va_type
, VDIR
);
3919 /* make the directory */
3920 if ((error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
)) != 0)
3923 // Make sure the name & parent pointers are hooked up
3924 if (vp
->v_name
== NULL
)
3925 update_flags
|= VNODE_UPDATE_NAME
;
3926 if (vp
->v_parent
== NULLVP
)
3927 update_flags
|= VNODE_UPDATE_PARENT
;
3930 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
3932 add_fsevent(FSE_CREATE_DIR
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
3936 * nameidone has to happen before we vnode_put(dvp)
3937 * since it may need to release the fs_nodelock on the dvp
3950 mkdir_extended(struct proc
*p
, register struct mkdir_extended_args
*uap
, __unused register_t
*retval
)
3952 struct vfs_context context
;
3954 kauth_filesec_t xsecdst
;
3955 struct vnode_attr va
;
3958 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
3959 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
3962 context
.vc_proc
= p
;
3963 context
.vc_ucred
= kauth_cred_get();
3966 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
3967 if (xsecdst
!= NULL
)
3968 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
3970 ciferror
= mkdir1(&context
, uap
->path
, &va
);
3971 if (xsecdst
!= NULL
)
3972 kauth_filesec_free(xsecdst
);
3977 mkdir(struct proc
*p
, register struct mkdir_args
*uap
, __unused register_t
*retval
)
3979 struct vfs_context context
;
3980 struct vnode_attr va
;
3982 context
.vc_proc
= p
;
3983 context
.vc_ucred
= kauth_cred_get();
3986 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
3988 return(mkdir1(&context
, uap
->path
, &va
));
3992 * Remove a directory file.
3996 rmdir(struct proc
*p
, struct rmdir_args
*uap
, __unused register_t
*retval
)
4000 struct nameidata nd
;
4001 struct vfs_context context
;
4003 context
.vc_proc
= p
;
4004 context
.vc_ucred
= kauth_cred_get();
4006 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
4007 UIO_USERSPACE
, uap
->path
, &context
);
4014 if (vp
->v_type
!= VDIR
) {
4016 * rmdir only deals with directories
4019 } else if (dvp
== vp
) {
4021 * No rmdir "." please.
4024 } else if (vp
->v_flag
& VROOT
) {
4026 * The root of a mounted filesystem cannot be deleted.
4030 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, &context
);
4037 if (need_fsevent(FSE_DELETE
, dvp
)) {
4038 path
= get_pathbuff();
4040 vn_getpath(vp
, path
, &len
);
4041 get_fse_info(vp
, &finfo
, &context
);
4043 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, &context
);
4045 if (!error
&& path
!= NULL
) {
4046 add_fsevent(FSE_DELETE
, &context
,
4047 FSE_ARG_STRING
, len
, path
,
4048 FSE_ARG_FINFO
, &finfo
,
4052 release_pathbuff(path
);
4055 * nameidone has to happen before we vnode_put(dvp)
4056 * since it may need to release the fs_nodelock on the dvp
4068 * Read a block of directory entries in a file system independent format.
4071 getdirentries(p
, uap
, retval
)
4073 register struct getdirentries_args
*uap
;
4077 struct vfs_context context
;
4078 struct fileproc
*fp
;
4080 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4084 char uio_buf
[ UIO_SIZEOF(1) ];
4086 AUDIT_ARG(fd
, uap
->fd
);
4087 error
= fp_getfvp(p
, fd
, &fp
, &vp
);
4091 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
4092 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4096 if ( (error
= vnode_getwithref(vp
)) ) {
4100 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4103 if (vp
->v_type
!= VDIR
) {
4104 (void)vnode_put(vp
);
4108 context
.vc_proc
= p
;
4109 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
4111 loff
= fp
->f_fglob
->fg_offset
;
4112 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
4113 &uio_buf
[0], sizeof(uio_buf
));
4114 uio_addiov(auio
, uap
->buf
, uap
->count
);
4116 error
= VNOP_READDIR(vp
, auio
, 0, &eofflag
, (int *)NULL
, &context
);
4117 fp
->f_fglob
->fg_offset
= uio_offset(auio
);
4119 (void)vnode_put(vp
);
4125 if ((uap
->count
== uio_resid(auio
)) &&
4126 (vp
->v_op
== union_vnodeop_p
)) {
4129 lvp
= union_dircache(vp
, p
);
4130 if (lvp
!= NULLVP
) {
4131 struct vnode_attr va
;
4133 * If the directory is opaque,
4134 * then don't show lower entries
4137 VATTR_WANTED(&va
, va_flags
);
4138 error
= vnode_getattr(vp
, &va
, &context
);
4139 if (va
.va_flags
& OPAQUE
) {
4145 if (lvp
!= NULLVP
) {
4146 error
= VNOP_OPEN(lvp
, FREAD
, &context
);
4152 fp
->f_fglob
->fg_data
= (caddr_t
) lvp
;
4153 fp
->f_fglob
->fg_offset
= 0;
4154 error
= VNOP_CLOSE(vp
, FREAD
, &context
);
4166 if (((user_ssize_t
)uap
->count
== uio_resid(auio
)) &&
4167 (vp
->v_flag
& VROOT
) &&
4168 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
4169 struct vnode
*tvp
= vp
;
4170 vp
= vp
->v_mount
->mnt_vnodecovered
;
4171 vnode_getwithref(vp
);
4173 fp
->f_fglob
->fg_data
= (caddr_t
) vp
;
4174 fp
->f_fglob
->fg_offset
= 0;
4180 error
= copyout((caddr_t
)&loff
, uap
->basep
, sizeof(long));
4181 // LP64todo - fix this
4182 *retval
= uap
->count
- uio_resid(auio
);
4189 * Set the mode mask for creation of filesystem nodes.
4191 #warning XXX implement xsecurity
4193 #define UMASK_NOXSECURITY (void *)1 /* leave existing xsecurity alone */
4195 umask1(struct proc
*p
, int newmask
, __unused kauth_filesec_t fsec
, register_t
*retval
)
4197 register struct filedesc
*fdp
;
4199 AUDIT_ARG(mask
, newmask
);
4201 *retval
= fdp
->fd_cmask
;
4202 fdp
->fd_cmask
= newmask
& ALLPERMS
;
4208 umask_extended(struct proc
*p
, struct umask_extended_args
*uap
, register_t
*retval
)
4211 kauth_filesec_t xsecdst
;
4213 xsecdst
= KAUTH_FILESEC_NONE
;
4214 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
4215 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
4218 xsecdst
= KAUTH_FILESEC_NONE
;
4221 ciferror
= umask1(p
, uap
->newmask
, xsecdst
, retval
);
4223 if (xsecdst
!= KAUTH_FILESEC_NONE
)
4224 kauth_filesec_free(xsecdst
);
4229 umask(struct proc
*p
, struct umask_args
*uap
, register_t
*retval
)
4231 return(umask1(p
, uap
->newmask
, UMASK_NOXSECURITY
, retval
));
4235 * Void all references to file by ripping underlying filesystem
4240 revoke(struct proc
*p
, register struct revoke_args
*uap
, __unused register_t
*retval
)
4242 register struct vnode
*vp
;
4243 struct vnode_attr va
;
4244 struct vfs_context context
;
4246 struct nameidata nd
;
4248 context
.vc_proc
= p
;
4249 context
.vc_ucred
= kauth_cred_get();
4251 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4252 UIO_USERSPACE
, uap
->path
, &context
);
4261 VATTR_WANTED(&va
, va_uid
);
4262 if ((error
= vnode_getattr(vp
, &va
, &context
)))
4264 if (kauth_cred_getuid(context
.vc_ucred
) != va
.va_uid
&&
4265 (error
= suser(context
.vc_ucred
, &p
->p_acflag
)))
4267 if (vp
->v_usecount
> 1 || (vp
->v_flag
& VALIASED
))
4268 VNOP_REVOKE(vp
, REVOKEALL
, &context
);
4276 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
4277 * The following system calls are designed to support features
4278 * which are specific to the HFS & HFS Plus volume formats
4281 #ifdef __APPLE_API_OBSOLETE
4283 /************************************************/
4284 /* *** Following calls will be deleted soon *** */
4285 /************************************************/
4288 * Make a complex file. A complex file is one with multiple forks (data streams)
4292 mkcomplex(__unused
struct proc
*p
, __unused
struct mkcomplex_args
*uap
, __unused register_t
*retval
)
4298 * Extended stat call which returns volumeid and vnodeid as well as other info
4302 statv(__unused
struct proc
*p
,
4303 __unused
struct statv_args
*uap
,
4304 __unused register_t
*retval
)
4306 return (ENOTSUP
); /* We'll just return an error for now */
4308 } /* end of statv system call */
4311 * Extended lstat call which returns volumeid and vnodeid as well as other info
4315 lstatv(__unused
struct proc
*p
,
4316 __unused
struct lstatv_args
*uap
,
4317 __unused register_t
*retval
)
4319 return (ENOTSUP
); /* We'll just return an error for now */
4320 } /* end of lstatv system call */
4323 * Extended fstat call which returns volumeid and vnodeid as well as other info
4327 fstatv(__unused
struct proc
*p
,
4328 __unused
struct fstatv_args
*uap
,
4329 __unused register_t
*retval
)
4331 return (ENOTSUP
); /* We'll just return an error for now */
4332 } /* end of fstatv system call */
4335 /************************************************/
4336 /* *** Preceding calls will be deleted soon *** */
4337 /************************************************/
4339 #endif /* __APPLE_API_OBSOLETE */
4342 * Obtain attribute information on objects in a directory while enumerating
4343 * the directory. This call does not yet support union mounted directories.
4345 * 1.union mounted directories.
4350 getdirentriesattr (struct proc
*p
, struct getdirentriesattr_args
*uap
, register_t
*retval
)
4353 struct fileproc
*fp
;
4355 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4356 uint64_t actualcount
;
4361 struct attrlist attributelist
;
4362 struct vfs_context context
;
4364 char uio_buf
[ UIO_SIZEOF(1) ];
4365 kauth_action_t action
;
4369 /* Get the attributes into kernel space */
4370 if ((error
= copyin(uap
->alist
, (caddr_t
) &attributelist
, sizeof (attributelist
))))
4372 actualcount
= fuulong(uap
->count
);
4373 if (actualcount
== -1ULL)
4376 if ( (error
= fp_getfvp(p
, fd
, &fp
, &vp
)) )
4379 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
4380 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4384 if ( (error
= vnode_getwithref(vp
)) )
4387 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4389 if (vp
->v_type
!= VDIR
) {
4390 (void)vnode_put(vp
);
4395 /* set up the uio structure which will contain the users return buffer */
4396 loff
= fp
->f_fglob
->fg_offset
;
4397 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
4398 &uio_buf
[0], sizeof(uio_buf
));
4399 uio_addiov(auio
, uap
->buffer
, uap
->buffersize
);
4401 context
.vc_proc
= p
;
4402 context
.vc_ucred
= kauth_cred_get();
4403 tmpcount
= (u_long
) actualcount
;
4406 * If the only item requested is file names, we can let that past with
4407 * just LIST_DIRECTORY. If they want any other attributes, that means
4408 * they need SEARCH as well.
4410 action
= KAUTH_VNODE_LIST_DIRECTORY
;
4411 if ((attributelist
.commonattr
& ~ATTR_CMN_NAME
) ||
4412 attributelist
.fileattr
|| attributelist
.dirattr
)
4413 action
|= KAUTH_VNODE_SEARCH
;
4415 if ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) == 0)
4416 error
= VNOP_READDIRATTR(vp
, &attributelist
, auio
,
4417 tmpcount
, uap
->options
, &newstate
, &eofflag
,
4418 &tmpcount
, &context
);
4419 (void)vnode_put(vp
);
4420 actualcount
= tmpcount
;
4424 fp
->f_fglob
->fg_offset
= uio_offset(auio
); /* should be multiple of dirent, not variable */
4426 if ((error
= suulong(uap
->count
, actualcount
)) != 0)
4428 if ((error
= suulong(uap
->newstate
, (uint64_t)newstate
)) != 0)
4430 if ((error
= suulong(uap
->basep
, (uint64_t)loff
)) != 0)
4433 *retval
= eofflag
; /* similar to getdirentries */
4437 return (error
); /* return error earlier, an retval of 0 or 1 now */
4439 } /* end of getdirentryattr system call */
4442 * Exchange data between two files
4447 exchangedata (struct proc
*p
, register struct exchangedata_args
*uap
, __unused register_t
*retval
)
4450 struct nameidata fnd
, snd
;
4451 struct vfs_context context
;
4452 struct vnode
*fvp
, *svp
;
4458 fse_info f_finfo
, s_finfo
;
4460 context
.vc_proc
= p
;
4461 context
.vc_ucred
= kauth_cred_get();
4464 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4466 NDINIT(&fnd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4467 UIO_USERSPACE
, uap
->path1
, &context
);
4469 error
= namei(&fnd
);
4476 NDINIT(&snd
, LOOKUP
, nameiflags
| AUDITVNPATH2
,
4477 UIO_USERSPACE
, uap
->path2
, &context
);
4479 error
= namei(&snd
);
4488 * if the files are the same, return an inval error
4496 * if the files are on different volumes, return an error
4498 if (svp
->v_mount
!= fvp
->v_mount
) {
4502 if (((error
= vnode_authorize(fvp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0) ||
4503 ((error
= vnode_authorize(svp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0))
4506 if (need_fsevent(FSE_EXCHANGE
, fvp
) || kauth_authorize_fileop_has_listeners()) {
4507 fpath
= get_pathbuff();
4508 spath
= get_pathbuff();
4511 if (vn_getpath(fvp
, fpath
, &flen
) != 0 || fpath
[0] == '\0') {
4512 printf("exchange: vn_getpath(fvp=0x%x) failed <<%s>>\n",
4515 if (vn_getpath(svp
, spath
, &slen
) != 0 || spath
[0] == '\0') {
4516 printf("exchange: vn_getpath(svp=0x%x) failed <<%s>>\n",
4519 get_fse_info(fvp
, &f_finfo
, &context
);
4520 get_fse_info(svp
, &s_finfo
, &context
);
4522 /* Ok, make the call */
4523 error
= VNOP_EXCHANGE(fvp
, svp
, 0, &context
);
4528 if (fpath
!= NULL
&& spath
!= NULL
) {
4529 /* call out to allow 3rd party notification of exchangedata.
4530 * Ignore result of kauth_authorize_fileop call.
4532 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_EXCHANGE
,
4533 (uintptr_t)fpath
, (uintptr_t)spath
);
4537 tmpname
= fvp
->v_name
;
4538 fvp
->v_name
= svp
->v_name
;
4539 svp
->v_name
= tmpname
;
4541 if (fvp
->v_parent
!= svp
->v_parent
) {
4544 tmp
= fvp
->v_parent
;
4545 fvp
->v_parent
= svp
->v_parent
;
4546 svp
->v_parent
= tmp
;
4548 name_cache_unlock();
4550 if (fpath
!= NULL
&& spath
!= NULL
) {
4551 add_fsevent(FSE_EXCHANGE
, &context
,
4552 FSE_ARG_STRING
, flen
, fpath
,
4553 FSE_ARG_FINFO
, &f_finfo
,
4554 FSE_ARG_STRING
, slen
, spath
,
4555 FSE_ARG_FINFO
, &s_finfo
,
4560 release_pathbuff(spath
);
4562 release_pathbuff(fpath
);
4572 #ifdef __APPLE_API_OBSOLETE
4574 /************************************************/
4575 /* *** Following calls will be deleted soon *** */
4576 /************************************************/
4579 * Check users access to a file
4583 #warning "checkuseraccess copies a cred in from user space but"
4584 #warning "user space has no way of knowing what one looks like"
4585 #warning "this code should use the access_extended spoof-as functionality"
4587 checkuseraccess (struct proc
*p
, register struct checkuseraccess_args
*uap
, __unused register_t
*retval
)
4589 register struct vnode
*vp
;
4591 struct nameidata nd
;
4592 struct ucred cred
; /* XXX ILLEGAL */
4593 int flags
; /*what will actually get passed to access*/
4595 struct vfs_context context
;
4597 /* Make sure that the number of groups is correct before we do anything */
4599 if ((uap
->ngroups
<= 0) || (uap
->ngroups
> NGROUPS
))
4602 /* Verify that the caller is root */
4604 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
4607 /* Fill in the credential structure */
4610 cred
.cr_uid
= uap
->userid
;
4611 cred
.cr_ngroups
= uap
->ngroups
;
4612 if ((error
= copyin(CAST_USER_ADDR_T(uap
->groups
), (caddr_t
) &(cred
.cr_groups
), (sizeof(gid_t
))*uap
->ngroups
)))
4615 context
.vc_proc
= p
;
4616 context
.vc_ucred
= &cred
;
4618 /* Get our hands on the file */
4620 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4621 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4622 UIO_USERSPACE
, CAST_USER_ADDR_T(uap
->path
), &context
);
4624 if ((error
= namei(&nd
)))
4629 /* Flags == 0 means only check for existence. */
4633 if (uap
->accessrequired
) {
4634 if (uap
->accessrequired
& R_OK
)
4635 flags
|= KAUTH_VNODE_READ_DATA
;
4636 if (uap
->accessrequired
& W_OK
)
4637 flags
|= KAUTH_VNODE_WRITE_DATA
;
4638 if (uap
->accessrequired
& X_OK
)
4639 flags
|= KAUTH_VNODE_EXECUTE
;
4641 error
= vnode_authorize(vp
, NULL
, flags
, &context
);
4650 } /* end of checkuseraccess system call */
4652 /************************************************/
4653 /* *** Preceding calls will be deleted soon *** */
4654 /************************************************/
4656 #endif /* __APPLE_API_OBSOLETE */
4663 searchfs (struct proc
*p
, register struct searchfs_args
*uap
, __unused register_t
*retval
)
4665 register struct vnode
*vp
;
4668 struct nameidata nd
;
4669 struct user_fssearchblock searchblock
;
4670 struct searchstate
*state
;
4671 struct attrlist
*returnattrs
;
4672 void *searchparams1
,*searchparams2
;
4674 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4678 struct vfs_context context
;
4679 char uio_buf
[ UIO_SIZEOF(1) ];
4681 context
.vc_proc
= p
;
4682 context
.vc_ucred
= kauth_cred_get();
4684 /* Start by copying in fsearchblock paramater list */
4685 if (IS_64BIT_PROCESS(p
)) {
4686 error
= copyin(uap
->searchblock
, (caddr_t
) &searchblock
, sizeof(searchblock
));
4689 struct fssearchblock tmp_searchblock
;
4690 error
= copyin(uap
->searchblock
, (caddr_t
) &tmp_searchblock
, sizeof(tmp_searchblock
));
4691 // munge into 64-bit version
4692 searchblock
.returnattrs
= CAST_USER_ADDR_T(tmp_searchblock
.returnattrs
);
4693 searchblock
.returnbuffer
= CAST_USER_ADDR_T(tmp_searchblock
.returnbuffer
);
4694 searchblock
.returnbuffersize
= tmp_searchblock
.returnbuffersize
;
4695 searchblock
.maxmatches
= tmp_searchblock
.maxmatches
;
4696 searchblock
.timelimit
= tmp_searchblock
.timelimit
;
4697 searchblock
.searchparams1
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams1
);
4698 searchblock
.sizeofsearchparams1
= tmp_searchblock
.sizeofsearchparams1
;
4699 searchblock
.searchparams2
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams2
);
4700 searchblock
.sizeofsearchparams2
= tmp_searchblock
.sizeofsearchparams2
;
4701 searchblock
.searchattrs
= tmp_searchblock
.searchattrs
;
4706 /* Do a sanity check on sizeofsearchparams1 and sizeofsearchparams2.
4708 if (searchblock
.sizeofsearchparams1
> SEARCHFS_MAX_SEARCHPARMS
||
4709 searchblock
.sizeofsearchparams2
> SEARCHFS_MAX_SEARCHPARMS
)
4712 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
4713 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
4714 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
4717 mallocsize
= searchblock
.sizeofsearchparams1
+ searchblock
.sizeofsearchparams2
+
4718 sizeof(struct attrlist
) + sizeof(struct searchstate
);
4720 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
4722 /* Now set up the various pointers to the correct place in our newly allocated memory */
4724 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
4725 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
4726 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
4728 /* Now copy in the stuff given our local variables. */
4730 if ((error
= copyin(searchblock
.searchparams1
, searchparams1
, searchblock
.sizeofsearchparams1
)))
4733 if ((error
= copyin(searchblock
.searchparams2
, searchparams2
, searchblock
.sizeofsearchparams2
)))
4736 if ((error
= copyin(searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
))))
4739 if ((error
= copyin(uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
))))
4742 /* set up the uio structure which will contain the users return buffer */
4744 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
4745 &uio_buf
[0], sizeof(uio_buf
));
4746 uio_addiov(auio
, searchblock
.returnbuffer
, searchblock
.returnbuffersize
);
4749 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4750 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4751 UIO_USERSPACE
, uap
->path
, &context
);
4762 * If searchblock.maxmatches == 0, then skip the search. This has happened
4763 * before and sometimes the underlyning code doesnt deal with it well.
4765 if (searchblock
.maxmatches
== 0) {
4771 Allright, we have everything we need, so lets make that call.
4773 We keep special track of the return value from the file system:
4774 EAGAIN is an acceptable error condition that shouldn't keep us
4775 from copying out any results...
4778 fserror
= VNOP_SEARCHFS(vp
,
4781 &searchblock
.searchattrs
,
4782 searchblock
.maxmatches
,
4783 &searchblock
.timelimit
,
4796 /* Now copy out the stuff that needs copying out. That means the number of matches, the
4797 search state. Everything was already put into he return buffer by the vop call. */
4799 if ((error
= copyout((caddr_t
) state
, uap
->state
, sizeof(struct searchstate
))) != 0)
4802 if ((error
= suulong(uap
->nummatches
, (uint64_t)nummatches
)) != 0)
4809 FREE(searchparams1
,M_TEMP
);
4814 } /* end of searchfs system call */
4818 * Make a filesystem-specific control call:
4822 fsctl (struct proc
*p
, struct fsctl_args
*uap
, __unused register_t
*retval
)
4826 struct nameidata nd
;
4828 u_long cmd
= uap
->cmd
;
4829 register u_int size
;
4830 #define STK_PARAMS 128
4831 char stkbuf
[STK_PARAMS
];
4833 struct vfs_context context
;
4835 context
.vc_proc
= p
;
4836 context
.vc_ucred
= kauth_cred_get();
4838 size
= IOCPARM_LEN(cmd
);
4839 if (size
> IOCPARM_MAX
) return (EINVAL
);
4841 is64bit
= proc_is64bit(p
);
4844 if (size
> sizeof (stkbuf
)) {
4845 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
4853 error
= copyin(uap
->data
, data
, size
);
4854 if (error
) goto FSCtl_Exit
;
4857 *(user_addr_t
*)data
= uap
->data
;
4860 *(uint32_t *)data
= (uint32_t)uap
->data
;
4863 } else if ((cmd
& IOC_OUT
) && size
) {
4865 * Zero the buffer so the user always
4866 * gets back something deterministic.
4869 } else if (cmd
& IOC_VOID
) {
4871 *(user_addr_t
*)data
= uap
->data
;
4874 *(uint32_t *)data
= (uint32_t)uap
->data
;
4878 /* Get the vnode for the file we are getting info on: */
4880 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4881 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, uap
->path
, &context
);
4882 if ((error
= namei(&nd
))) goto FSCtl_Exit
;
4884 /* Invoke the filesystem-specific code */
4885 error
= VNOP_IOCTL(nd
.ni_vp
, IOCBASECMD(cmd
), data
, uap
->options
, &context
);
4887 vnode_put(nd
.ni_vp
);
4891 * Copy any data to user, size was
4892 * already set and checked above.
4894 if (error
== 0 && (cmd
& IOC_OUT
) && size
)
4895 error
= copyout(data
, uap
->data
, size
);
4898 if (memp
) kfree(memp
, size
);
4902 /* end of fsctl system call */
4905 * An in-kernel sync for power management to call.
4907 __private_extern__
int
4912 struct sync_args data
;
4917 error
= sync(current_proc(), &data
, &retval
[0]);
4921 } /* end of sync_internal call */
4925 * Retrieve the data of an extended attribute.
4928 getxattr(struct proc
*p
, struct getxattr_args
*uap
, user_ssize_t
*retval
)
4931 struct nameidata nd
;
4932 char attrname
[XATTR_MAXNAMELEN
+1];
4933 struct vfs_context context
;
4935 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4936 size_t attrsize
= 0;
4940 char uio_buf
[ UIO_SIZEOF(1) ];
4942 context
.vc_proc
= p
;
4943 context
.vc_ucred
= kauth_cred_get();
4945 if (uap
->options
& XATTR_NOSECURITY
)
4948 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
4949 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
4950 if ((error
= namei(&nd
))) {
4956 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
4959 if (xattr_protected(attrname
)) {
4963 if (uap
->value
&& uap
->size
> 0) {
4964 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
4965 &uio_buf
[0], sizeof(uio_buf
));
4966 uio_addiov(auio
, uap
->value
, uap
->size
);
4969 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, &context
);
4974 *retval
= uap
->size
- uio_resid(auio
);
4976 *retval
= (user_ssize_t
)attrsize
;
4983 * Retrieve the data of an extended attribute.
4986 fgetxattr(struct proc
*p
, struct fgetxattr_args
*uap
, user_ssize_t
*retval
)
4989 char attrname
[XATTR_MAXNAMELEN
+1];
4990 struct vfs_context context
;
4992 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4993 size_t attrsize
= 0;
4996 char uio_buf
[ UIO_SIZEOF(1) ];
4998 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5001 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5004 if ( (error
= vnode_getwithref(vp
)) ) {
5008 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5011 if (xattr_protected(attrname
)) {
5015 if (uap
->value
&& uap
->size
> 0) {
5016 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
5017 &uio_buf
[0], sizeof(uio_buf
));
5018 uio_addiov(auio
, uap
->value
, uap
->size
);
5020 context
.vc_proc
= p
;
5021 context
.vc_ucred
= kauth_cred_get();
5023 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, &context
);
5025 (void)vnode_put(vp
);
5029 *retval
= uap
->size
- uio_resid(auio
);
5031 *retval
= (user_ssize_t
)attrsize
;
5037 * Set the data of an extended attribute.
5040 setxattr(struct proc
*p
, struct setxattr_args
*uap
, int *retval
)
5043 struct nameidata nd
;
5044 char attrname
[XATTR_MAXNAMELEN
+1];
5045 struct vfs_context context
;
5047 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5051 char uio_buf
[ UIO_SIZEOF(1) ];
5053 context
.vc_proc
= p
;
5054 context
.vc_ucred
= kauth_cred_get();
5056 if (uap
->options
& XATTR_NOSECURITY
)
5059 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5062 if (xattr_protected(attrname
))
5064 if (uap
->value
== 0 || uap
->size
== 0) {
5068 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5069 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5070 if ((error
= namei(&nd
))) {
5076 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
5077 &uio_buf
[0], sizeof(uio_buf
));
5078 uio_addiov(auio
, uap
->value
, uap
->size
);
5080 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, &context
);
5087 * Set the data of an extended attribute.
5090 fsetxattr(struct proc
*p
, struct fsetxattr_args
*uap
, int *retval
)
5093 char attrname
[XATTR_MAXNAMELEN
+1];
5094 struct vfs_context context
;
5096 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5099 char uio_buf
[ UIO_SIZEOF(1) ];
5101 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5104 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5107 if (xattr_protected(attrname
))
5109 if (uap
->value
== 0 || uap
->size
== 0) {
5112 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5115 if ( (error
= vnode_getwithref(vp
)) ) {
5119 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
5120 &uio_buf
[0], sizeof(uio_buf
));
5121 uio_addiov(auio
, uap
->value
, uap
->size
);
5122 context
.vc_proc
= p
;
5123 context
.vc_ucred
= kauth_cred_get();
5125 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, &context
);
5133 * Remove an extended attribute.
5135 #warning "code duplication"
5137 removexattr(struct proc
*p
, struct removexattr_args
*uap
, int *retval
)
5140 struct nameidata nd
;
5141 char attrname
[XATTR_MAXNAMELEN
+1];
5142 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5143 struct vfs_context context
;
5148 context
.vc_proc
= p
;
5149 context
.vc_ucred
= kauth_cred_get();
5151 if (uap
->options
& XATTR_NOSECURITY
)
5154 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
5158 if (xattr_protected(attrname
))
5160 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5161 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5162 if ((error
= namei(&nd
))) {
5168 error
= vn_removexattr(vp
, attrname
, uap
->options
, &context
);
5175 * Remove an extended attribute.
5177 #warning "code duplication"
5179 fremovexattr(struct proc
*p
, struct fremovexattr_args
*uap
, int *retval
)
5182 char attrname
[XATTR_MAXNAMELEN
+1];
5183 struct vfs_context context
;
5187 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5190 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
5194 if (xattr_protected(attrname
))
5196 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5199 if ( (error
= vnode_getwithref(vp
)) ) {
5203 context
.vc_proc
= p
;
5204 context
.vc_ucred
= kauth_cred_get();
5206 error
= vn_removexattr(vp
, attrname
, uap
->options
, &context
);
5214 * Retrieve the list of extended attribute names.
5216 #warning "code duplication"
5218 listxattr(struct proc
*p
, struct listxattr_args
*uap
, user_ssize_t
*retval
)
5221 struct nameidata nd
;
5222 struct vfs_context context
;
5224 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5225 size_t attrsize
= 0;
5228 char uio_buf
[ UIO_SIZEOF(1) ];
5230 context
.vc_proc
= p
;
5231 context
.vc_ucred
= kauth_cred_get();
5233 if (uap
->options
& XATTR_NOSECURITY
)
5236 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5237 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5238 if ((error
= namei(&nd
))) {
5243 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
5244 // LP64todo - fix this!
5245 auio
= uio_createwithbuffer(1, 0, spacetype
,
5246 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
5247 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
5250 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, &context
);
5254 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
5256 *retval
= (user_ssize_t
)attrsize
;
5262 * Retrieve the list of extended attribute names.
5264 #warning "code duplication"
5266 flistxattr(struct proc
*p
, struct flistxattr_args
*uap
, user_ssize_t
*retval
)
5269 struct vfs_context context
;
5271 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5272 size_t attrsize
= 0;
5274 char uio_buf
[ UIO_SIZEOF(1) ];
5276 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5279 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5282 if ( (error
= vnode_getwithref(vp
)) ) {
5286 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
5287 // LP64todo - fix this!
5288 auio
= uio_createwithbuffer(1, 0, spacetype
,
5289 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
5290 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
5292 context
.vc_proc
= p
;
5293 context
.vc_ucred
= kauth_cred_get();
5295 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, &context
);
5300 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
5302 *retval
= (user_ssize_t
)attrsize
;
5308 * Common routine to handle various flavors of statfs data heading out
5312 munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
5313 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
5314 boolean_t partial_copy
)
5317 int my_size
, copy_size
;
5320 struct user_statfs sfs
;
5321 my_size
= copy_size
= sizeof(sfs
);
5322 bzero(&sfs
, my_size
);
5323 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
5324 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
5325 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
5326 sfs
.f_bsize
= (user_long_t
)sfsp
->f_bsize
;
5327 sfs
.f_iosize
= (user_long_t
)sfsp
->f_iosize
;
5328 sfs
.f_blocks
= (user_long_t
)sfsp
->f_blocks
;
5329 sfs
.f_bfree
= (user_long_t
)sfsp
->f_bfree
;
5330 sfs
.f_bavail
= (user_long_t
)sfsp
->f_bavail
;
5331 sfs
.f_files
= (user_long_t
)sfsp
->f_files
;
5332 sfs
.f_ffree
= (user_long_t
)sfsp
->f_ffree
;
5333 sfs
.f_fsid
= sfsp
->f_fsid
;
5334 sfs
.f_owner
= sfsp
->f_owner
;
5335 strncpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
-1);
5336 strncpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
-1);
5337 strncpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
-1);
5340 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
5342 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
5346 my_size
= copy_size
= sizeof(sfs
);
5347 bzero(&sfs
, my_size
);
5349 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
5350 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
5351 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
5354 * It's possible for there to be more than 2^^31 blocks in the filesystem, so we
5355 * have to fudge the numbers here in that case. We inflate the blocksize in order
5356 * to reflect the filesystem size as best we can.
5358 if ((sfsp
->f_blocks
> LONG_MAX
)
5359 /* Hack for 4061702 . I think the real fix is for Carbon to
5360 * look for some volume capability and not depend on hidden
5361 * semantics agreed between a FS and carbon.
5362 * f_blocks, f_bfree, and f_bavail set to -1 is the trigger
5363 * for Carbon to set bNoVolumeSizes volume attribute.
5364 * Without this the webdavfs files cannot be copied onto
5365 * disk as they look huge. This change should not affect
5366 * XSAN as they should not setting these to -1..
5368 && (sfsp
->f_blocks
!= 0xffffffffffffffff)
5369 && (sfsp
->f_bfree
!= 0xffffffffffffffff)
5370 && (sfsp
->f_bavail
!= 0xffffffffffffffff)) {
5374 * Work out how far we have to shift the block count down to make it fit.
5375 * Note that it's possible to have to shift so far that the resulting
5376 * blocksize would be unreportably large. At that point, we will clip
5377 * any values that don't fit.
5379 * For safety's sake, we also ensure that f_iosize is never reported as
5380 * being smaller than f_bsize.
5382 for (shift
= 0; shift
< 32; shift
++) {
5383 if ((sfsp
->f_blocks
>> shift
) <= LONG_MAX
)
5385 if ((sfsp
->f_bsize
<< (shift
+ 1)) > LONG_MAX
)
5388 #define __SHIFT_OR_CLIP(x, s) ((((x) >> (s)) > LONG_MAX) ? LONG_MAX : ((x) >> (s)))
5389 sfs
.f_blocks
= (long)__SHIFT_OR_CLIP(sfsp
->f_blocks
, shift
);
5390 sfs
.f_bfree
= (long)__SHIFT_OR_CLIP(sfsp
->f_bfree
, shift
);
5391 sfs
.f_bavail
= (long)__SHIFT_OR_CLIP(sfsp
->f_bavail
, shift
);
5392 #undef __SHIFT_OR_CLIP
5393 sfs
.f_bsize
= (long)(sfsp
->f_bsize
<< shift
);
5394 sfs
.f_iosize
= lmax(sfsp
->f_iosize
, sfsp
->f_bsize
);
5396 /* filesystem is small enough to be reported honestly */
5397 sfs
.f_bsize
= (long)sfsp
->f_bsize
;
5398 sfs
.f_iosize
= (long)sfsp
->f_iosize
;
5399 sfs
.f_blocks
= (long)sfsp
->f_blocks
;
5400 sfs
.f_bfree
= (long)sfsp
->f_bfree
;
5401 sfs
.f_bavail
= (long)sfsp
->f_bavail
;
5403 sfs
.f_files
= (long)sfsp
->f_files
;
5404 sfs
.f_ffree
= (long)sfsp
->f_ffree
;
5405 sfs
.f_fsid
= sfsp
->f_fsid
;
5406 sfs
.f_owner
= sfsp
->f_owner
;
5407 strncpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
-1);
5408 strncpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
-1);
5409 strncpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
-1);
5412 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
5414 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
5417 if (sizep
!= NULL
) {
5424 * copy stat structure into user_stat structure.
5426 void munge_stat(struct stat
*sbp
, struct user_stat
*usbp
)
5428 usbp
->st_dev
= sbp
->st_dev
;
5429 usbp
->st_ino
= sbp
->st_ino
;
5430 usbp
->st_mode
= sbp
->st_mode
;
5431 usbp
->st_nlink
= sbp
->st_nlink
;
5432 usbp
->st_uid
= sbp
->st_uid
;
5433 usbp
->st_gid
= sbp
->st_gid
;
5434 usbp
->st_rdev
= sbp
->st_rdev
;
5435 #ifndef _POSIX_SOURCE
5436 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
5437 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
5438 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
5439 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
5440 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
5441 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
5443 usbp
->st_atime
= sbp
->st_atime
;
5444 usbp
->st_atimensec
= sbp
->st_atimensec
;
5445 usbp
->st_mtime
= sbp
->st_mtime
;
5446 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
5447 usbp
->st_ctime
= sbp
->st_ctime
;
5448 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
5450 usbp
->st_size
= sbp
->st_size
;
5451 usbp
->st_blocks
= sbp
->st_blocks
;
5452 usbp
->st_blksize
= sbp
->st_blksize
;
5453 usbp
->st_flags
= sbp
->st_flags
;
5454 usbp
->st_gen
= sbp
->st_gen
;
5455 usbp
->st_lspare
= sbp
->st_lspare
;
5456 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
5457 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];