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
;
193 boolean_t is_rwlock_locked
= FALSE
;
195 AUDIT_ARG(fflags
, uap
->flags
);
198 context
.vc_ucred
= kauth_cred_get();
199 is_64bit
= proc_is64bit(p
);
202 * Get vnode to be covered
204 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
205 UIO_USERSPACE
, uap
->path
, &context
);
211 if ((vp
->v_flag
& VROOT
) &&
212 (vp
->v_mount
->mnt_flag
& MNT_ROOTFS
))
213 uap
->flags
|= MNT_UPDATE
;
215 if (uap
->flags
& MNT_UPDATE
) {
216 if ((vp
->v_flag
& VROOT
) == 0) {
222 /* unmount in progress return error */
224 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
230 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
231 is_rwlock_locked
= TRUE
;
233 * We only allow the filesystem to be reloaded if it
234 * is currently mounted read-only.
236 if ((uap
->flags
& MNT_RELOAD
) &&
237 ((mp
->mnt_flag
& MNT_RDONLY
) == 0)) {
242 * Only root, or the user that did the original mount is
243 * permitted to update it.
245 if (mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(context
.vc_ucred
) &&
246 (error
= suser(context
.vc_ucred
, &p
->p_acflag
))) {
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 is_rwlock_locked
= TRUE
;
337 mp
->mnt_op
= vfsp
->vfc_vfsops
;
338 mp
->mnt_vtable
= vfsp
;
340 vfsp
->vfc_refcount
++;
342 //mp->mnt_stat.f_type = vfsp->vfc_typenum;
343 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
344 strncpy(mp
->mnt_vfsstat
.f_fstypename
, vfsp
->vfc_name
, MFSTYPENAMELEN
);
345 strncpy(mp
->mnt_vfsstat
.f_mntonname
, nd
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
346 mp
->mnt_vnodecovered
= vp
;
347 mp
->mnt_vfsstat
.f_owner
= kauth_cred_getuid(context
.vc_ucred
);
349 /* XXX 3762912 hack to support HFS filesystem 'owner' - filesystem may update later */
350 vfs_setowner(mp
, KAUTH_UID_NONE
, KAUTH_GID_NONE
);
354 * Set the mount level flags.
356 if (uap
->flags
& MNT_RDONLY
)
357 mp
->mnt_flag
|= MNT_RDONLY
;
358 else if (mp
->mnt_flag
& MNT_RDONLY
)
359 mp
->mnt_kern_flag
|= MNTK_WANTRDWR
;
360 mp
->mnt_flag
&= ~(MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
361 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
362 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
);
363 mp
->mnt_flag
|= uap
->flags
& (MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
364 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
365 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
|
368 if (vfsp
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
370 if ( (error
= copyin(fsmountargs
, (caddr_t
)&devpath
, sizeof(devpath
))) )
372 fsmountargs
+= sizeof(devpath
);
375 if ( (error
= copyin(fsmountargs
, (caddr_t
)&tmp
, sizeof(tmp
))) )
377 /* munge into LP64 addr */
378 devpath
= CAST_USER_ADDR_T(tmp
);
379 fsmountargs
+= sizeof(tmp
);
382 /* if it is not update and device name needs to be parsed */
384 NDINIT(&nd1
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, devpath
, &context
);
385 if ( (error
= namei(&nd1
)) )
388 strncpy(mp
->mnt_vfsstat
.f_mntfromname
, nd1
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
393 if (devvp
->v_type
!= VBLK
) {
397 if (major(devvp
->v_rdev
) >= nblkdev
) {
402 * If mount by non-root, then verify that user has necessary
403 * permissions on the device.
405 if (suser(context
.vc_ucred
, NULL
) != 0) {
406 accessmode
= KAUTH_VNODE_READ_DATA
;
407 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
408 accessmode
|= KAUTH_VNODE_WRITE_DATA
;
409 if ((error
= vnode_authorize(devvp
, NULL
, accessmode
, &context
)) != 0)
413 if (devpath
&& ((uap
->flags
& MNT_UPDATE
) == 0)) {
414 if ( (error
= vnode_ref(devvp
)) )
417 * Disallow multiple mounts of the same device.
418 * Disallow mounting of a device that is currently in use
419 * (except for root, which might share swap device for miniroot).
420 * Flush out any old buffers remaining from a previous use.
422 if ( (error
= vfs_mountedon(devvp
)) )
425 if (vcount(devvp
) > 1 && !(vfs_flags(mp
) & MNT_ROOTFS
)) {
429 if ( (error
= VNOP_FSYNC(devvp
, MNT_WAIT
, &context
)) ) {
433 if ( (error
= buf_invalidateblks(devvp
, BUF_WRITE_DATA
, 0, 0)) )
436 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
437 if ( (error
= VNOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, &context
)) )
440 mp
->mnt_devvp
= devvp
;
441 device_vnode
= devvp
;
443 if ((mp
->mnt_flag
& MNT_RDONLY
) && (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)) {
445 * If upgrade to read-write by non-root, then verify
446 * that user has necessary permissions on the device.
448 device_vnode
= mp
->mnt_devvp
;
449 if (device_vnode
&& suser(context
.vc_ucred
, NULL
)) {
450 if ((error
= vnode_authorize(device_vnode
, NULL
,
451 KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0)
455 device_vnode
= NULLVP
;
461 * Mount the filesystem.
463 error
= VFS_MOUNT(mp
, device_vnode
, fsmountargs
, &context
);
465 if (uap
->flags
& MNT_UPDATE
) {
466 if (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)
467 mp
->mnt_flag
&= ~MNT_RDONLY
;
469 (MNT_UPDATE
| MNT_RELOAD
| MNT_FORCE
);
470 mp
->mnt_kern_flag
&=~ MNTK_WANTRDWR
;
473 vfs_event_signal(NULL
, VQ_UPDATE
, (intptr_t)NULL
);
474 lck_rw_done(&mp
->mnt_rwlock
);
475 is_rwlock_locked
= FALSE
;
477 enablequotas(mp
,&context
);
481 * Put the new filesystem on the mount list after root.
484 CLR(vp
->v_flag
, VMOUNT
);
487 vp
->v_mountedhere
= mp
;
492 vfs_event_signal(NULL
, VQ_MOUNT
, (intptr_t)NULL
);
493 checkdirs(vp
, &context
);
494 lck_rw_done(&mp
->mnt_rwlock
);
495 is_rwlock_locked
= FALSE
;
498 * there is no cleanup code here so I have made it void
499 * we need to revisit this
501 (void)VFS_START(mp
, 0, &context
);
503 /* increment the operations count */
504 OSAddAtomic(1, (SInt32
*)&vfs_nummntops
);
505 enablequotas(mp
,&context
);
508 device_vnode
->v_specflags
|= SI_MOUNTEDON
;
511 * cache the IO attributes for the underlying physical media...
512 * an error return indicates the underlying driver doesn't
513 * support all the queries necessary... however, reasonable
514 * defaults will have been set, so no reason to bail or care
516 vfs_init_io_attributes(device_vnode
, mp
);
519 CLR(vp
->v_flag
, VMOUNT
);
521 mp
->mnt_vtable
->vfc_refcount
--;
525 VNOP_CLOSE(device_vnode
, ronly
? FREAD
: FREAD
|FWRITE
, &context
);
526 vnode_rele(device_vnode
);
528 lck_rw_done(&mp
->mnt_rwlock
);
529 is_rwlock_locked
= FALSE
;
530 mount_lock_destroy(mp
);
531 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
536 * drop I/O count on covered 'vp' and
537 * on the device vp if there was one
539 if (devpath
&& devvp
)
548 if (devpath
&& devvp
)
551 /* Release mnt_rwlock only when it was taken */
552 if (is_rwlock_locked
== TRUE
) {
553 lck_rw_done(&mp
->mnt_rwlock
);
556 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
565 enablequotas(struct mount
*mp
, vfs_context_t context
)
567 struct nameidata qnd
;
569 char qfpath
[MAXPATHLEN
];
570 const char *qfname
= QUOTAFILENAME
;
571 const char *qfopsname
= QUOTAOPSNAME
;
572 const char *qfextension
[] = INITQFNAMES
;
574 if ((strcmp(mp
->mnt_vfsstat
.f_fstypename
, "hfs") != 0 )
575 && (strcmp( mp
->mnt_vfsstat
.f_fstypename
, "ufs") != 0))
579 * Enable filesystem disk quotas if necessary.
580 * We ignore errors as this should not interfere with final mount
582 for (type
=0; type
< MAXQUOTAS
; type
++) {
583 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfopsname
, qfextension
[type
]);
584 NDINIT(&qnd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE32
, CAST_USER_ADDR_T(qfpath
), context
);
585 if (namei(&qnd
) != 0)
586 continue; /* option file to trigger quotas is not present */
587 vnode_put(qnd
.ni_vp
);
589 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfname
, qfextension
[type
]);
591 (void) VFS_QUOTACTL(mp
, QCMD(Q_QUOTAON
, type
), 0, qfpath
, context
);
597 * Scan all active processes to see if any of them have a current
598 * or root directory onto which the new filesystem has just been
599 * mounted. If so, replace them with the new mount point.
602 checkdirs(olddp
, context
)
604 vfs_context_t context
;
606 struct filedesc
*fdp
;
610 struct vnode
*fdp_cvp
;
611 struct vnode
*fdp_rvp
;
612 int cdir_changed
= 0;
613 int rdir_changed
= 0;
614 boolean_t funnel_state
;
616 if (olddp
->v_usecount
== 1)
618 if (VFS_ROOT(olddp
->v_mountedhere
, &newdp
, context
))
619 panic("mount: lost mount");
620 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
622 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
625 if (fdp
== (struct filedesc
*)0) {
629 fdp_cvp
= fdp
->fd_cdir
;
630 fdp_rvp
= fdp
->fd_rdir
;
633 if (fdp_cvp
== olddp
) {
640 if (fdp_rvp
== olddp
) {
647 if (cdir_changed
|| rdir_changed
) {
649 fdp
->fd_cdir
= fdp_cvp
;
650 fdp
->fd_rdir
= fdp_rvp
;
654 if (rootvnode
== olddp
) {
660 thread_funnel_set(kernel_flock
, funnel_state
);
666 * Unmount a file system.
668 * Note: unmount takes a path to the vnode mounted on as argument,
669 * not special file (as before).
673 unmount(struct proc
*p
, register struct unmount_args
*uap
, __unused register_t
*retval
)
675 register struct vnode
*vp
;
679 struct vfs_context context
;
682 context
.vc_ucred
= kauth_cred_get();
684 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
685 UIO_USERSPACE
, uap
->path
, &context
);
694 * Must be the root of the filesystem
696 if ((vp
->v_flag
& VROOT
) == 0) {
701 return (safedounmount(mp
, uap
->flags
, p
));
705 * Do the actual file system unmount, prevent some common foot shooting.
707 * XXX Should take a "vfs_context_t" instead of a "struct proc *"
710 safedounmount(mp
, flags
, p
)
718 * Only root, or the user that did the original mount is
719 * permitted to unmount this filesystem.
721 if ((mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(kauth_cred_get())) &&
722 (error
= suser(kauth_cred_get(), &p
->p_acflag
)))
726 * Don't allow unmounting the root file system.
728 if (mp
->mnt_flag
& MNT_ROOTFS
)
729 return (EBUSY
); /* the root is always busy */
731 return (dounmount(mp
, flags
, p
));
735 * Do the actual file system unmount.
738 dounmount(mp
, flags
, p
)
739 register struct mount
*mp
;
743 struct vnode
*coveredvp
= (vnode_t
)0;
746 struct vfs_context context
;
747 int forcedunmount
= 0;
751 context
.vc_ucred
= kauth_cred_get();
753 if (flags
& MNT_FORCE
)
756 /* XXX post jaguar fix LK_DRAIN - then clean this up */
757 if ((flags
& MNT_FORCE
)) {
758 mp
->mnt_kern_flag
|= MNTK_FRCUNMOUNT
;
759 mp
->mnt_lflag
|= MNT_LFORCE
;
761 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
762 mp
->mnt_lflag
|= MNT_LWAIT
;
763 msleep((caddr_t
)mp
, &mp
->mnt_mlock
, (PVFS
| PDROP
), "dounmount", 0 );
765 * The prior unmount attempt has probably succeeded.
766 * Do not dereference mp here - returning EBUSY is safest.
770 mp
->mnt_kern_flag
|= MNTK_UNMOUNT
;
771 mp
->mnt_lflag
|= MNT_LUNMOUNT
;
772 mp
->mnt_flag
&=~ MNT_ASYNC
;
774 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
775 fsevent_unmount(mp
); /* has to come first! */
777 if (forcedunmount
== 0) {
778 ubc_umount(mp
); /* release cached vnodes */
779 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
780 error
= VFS_SYNC(mp
, MNT_WAIT
, &context
);
783 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
784 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
785 mp
->mnt_lflag
&= ~MNT_LFORCE
;
792 lflags
|= FORCECLOSE
;
793 error
= vflush(mp
, NULLVP
, SKIPSWAP
| SKIPSYSTEM
| SKIPROOT
| lflags
);
794 if ((forcedunmount
== 0) && error
) {
796 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
797 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
798 mp
->mnt_lflag
&= ~MNT_LFORCE
;
802 /* make sure there are no one in the mount iterations or lookup */
805 error
= VFS_UNMOUNT(mp
, flags
, &context
);
809 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
810 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
811 mp
->mnt_lflag
&= ~MNT_LFORCE
;
815 /* increment the operations count */
817 OSAddAtomic(1, (SInt32
*)&vfs_nummntops
);
819 if ( mp
->mnt_devvp
&& mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
820 mp
->mnt_devvp
->v_specflags
&= ~SI_MOUNTEDON
;
821 VNOP_CLOSE(mp
->mnt_devvp
, mp
->mnt_flag
& MNT_RDONLY
? FREAD
: FREAD
|FWRITE
,
823 vnode_rele(mp
->mnt_devvp
);
825 lck_rw_done(&mp
->mnt_rwlock
);
826 mount_list_remove(mp
);
827 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
829 /* mark the mount point hook in the vp but not drop the ref yet */
830 if ((coveredvp
= mp
->mnt_vnodecovered
) != NULLVP
) {
831 vnode_getwithref(coveredvp
);
832 vnode_lock(coveredvp
);
833 coveredvp
->v_mountedhere
= (struct mount
*)0;
834 vnode_unlock(coveredvp
);
835 vnode_put(coveredvp
);
839 mp
->mnt_vtable
->vfc_refcount
--;
842 cache_purgevfs(mp
); /* remove cache entries for this file sys */
843 vfs_event_signal(NULL
, VQ_UNMOUNT
, (intptr_t)NULL
);
845 mp
->mnt_lflag
|= MNT_LDEAD
;
847 if (mp
->mnt_lflag
& MNT_LWAIT
) {
850 * in case we block in mount_refdrain
851 * which will drop the mount lock
852 * and allow anyone blocked in vfs_busy
853 * to wakeup and see the LDEAD state
855 mp
->mnt_lflag
&= ~MNT_LWAIT
;
860 if (mp
->mnt_lflag
& MNT_LWAIT
) {
861 mp
->mnt_lflag
&= ~MNT_LWAIT
;
865 lck_rw_done(&mp
->mnt_rwlock
);
870 if ((coveredvp
!= NULLVP
)) {
871 vnode_getwithref(coveredvp
);
872 vnode_rele(coveredvp
);
873 vnode_lock(coveredvp
);
874 if(mp
->mnt_crossref
== 0) {
875 vnode_unlock(coveredvp
);
876 mount_lock_destroy(mp
);
877 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
879 coveredvp
->v_lflag
|= VL_MOUNTDEAD
;
880 vnode_unlock(coveredvp
);
882 vnode_put(coveredvp
);
883 } else if (mp
->mnt_flag
& MNT_ROOTFS
) {
884 mount_lock_destroy(mp
);
885 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
887 panic("dounmount: no coveredvp");
893 mount_dropcrossref(mount_t mp
, vnode_t dp
, int need_put
)
897 if (mp
->mnt_crossref
< 0)
898 panic("mount cross refs -ve");
899 if (((dp
->v_lflag
& VL_MOUNTDEAD
) == VL_MOUNTDEAD
) && (mp
->mnt_crossref
== 0)) {
900 dp
->v_lflag
&= ~VL_MOUNTDEAD
;
902 vnode_put_locked(dp
);
904 mount_lock_destroy(mp
);
905 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
909 vnode_put_locked(dp
);
915 * Sync each mounted filesystem.
919 struct ctldebug debug0
= { "syncprt", &syncprt
};
922 int print_vmpage_stat
=0;
925 sync_callback(mount_t mp
, __unused
void * arg
)
927 struct proc
* p
= current_proc();
929 struct vfs_context context
;
932 context
.vc_ucred
= kauth_cred_get();
934 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
935 asyncflag
= mp
->mnt_flag
& MNT_ASYNC
;
936 mp
->mnt_flag
&= ~MNT_ASYNC
;
937 VFS_SYNC(mp
, MNT_NOWAIT
, &context
);
939 mp
->mnt_flag
|= MNT_ASYNC
;
941 return(VFS_RETURNED
);
945 extern unsigned int vp_pagein
, vp_pgodirty
, vp_pgoclean
;
946 extern unsigned int dp_pgins
, dp_pgouts
;
950 sync(__unused
struct proc
*p
, __unused
struct sync_args
*uap
, __unused register_t
*retval
)
953 vfs_iterate(LK_NOWAIT
, sync_callback
, (void *)0);
955 if(print_vmpage_stat
) {
956 vm_countdirtypages();
957 printf("VP: %d: %d: %d: %d: %d\n", vp_pgodirty
, vp_pgoclean
, vp_pagein
,
958 dp_pgins
, dp_pgouts
);
964 #endif /* DIAGNOSTIC */
969 * Change filesystem quotas.
973 quotactl(struct proc
*p
, register struct quotactl_args
*uap
, __unused register_t
*retval
)
975 register struct mount
*mp
;
976 int error
, quota_cmd
, quota_status
;
980 struct vfs_context context
;
981 struct dqblk my_dqblk
;
984 context
.vc_ucred
= kauth_cred_get();
986 AUDIT_ARG(uid
, uap
->uid
, 0, 0, 0);
987 AUDIT_ARG(cmd
, uap
->cmd
);
988 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
989 UIO_USERSPACE
, uap
->path
, &context
);
993 mp
= nd
.ni_vp
->v_mount
;
997 /* copyin any data we will need for downstream code */
998 quota_cmd
= uap
->cmd
>> SUBCMDSHIFT
;
1000 switch (quota_cmd
) {
1002 /* uap->arg specifies a file from which to take the quotas */
1003 fnamelen
= MAXPATHLEN
;
1004 datap
= kalloc(MAXPATHLEN
);
1005 error
= copyinstr(uap
->arg
, datap
, MAXPATHLEN
, &fnamelen
);
1008 /* uap->arg is a pointer to a dqblk structure. */
1009 datap
= (caddr_t
) &my_dqblk
;
1013 /* uap->arg is a pointer to a dqblk structure. */
1014 datap
= (caddr_t
) &my_dqblk
;
1015 if (proc_is64bit(p
)) {
1016 struct user_dqblk my_dqblk64
;
1017 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk64
, sizeof (my_dqblk64
));
1019 munge_dqblk(&my_dqblk
, &my_dqblk64
, FALSE
);
1023 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk
, sizeof (my_dqblk
));
1027 /* uap->arg is a pointer to an integer */
1028 datap
= (caddr_t
) "a_status
;
1036 error
= VFS_QUOTACTL(mp
, uap
->cmd
, uap
->uid
, datap
, &context
);
1039 switch (quota_cmd
) {
1042 kfree(datap
, MAXPATHLEN
);
1045 /* uap->arg is a pointer to a dqblk structure we need to copy out to */
1047 if (proc_is64bit(p
)) {
1048 struct user_dqblk my_dqblk64
;
1049 munge_dqblk(&my_dqblk
, &my_dqblk64
, TRUE
);
1050 error
= copyout((caddr_t
)&my_dqblk64
, uap
->arg
, sizeof (my_dqblk64
));
1053 error
= copyout(datap
, uap
->arg
, sizeof (struct dqblk
));
1058 /* uap->arg is a pointer to an integer */
1060 error
= copyout(datap
, uap
->arg
, sizeof(quota_status
));
1071 * Get filesystem statistics.
1075 statfs(struct proc
*p
, register struct statfs_args
*uap
, __unused register_t
*retval
)
1078 struct vfsstatfs
*sp
;
1080 struct nameidata nd
;
1081 struct vfs_context context
;
1084 context
.vc_proc
= p
;
1085 context
.vc_ucred
= kauth_cred_get();
1087 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1088 UIO_USERSPACE
, uap
->path
, &context
);
1094 sp
= &mp
->mnt_vfsstat
;
1097 error
= vfs_update_vfsstat(mp
, &context
);
1102 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1107 * Get filesystem statistics.
1111 fstatfs(struct proc
*p
, register struct fstatfs_args
*uap
, __unused register_t
*retval
)
1115 struct vfsstatfs
*sp
;
1117 struct vfs_context context
;
1119 context
.vc_proc
= p
;
1120 context
.vc_ucred
= kauth_cred_get();
1122 AUDIT_ARG(fd
, uap
->fd
);
1124 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1127 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
1134 sp
= &mp
->mnt_vfsstat
;
1135 if ((error
= vfs_update_vfsstat(mp
, &context
)) != 0) {
1141 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1147 struct getfsstat_struct
{
1157 getfsstat_callback(mount_t mp
, void * arg
)
1160 struct getfsstat_struct
*fstp
= (struct getfsstat_struct
*)arg
;
1161 struct vfsstatfs
*sp
;
1162 struct proc
* p
= current_proc();
1164 struct vfs_context context
;
1166 context
.vc_proc
= p
;
1167 context
.vc_ucred
= kauth_cred_get();
1169 if (fstp
->sfsp
&& fstp
->count
< fstp
->maxcount
) {
1170 sp
= &mp
->mnt_vfsstat
;
1172 * If MNT_NOWAIT is specified, do not refresh the
1173 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
1175 if (((fstp
->flags
& MNT_NOWAIT
) == 0 || (fstp
->flags
& MNT_WAIT
)) &&
1176 (error
= vfs_update_vfsstat(mp
, &context
))) {
1177 KAUTH_DEBUG("vfs_update_vfsstat returned %d", error
);
1178 return(VFS_RETURNED
);
1182 * Need to handle LP64 version of struct statfs
1184 error
= munge_statfs(mp
, sp
, fstp
->sfsp
, &my_size
, IS_64BIT_PROCESS(p
), FALSE
);
1186 fstp
->error
= error
;
1187 return(VFS_RETURNED_DONE
);
1189 fstp
->sfsp
+= my_size
;
1192 return(VFS_RETURNED
);
1196 * Get statistics on all filesystems.
1199 getfsstat(__unused proc_t p
, struct getfsstat_args
*uap
, int *retval
)
1202 int count
, maxcount
;
1203 struct getfsstat_struct fst
;
1205 if (IS_64BIT_PROCESS(p
)) {
1206 maxcount
= uap
->bufsize
/ sizeof(struct user_statfs
);
1209 maxcount
= uap
->bufsize
/ sizeof(struct statfs
);
1215 fst
.flags
= uap
->flags
;
1218 fst
.maxcount
= maxcount
;
1221 vfs_iterate(0, getfsstat_callback
, &fst
);
1224 KAUTH_DEBUG("ERROR - %s gets %d", p
->p_comm
, fst
.error
);
1228 if (fst
.sfsp
&& fst
.count
> fst
.maxcount
)
1229 *retval
= fst
.maxcount
;
1231 *retval
= fst
.count
;
1235 #if COMPAT_GETFSSTAT
1236 ogetfsstat(p
, uap
, retval
)
1238 register struct getfsstat_args
*uap
;
1246 * Change current working directory to a given file descriptor.
1250 fchdir(struct proc
*p
, struct fchdir_args
*uap
, __unused register_t
*retval
)
1252 register struct filedesc
*fdp
= p
->p_fd
;
1253 struct vnode
*vp
, *tdp
, *tvp
;
1256 struct vfs_context context
;
1258 context
.vc_proc
= p
;
1259 context
.vc_ucred
= kauth_cred_get();
1261 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1263 if ( (error
= vnode_getwithref(vp
)) ) {
1268 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
1270 if (vp
->v_type
!= VDIR
)
1273 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, &context
);
1274 while (!error
&& (mp
= vp
->v_mountedhere
) != NULL
) {
1275 if (vfs_busy(mp
, LK_NOWAIT
)) {
1279 error
= VFS_ROOT(mp
, &tdp
, &context
);
1288 if ( (error
= vnode_ref(vp
)) )
1310 * Change current working directory (``.'').
1314 chdir(struct proc
*p
, struct chdir_args
*uap
, __unused register_t
*retval
)
1316 register struct filedesc
*fdp
= p
->p_fd
;
1318 struct nameidata nd
;
1320 struct vfs_context context
;
1322 context
.vc_proc
= p
;
1323 context
.vc_ucred
= kauth_cred_get();
1325 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1326 UIO_USERSPACE
, uap
->path
, &context
);
1327 error
= change_dir(&nd
, &context
);
1330 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
1331 vnode_put(nd
.ni_vp
);
1335 * drop the iocount we picked up in change_dir
1337 vnode_put(nd
.ni_vp
);
1341 fdp
->fd_cdir
= nd
.ni_vp
;
1351 * Change notion of root (``/'') directory.
1355 chroot(struct proc
*p
, struct chroot_args
*uap
, __unused register_t
*retval
)
1357 register struct filedesc
*fdp
= p
->p_fd
;
1359 struct nameidata nd
;
1360 boolean_t shared_regions_active
;
1362 struct vfs_context context
;
1364 context
.vc_proc
= p
;
1365 context
.vc_ucred
= kauth_cred_get();
1367 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
1370 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1371 UIO_USERSPACE
, uap
->path
, &context
);
1372 error
= change_dir(&nd
, &context
);
1376 if(p
->p_flag
& P_NOSHLIB
) {
1377 shared_regions_active
= FALSE
;
1379 shared_regions_active
= TRUE
;
1381 if ((error
= clone_system_shared_regions(shared_regions_active
,
1382 TRUE
, /* chain_regions */
1384 vnode_put(nd
.ni_vp
);
1387 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
1388 vnode_put(nd
.ni_vp
);
1391 vnode_put(nd
.ni_vp
);
1395 fdp
->fd_rdir
= nd
.ni_vp
;
1396 fdp
->fd_flags
|= FD_CHROOT
;
1406 * Common routine for chroot and chdir.
1409 change_dir(struct nameidata
*ndp
, vfs_context_t ctx
)
1414 if ((error
= namei(ndp
)))
1418 if (vp
->v_type
!= VDIR
)
1421 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, ctx
);
1429 * Check permissions, allocate an open file structure,
1430 * and call the device open routine if any.
1433 #warning XXX implement uid, gid
1435 open1(vfs_context_t ctx
, user_addr_t upath
, int uflags
, struct vnode_attr
*vap
, register_t
*retval
)
1437 struct proc
*p
= vfs_context_proc(ctx
);
1438 register struct filedesc
*fdp
= p
->p_fd
;
1439 register struct fileproc
*fp
;
1440 register struct vnode
*vp
;
1442 struct fileproc
*nfp
;
1443 int type
, indx
, error
;
1445 struct nameidata nd
;
1449 if ((oflags
& O_ACCMODE
) == O_ACCMODE
)
1451 flags
= FFLAGS(uflags
);
1453 AUDIT_ARG(fflags
, oflags
);
1454 AUDIT_ARG(mode
, vap
->va_mode
);
1456 if ( (error
= falloc(p
, &nfp
, &indx
)) ) {
1460 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1461 UIO_USERSPACE
, upath
, ctx
);
1462 p
->p_dupfd
= -indx
- 1; /* XXX check for fdopen */
1464 if ((error
= vn_open_auth(&nd
, &flags
, vap
))) {
1465 if ((error
== ENODEV
|| error
== ENXIO
) && (p
->p_dupfd
>= 0)) { /* XXX from fdopen */
1466 if ((error
= dupfdopen(fdp
, indx
, p
->p_dupfd
, flags
, error
)) == 0) {
1467 fp_drop(p
, indx
, 0, 0);
1472 if (error
== ERESTART
)
1474 fp_free(p
, indx
, fp
);
1481 fp
->f_fglob
->fg_flag
= flags
& (FMASK
| O_EVTONLY
);
1482 fp
->f_fglob
->fg_type
= DTYPE_VNODE
;
1483 fp
->f_fglob
->fg_ops
= &vnops
;
1484 fp
->f_fglob
->fg_data
= (caddr_t
)vp
;
1486 if (flags
& (O_EXLOCK
| O_SHLOCK
)) {
1487 lf
.l_whence
= SEEK_SET
;
1490 if (flags
& O_EXLOCK
)
1491 lf
.l_type
= F_WRLCK
;
1493 lf
.l_type
= F_RDLCK
;
1495 if ((flags
& FNONBLOCK
) == 0)
1497 if ((error
= VNOP_ADVLOCK(vp
, (caddr_t
)fp
->f_fglob
, F_SETLK
, &lf
, type
, ctx
)))
1499 fp
->f_fglob
->fg_flag
|= FHASLOCK
;
1502 /* try to truncate by setting the size attribute */
1503 if ((flags
& O_TRUNC
) && ((error
= vnode_setsize(vp
, (off_t
)0, 0, ctx
)) != 0))
1509 *fdflags(p
, indx
) &= ~UF_RESERVED
;
1510 fp_drop(p
, indx
, fp
, 1);
1517 vn_close(vp
, fp
->f_fglob
->fg_flag
, fp
->f_fglob
->fg_cred
, p
);
1519 fp_free(p
, indx
, fp
);
1526 open_extended(struct proc
*p
, struct open_extended_args
*uap
, register_t
*retval
)
1528 struct vfs_context context
;
1529 register struct filedesc
*fdp
= p
->p_fd
;
1531 kauth_filesec_t xsecdst
;
1532 struct vnode_attr va
;
1536 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
1537 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
1540 context
.vc_proc
= p
;
1541 context
.vc_ucred
= kauth_cred_get();
1544 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
1545 VATTR_SET(&va
, va_mode
, cmode
);
1546 if (uap
->uid
!= KAUTH_UID_NONE
)
1547 VATTR_SET(&va
, va_uid
, uap
->uid
);
1548 if (uap
->gid
!= KAUTH_GID_NONE
)
1549 VATTR_SET(&va
, va_gid
, uap
->gid
);
1550 if (xsecdst
!= NULL
)
1551 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
1553 ciferror
= open1(&context
, uap
->path
, uap
->flags
, &va
, retval
);
1554 if (xsecdst
!= NULL
)
1555 kauth_filesec_free(xsecdst
);
1561 open(struct proc
*p
, struct open_args
*uap
, register_t
*retval
)
1563 struct vfs_context context
;
1564 register struct filedesc
*fdp
= p
->p_fd
;
1565 struct vnode_attr va
;
1568 context
.vc_proc
= p
;
1569 context
.vc_ucred
= kauth_cred_get();
1572 /* Mask off all but regular access permissions */
1573 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
1574 VATTR_SET(&va
, va_mode
, cmode
& ACCESSPERMS
);
1576 return(open1(&context
, uap
->path
, uap
->flags
, &va
, retval
));
1581 * Create a special file.
1583 static int mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
);
1586 mknod(struct proc
*p
, register struct mknod_args
*uap
, __unused register_t
*retval
)
1588 struct vnode_attr va
;
1589 struct vfs_context context
;
1592 struct nameidata nd
;
1595 context
.vc_proc
= p
;
1596 context
.vc_ucred
= kauth_cred_get();
1599 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1600 VATTR_SET(&va
, va_rdev
, uap
->dev
);
1602 /* If it's a mknod() of a FIFO, call mkfifo1() instead */
1603 if ((uap
->mode
& S_IFMT
) == S_IFIFO
)
1604 return(mkfifo1(&context
, uap
->path
, &va
));
1606 AUDIT_ARG(mode
, uap
->mode
);
1607 AUDIT_ARG(dev
, uap
->dev
);
1609 if ((error
= suser(context
.vc_ucred
, &p
->p_acflag
)))
1611 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1612 UIO_USERSPACE
, uap
->path
, &context
);
1624 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
1627 switch (uap
->mode
& S_IFMT
) {
1628 case S_IFMT
: /* used by badsect to flag bad sectors */
1629 VATTR_SET(&va
, va_type
, VBAD
);
1632 VATTR_SET(&va
, va_type
, VCHR
);
1635 VATTR_SET(&va
, va_type
, VBLK
);
1645 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, CREATE
, &context
);
1647 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, &va
, 0, &context
);
1653 int update_flags
= 0;
1655 // Make sure the name & parent pointers are hooked up
1656 if (vp
->v_name
== NULL
)
1657 update_flags
|= VNODE_UPDATE_NAME
;
1658 if (vp
->v_parent
== NULLVP
)
1659 update_flags
|= VNODE_UPDATE_PARENT
;
1662 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
1664 add_fsevent(FSE_CREATE_FILE
, &context
,
1671 * nameidone has to happen before we vnode_put(dvp)
1672 * since it may need to release the fs_nodelock on the dvp
1684 * Create a named pipe.
1687 mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
)
1691 struct nameidata nd
;
1693 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1694 UIO_USERSPACE
, upath
, ctx
);
1701 /* check that this is a new file and authorize addition */
1706 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
1709 VATTR_SET(vap
, va_type
, VFIFO
);
1711 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
);
1714 * nameidone has to happen before we vnode_put(dvp)
1715 * since it may need to release the fs_nodelock on the dvp
1727 mkfifo_extended(struct proc
*p
, struct mkfifo_extended_args
*uap
, __unused register_t
*retval
)
1730 kauth_filesec_t xsecdst
;
1731 struct vfs_context context
;
1732 struct vnode_attr va
;
1734 xsecdst
= KAUTH_FILESEC_NONE
;
1735 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
1736 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
1740 context
.vc_proc
= p
;
1741 context
.vc_ucred
= kauth_cred_get();
1744 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1745 if (uap
->uid
!= KAUTH_UID_NONE
)
1746 VATTR_SET(&va
, va_uid
, uap
->uid
);
1747 if (uap
->gid
!= KAUTH_GID_NONE
)
1748 VATTR_SET(&va
, va_gid
, uap
->gid
);
1749 if (xsecdst
!= KAUTH_FILESEC_NONE
)
1750 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
1752 ciferror
= mkfifo1(&context
, uap
->path
, &va
);
1754 if (xsecdst
!= KAUTH_FILESEC_NONE
)
1755 kauth_filesec_free(xsecdst
);
1761 mkfifo(struct proc
*p
, register struct mkfifo_args
*uap
, __unused register_t
*retval
)
1763 struct vfs_context context
;
1764 struct vnode_attr va
;
1766 context
.vc_proc
= p
;
1767 context
.vc_ucred
= kauth_cred_get();
1770 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1772 return(mkfifo1(&context
, uap
->path
, &va
));
1776 * Make a hard file link.
1780 link(struct proc
*p
, register struct link_args
*uap
, __unused register_t
*retval
)
1782 vnode_t vp
, dvp
, lvp
;
1783 struct nameidata nd
;
1784 struct vfs_context context
;
1787 int need_event
, has_listeners
;
1789 context
.vc_proc
= p
;
1790 context
.vc_ucred
= kauth_cred_get();
1791 vp
= dvp
= lvp
= NULLVP
;
1793 /* look up the object we are linking to */
1794 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1795 UIO_USERSPACE
, uap
->path
, &context
);
1803 /* we're not allowed to link to directories */
1804 if (vp
->v_type
== VDIR
) {
1805 error
= EPERM
; /* POSIX */
1809 /* or to anything that kauth doesn't want us to (eg. immutable items) */
1810 if ((error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_LINKTARGET
, &context
)) != 0)
1813 /* lookup the target node */
1814 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1815 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| AUDITVNPATH2
;
1816 nd
.ni_dirp
= uap
->link
;
1822 /* target node must not exist */
1823 if (lvp
!= NULLVP
) {
1827 /* cannot link across mountpoints */
1828 if (vnode_mount(vp
) != vnode_mount(dvp
)) {
1833 /* authorize creation of the target note */
1834 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
1837 /* and finally make the link */
1838 error
= VNOP_LINK(vp
, dvp
, &nd
.ni_cnd
, &context
);
1842 need_event
= need_fsevent(FSE_CREATE_FILE
, dvp
);
1843 has_listeners
= kauth_authorize_fileop_has_listeners();
1845 if (need_event
|| has_listeners
) {
1846 char *target_path
= NULL
;
1847 char *link_to_path
= NULL
;
1848 int len
, link_name_len
;
1850 /* build the path to the new link file */
1851 target_path
= get_pathbuff();
1853 vn_getpath(dvp
, target_path
, &len
);
1854 target_path
[len
-1] = '/';
1855 strcpy(&target_path
[len
], nd
.ni_cnd
.cn_nameptr
);
1856 len
+= nd
.ni_cnd
.cn_namelen
;
1858 if (has_listeners
) {
1859 /* build the path to file we are linking to */
1860 link_to_path
= get_pathbuff();
1861 link_name_len
= MAXPATHLEN
;
1862 vn_getpath(vp
, link_to_path
, &link_name_len
);
1864 /* call out to allow 3rd party notification of rename.
1865 * Ignore result of kauth_authorize_fileop call.
1867 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_LINK
,
1868 (uintptr_t)link_to_path
, (uintptr_t)target_path
);
1869 if (link_to_path
!= NULL
)
1870 release_pathbuff(link_to_path
);
1873 /* construct fsevent */
1874 if (get_fse_info(vp
, &finfo
, &context
) == 0) {
1875 // build the path to the destination of the link
1876 add_fsevent(FSE_CREATE_FILE
, &context
,
1877 FSE_ARG_STRING
, len
, target_path
,
1878 FSE_ARG_FINFO
, &finfo
,
1882 release_pathbuff(target_path
);
1886 * nameidone has to happen before we vnode_put(dvp)
1887 * since it may need to release the fs_nodelock on the dvp
1900 * Make a symbolic link.
1902 * We could add support for ACLs here too...
1906 symlink(struct proc
*p
, register struct symlink_args
*uap
, __unused register_t
*retval
)
1908 struct vnode_attr va
;
1911 struct nameidata nd
;
1912 struct vfs_context context
;
1916 context
.vc_proc
= p
;
1917 context
.vc_ucred
= kauth_cred_get();
1919 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1920 error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
);
1923 AUDIT_ARG(text
, path
); /* This is the link string */
1925 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1926 UIO_USERSPACE
, uap
->link
, &context
);
1935 VATTR_SET(&va
, va_type
, VLNK
);
1936 VATTR_SET(&va
, va_mode
, ACCESSPERMS
& ~p
->p_fd
->fd_cmask
);
1939 error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
);
1940 /* get default ownership, etc. */
1942 error
= vnode_authattr_new(dvp
, &va
, 0, &context
);
1944 error
= VNOP_SYMLINK(dvp
, &vp
, &nd
.ni_cnd
, &va
, path
, &context
);
1946 /* do fallback attribute handling */
1948 error
= vnode_setattr_fallback(vp
, &va
, &context
);
1951 int update_flags
= 0;
1954 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
1955 nd
.ni_cnd
.cn_flags
= 0;
1963 #if 0 /* XXX - kauth_todo - is KAUTH_FILEOP_SYMLINK needed? */
1964 /* call out to allow 3rd party notification of rename.
1965 * Ignore result of kauth_authorize_fileop call.
1967 if (kauth_authorize_fileop_has_listeners() &&
1969 char *new_link_path
= NULL
;
1972 /* build the path to the new link file */
1973 new_link_path
= get_pathbuff();
1975 vn_getpath(dvp
, new_link_path
, &len
);
1976 new_link_path
[len
- 1] = '/';
1977 strcpy(&new_link_path
[len
], nd
.ni_cnd
.cn_nameptr
);
1979 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_SYMLINK
,
1980 (uintptr_t)path
, (uintptr_t)new_link_path
);
1981 if (new_link_path
!= NULL
)
1982 release_pathbuff(new_link_path
);
1985 // Make sure the name & parent pointers are hooked up
1986 if (vp
->v_name
== NULL
)
1987 update_flags
|= VNODE_UPDATE_NAME
;
1988 if (vp
->v_parent
== NULLVP
)
1989 update_flags
|= VNODE_UPDATE_PARENT
;
1992 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
1994 add_fsevent(FSE_CREATE_FILE
, &context
,
2003 * nameidone has to happen before we vnode_put(dvp)
2004 * since it may need to release the fs_nodelock on the dvp
2012 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
2018 * Delete a whiteout from the filesystem.
2021 #warning XXX authorization not implmented for whiteouts
2023 undelete(struct proc
*p
, register struct undelete_args
*uap
, __unused register_t
*retval
)
2026 struct nameidata nd
;
2027 struct vfs_context context
;
2030 context
.vc_proc
= p
;
2031 context
.vc_ucred
= kauth_cred_get();
2033 NDINIT(&nd
, DELETE
, LOCKPARENT
|DOWHITEOUT
|AUDITVNPATH1
,
2034 UIO_USERSPACE
, uap
->path
, &context
);
2041 if (vp
== NULLVP
&& (nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
2042 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, DELETE
, &context
);
2047 * nameidone has to happen before we vnode_put(dvp)
2048 * since it may need to release the fs_nodelock on the dvp
2060 * Delete a name from the filesystem.
2064 _unlink(struct proc
*p
, struct unlink_args
*uap
, __unused register_t
*retval
, int nodelbusy
)
2068 struct nameidata nd
;
2069 struct vfs_context context
;
2070 struct componentname
*cnp
;
2073 context
.vc_proc
= p
;
2074 context
.vc_ucred
= kauth_cred_get();
2076 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
2077 UIO_USERSPACE
, uap
->path
, &context
);
2080 /* With Carbon delete semantics, busy files cannot be deleted */
2082 flags
|= VNODE_REMOVE_NODELETEBUSY
;
2090 if (vp
->v_type
== VDIR
) {
2091 error
= EPERM
; /* POSIX */
2094 * The root of a mounted filesystem cannot be deleted.
2096 if (vp
->v_flag
& VROOT
) {
2100 /* authorize the delete operation */
2102 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, &context
);
2109 if (need_fsevent(FSE_DELETE
, dvp
)) {
2110 path
= get_pathbuff();
2112 vn_getpath(vp
, path
, &len
);
2113 get_fse_info(vp
, &finfo
, &context
);
2115 error
= VNOP_REMOVE(dvp
, vp
, &nd
.ni_cnd
, flags
, &context
);
2117 if ( !error
&& path
!= NULL
) {
2118 add_fsevent(FSE_DELETE
, &context
,
2119 FSE_ARG_STRING
, len
, path
,
2120 FSE_ARG_FINFO
, &finfo
,
2124 release_pathbuff(path
);
2127 * nameidone has to happen before we vnode_put(dvp)
2128 * since it may need to release the fs_nodelock on the dvp
2137 * Delete a name from the filesystem using POSIX semantics.
2140 unlink(p
, uap
, retval
)
2142 struct unlink_args
*uap
;
2145 return _unlink(p
, uap
, retval
, 0);
2149 * Delete a name from the filesystem using Carbon semantics.
2152 delete(p
, uap
, retval
)
2154 struct delete_args
*uap
;
2157 return _unlink(p
, (struct unlink_args
*)uap
, retval
, 1);
2161 * Reposition read/write file offset.
2164 lseek(p
, uap
, retval
)
2166 register struct lseek_args
*uap
;
2169 struct fileproc
*fp
;
2171 struct vfs_context context
;
2172 off_t offset
= uap
->offset
, file_size
;
2175 if ( (error
= fp_getfvp(p
,uap
->fd
, &fp
, &vp
)) ) {
2176 if (error
== ENOTSUP
)
2180 if (vnode_isfifo(vp
)) {
2184 if ( (error
= vnode_getwithref(vp
)) ) {
2189 switch (uap
->whence
) {
2191 offset
+= fp
->f_fglob
->fg_offset
;
2194 context
.vc_proc
= p
;
2195 context
.vc_ucred
= kauth_cred_get();
2196 if ((error
= vnode_size(vp
, &file_size
, &context
)) != 0)
2198 offset
+= file_size
;
2206 if (uap
->offset
> 0 && offset
< 0) {
2207 /* Incremented/relative move past max size */
2211 * Allow negative offsets on character devices, per
2212 * POSIX 1003.1-2001. Most likely for writing disk
2215 if (offset
< 0 && vp
->v_type
!= VCHR
) {
2216 /* Decremented/relative move before start */
2220 fp
->f_fglob
->fg_offset
= offset
;
2221 *retval
= fp
->f_fglob
->fg_offset
;
2225 (void)vnode_put(vp
);
2232 * Check access permissions.
2235 access1(vnode_t vp
, vnode_t dvp
, int uflags
, vfs_context_t ctx
)
2237 kauth_action_t action
;
2241 * If just the regular access bits, convert them to something
2242 * that vnode_authorize will understand.
2244 if (!(uflags
& _ACCESS_EXTENDED_MASK
)) {
2247 action
|= KAUTH_VNODE_READ_DATA
; /* aka KAUTH_VNODE_LIST_DIRECTORY */
2248 if (uflags
& W_OK
) {
2249 if (vnode_isdir(vp
)) {
2250 action
|= KAUTH_VNODE_ADD_FILE
|
2251 KAUTH_VNODE_ADD_SUBDIRECTORY
;
2252 /* might want delete rights here too */
2254 action
|= KAUTH_VNODE_WRITE_DATA
;
2257 if (uflags
& X_OK
) {
2258 if (vnode_isdir(vp
)) {
2259 action
|= KAUTH_VNODE_SEARCH
;
2261 action
|= KAUTH_VNODE_EXECUTE
;
2265 /* take advantage of definition of uflags */
2266 action
= uflags
>> 8;
2269 /* action == 0 means only check for existence */
2271 error
= vnode_authorize(vp
, dvp
, action
| KAUTH_VNODE_ACCESS
, ctx
);
2281 /* XXX need to support the check-as uid argument */
2283 access_extended(__unused
struct proc
*p
, struct access_extended_args
*uap
, __unused register_t
*retval
)
2285 struct accessx_descriptor
*input
;
2287 int error
, limit
, nent
, i
, j
, wantdelete
;
2288 struct vfs_context context
;
2289 struct nameidata nd
;
2298 context
.vc_ucred
= NULL
;
2300 /* check input size and fetch descriptor array into allocated storage */
2301 if (uap
->size
> ACCESSX_MAX_TABLESIZE
)
2303 if (uap
->size
< sizeof(struct accessx_descriptor
))
2305 MALLOC(input
, struct accessx_descriptor
*, uap
->size
, M_TEMP
, M_WAITOK
);
2306 if (input
== NULL
) {
2310 error
= copyin(uap
->entries
, input
, uap
->size
);
2315 * Access is defined as checking against the process'
2316 * real identity, even if operations are checking the
2317 * effective identity. So we need to tweak the credential
2320 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
2321 context
.vc_proc
= current_proc();
2324 * Find out how many entries we have, so we can allocate the result array.
2326 limit
= uap
->size
/ sizeof(struct accessx_descriptor
);
2329 for (i
= 0; i
< nent
; i
++) {
2331 * Take the offset to the name string for this entry and convert to an
2332 * input array index, which would be one off the end of the array if this
2333 * was the lowest-addressed name string.
2335 j
= input
[i
].ad_name_offset
/ sizeof(struct accessx_descriptor
);
2341 /* implicit reference to previous name, not a real offset */
2343 /* first entry must have a name string */
2353 if (nent
> ACCESSX_MAX_DESCRIPTORS
) {
2357 MALLOC(result
, errno_t
*, nent
* sizeof(errno_t
), M_TEMP
, M_WAITOK
);
2358 if (result
== NULL
) {
2367 for (i
= 0; i
< nent
; i
++) {
2369 * Looking up a new name?
2371 if (input
[i
].ad_name_offset
!= 0) {
2372 /* discard old vnodes */
2382 /* scan forwards to see if we need the parent this time */
2383 wantdelete
= input
[i
].ad_flags
& _DELETE_OK
;
2384 for (j
= i
+ 1; (j
< nent
) && (input
[j
].ad_name_offset
== 0); j
++)
2385 if (input
[j
].ad_flags
& _DELETE_OK
)
2388 niopts
= FOLLOW
| AUDITVNPATH1
;
2389 /* need parent for vnode_authorize for deletion test */
2391 niopts
|= WANTPARENT
;
2394 NDINIT(&nd
, LOOKUP
, niopts
, UIO_SYSSPACE
, CAST_USER_ADDR_T((const char *)input
+ input
[i
].ad_name_offset
), &context
);
2405 * Handle lookup errors.
2415 /* run this access check */
2416 result
[i
] = access1(vp
, dvp
, input
[i
].ad_flags
, &context
);
2419 /* fatal lookup error */
2425 /* copy out results */
2426 error
= copyout(result
, uap
->results
, nent
* sizeof(errno_t
));
2430 FREE(input
, M_TEMP
);
2432 FREE(result
, M_TEMP
);
2437 if (context
.vc_ucred
)
2438 kauth_cred_rele(context
.vc_ucred
);
2443 access(__unused
struct proc
*p
, register struct access_args
*uap
, __unused register_t
*retval
)
2446 struct nameidata nd
;
2448 struct vfs_context context
;
2451 * Access is defined as checking against the process'
2452 * real identity, even if operations are checking the
2453 * effective identity. So we need to tweak the credential
2456 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
2457 context
.vc_proc
= current_proc();
2459 niopts
= FOLLOW
| AUDITVNPATH1
;
2460 /* need parent for vnode_authorize for deletion test */
2461 if (uap
->flags
& _DELETE_OK
)
2462 niopts
|= WANTPARENT
;
2463 NDINIT(&nd
, LOOKUP
, niopts
, UIO_USERSPACE
, uap
->path
, &context
);
2468 error
= access1(nd
.ni_vp
, nd
.ni_dvp
, uap
->flags
, &context
);
2470 vnode_put(nd
.ni_vp
);
2471 if (uap
->flags
& _DELETE_OK
)
2472 vnode_put(nd
.ni_dvp
);
2476 kauth_cred_rele(context
.vc_ucred
);
2482 stat2(vfs_context_t ctx
, struct nameidata
*ndp
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2485 struct user_stat user_sb
;
2488 kauth_filesec_t fsec
;
2489 size_t xsecurity_bufsize
;
2494 fsec
= KAUTH_FILESEC_NONE
;
2495 error
= vn_stat(ndp
->ni_vp
, &sb
, (xsecurity
!= USER_ADDR_NULL
? &fsec
: NULL
), ctx
);
2496 vnode_put(ndp
->ni_vp
);
2501 /* Zap spare fields */
2503 sb
.st_qspare
[0] = 0LL;
2504 sb
.st_qspare
[1] = 0LL;
2505 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
2506 munge_stat(&sb
, &user_sb
);
2507 my_size
= sizeof(user_sb
);
2508 sbp
= (caddr_t
)&user_sb
;
2511 my_size
= sizeof(sb
);
2514 if ((error
= copyout(sbp
, ub
, my_size
)) != 0)
2517 /* caller wants extended security information? */
2518 if (xsecurity
!= USER_ADDR_NULL
) {
2520 /* did we get any? */
2521 if (fsec
== KAUTH_FILESEC_NONE
) {
2522 if (susize(xsecurity_size
, 0) != 0) {
2527 /* find the user buffer size */
2528 xsecurity_bufsize
= fusize(xsecurity_size
);
2530 /* copy out the actual data size */
2531 if (susize(xsecurity_size
, KAUTH_FILESEC_COPYSIZE(fsec
)) != 0) {
2536 /* if the caller supplied enough room, copy out to it */
2537 if (xsecurity_bufsize
>= KAUTH_FILESEC_COPYSIZE(fsec
))
2538 error
= copyout(fsec
, xsecurity
, KAUTH_FILESEC_COPYSIZE(fsec
));
2542 if (fsec
!= KAUTH_FILESEC_NONE
)
2543 kauth_filesec_free(fsec
);
2548 * Get file status; this version follows links.
2551 stat1(struct proc
*p
, user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2553 struct nameidata nd
;
2554 struct vfs_context context
;
2556 context
.vc_proc
= p
;
2557 context
.vc_ucred
= kauth_cred_get();
2559 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2560 UIO_USERSPACE
, path
, &context
);
2561 return(stat2(&context
, &nd
, ub
, xsecurity
, xsecurity_size
));
2565 stat_extended(struct proc
*p
, struct stat_extended_args
*uap
, __unused register_t
*retval
)
2567 return (stat1(p
, uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
));
2571 stat(struct proc
*p
, struct stat_args
*uap
, __unused register_t
*retval
)
2573 return(stat1(p
, uap
->path
, uap
->ub
, 0, 0));
2577 * Get file status; this version does not follow links.
2580 lstat1(struct proc
*p
, user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2582 struct nameidata nd
;
2583 struct vfs_context context
;
2585 context
.vc_proc
= p
;
2586 context
.vc_ucred
= kauth_cred_get();
2588 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
2589 UIO_USERSPACE
, path
, &context
);
2591 return(stat2(&context
, &nd
, ub
, xsecurity
, xsecurity_size
));
2595 lstat_extended(struct proc
*p
, struct lstat_extended_args
*uap
, __unused register_t
*retval
)
2597 return (lstat1(p
, uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
));
2601 lstat(struct proc
*p
, struct lstat_args
*uap
, __unused register_t
*retval
)
2603 return(lstat1(p
, uap
->path
, uap
->ub
, 0, 0));
2607 * Get configurable pathname variables.
2611 pathconf(p
, uap
, retval
)
2613 register struct pathconf_args
*uap
;
2617 struct nameidata nd
;
2618 struct vfs_context context
;
2620 context
.vc_proc
= p
;
2621 context
.vc_ucred
= kauth_cred_get();
2623 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2624 UIO_USERSPACE
, uap
->path
, &context
);
2629 error
= vn_pathconf(nd
.ni_vp
, uap
->name
, retval
, &context
);
2631 vnode_put(nd
.ni_vp
);
2637 * Return target name of a symbolic link.
2641 readlink(p
, uap
, retval
)
2643 register struct readlink_args
*uap
;
2646 register struct vnode
*vp
;
2648 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
2650 struct nameidata nd
;
2651 struct vfs_context context
;
2652 char uio_buf
[ UIO_SIZEOF(1) ];
2654 context
.vc_proc
= p
;
2655 context
.vc_ucred
= kauth_cred_get();
2657 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
2658 UIO_USERSPACE
, uap
->path
, &context
);
2666 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
2667 &uio_buf
[0], sizeof(uio_buf
));
2668 uio_addiov(auio
, uap
->buf
, uap
->count
);
2669 if (vp
->v_type
!= VLNK
)
2672 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, &context
);
2674 error
= VNOP_READLINK(vp
, auio
, &context
);
2677 // LP64todo - fix this
2678 *retval
= uap
->count
- (int)uio_resid(auio
);
2683 * Change file flags.
2686 chflags1(vnode_t vp
, int flags
, vfs_context_t ctx
)
2688 struct vnode_attr va
;
2689 kauth_action_t action
;
2693 VATTR_SET(&va
, va_flags
, flags
);
2695 /* request authorisation, disregard immutability */
2696 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
2699 * Request that the auth layer disregard those file flags it's allowed to when
2700 * authorizing this operation; we need to do this in order to be able to
2701 * clear immutable flags.
2703 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
| KAUTH_VNODE_NOIMMUTABLE
, ctx
)) != 0))
2705 error
= vnode_setattr(vp
, &va
, ctx
);
2713 * Change flags of a file given a path name.
2717 chflags(struct proc
*p
, register struct chflags_args
*uap
, __unused register_t
*retval
)
2719 register struct vnode
*vp
;
2720 struct vfs_context context
;
2722 struct nameidata nd
;
2724 context
.vc_proc
= p
;
2725 context
.vc_ucred
= kauth_cred_get();
2727 AUDIT_ARG(fflags
, uap
->flags
);
2728 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2729 UIO_USERSPACE
, uap
->path
, &context
);
2736 error
= chflags1(vp
, uap
->flags
, &context
);
2742 * Change flags of a file given a file descriptor.
2746 fchflags(struct proc
*p
, register struct fchflags_args
*uap
, __unused register_t
*retval
)
2748 struct vfs_context context
;
2752 AUDIT_ARG(fd
, uap
->fd
);
2753 AUDIT_ARG(fflags
, uap
->flags
);
2754 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
2757 if ((error
= vnode_getwithref(vp
))) {
2762 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2764 context
.vc_proc
= p
;
2765 context
.vc_ucred
= kauth_cred_get();
2767 error
= chflags1(vp
, uap
->flags
, &context
);
2774 * Change security information on a filesystem object.
2777 chmod2(vfs_context_t ctx
, struct vnode
*vp
, struct vnode_attr
*vap
)
2779 kauth_action_t action
;
2782 AUDIT_ARG(mode
, (mode_t
)vap
->va_mode
);
2783 #warning XXX audit new args
2785 /* make sure that the caller is allowed to set this security information */
2786 if (((error
= vnode_authattr(vp
, vap
, &action
, ctx
)) != 0) ||
2787 ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
2788 if (error
== EACCES
)
2793 error
= vnode_setattr(vp
, vap
, ctx
);
2800 * Change mode of a file given path name.
2803 chmod1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
2805 struct nameidata nd
;
2808 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2809 UIO_USERSPACE
, path
, ctx
);
2810 if ((error
= namei(&nd
)))
2812 error
= chmod2(ctx
, nd
.ni_vp
, vap
);
2813 vnode_put(nd
.ni_vp
);
2819 chmod_extended(struct proc
*p
, struct chmod_extended_args
*uap
, __unused register_t
*retval
)
2821 struct vfs_context context
;
2823 struct vnode_attr va
;
2824 kauth_filesec_t xsecdst
;
2827 if (uap
->mode
!= -1)
2828 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2829 if (uap
->uid
!= KAUTH_UID_NONE
)
2830 VATTR_SET(&va
, va_uid
, uap
->uid
);
2831 if (uap
->gid
!= KAUTH_GID_NONE
)
2832 VATTR_SET(&va
, va_gid
, uap
->gid
);
2835 switch(uap
->xsecurity
) {
2836 /* explicit remove request */
2837 case CAST_USER_ADDR_T((void *)1): /* _FILESEC_REMOVE_ACL */
2838 VATTR_SET(&va
, va_acl
, NULL
);
2841 case USER_ADDR_NULL
:
2844 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
2846 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2847 KAUTH_DEBUG("CHMOD - setting ACL with %d entries", va
.va_acl
->acl_entrycount
);
2849 context
.vc_proc
= p
;
2850 context
.vc_ucred
= kauth_cred_get();
2852 error
= chmod1(&context
, uap
->path
, &va
);
2854 if (xsecdst
!= NULL
)
2855 kauth_filesec_free(xsecdst
);
2860 chmod(struct proc
*p
, register struct chmod_args
*uap
, __unused register_t
*retval
)
2862 struct vfs_context context
;
2863 struct vnode_attr va
;
2866 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2868 context
.vc_proc
= p
;
2869 context
.vc_ucred
= kauth_cred_get();
2871 return(chmod1(&context
, uap
->path
, &va
));
2875 * Change mode of a file given a file descriptor.
2878 fchmod1(struct proc
*p
, int fd
, struct vnode_attr
*vap
)
2882 struct vfs_context context
;
2884 context
.vc_proc
= p
;
2885 context
.vc_ucred
= kauth_cred_get();
2889 if ((error
= file_vnode(fd
, &vp
)) != 0)
2891 if ((error
= vnode_getwithref(vp
)) != 0) {
2895 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2897 error
= chmod2(&context
, vp
, vap
);
2898 (void)vnode_put(vp
);
2905 fchmod_extended(struct proc
*p
, struct fchmod_extended_args
*uap
, __unused register_t
*retval
)
2908 struct vnode_attr va
;
2909 kauth_filesec_t xsecdst
;
2912 if (uap
->mode
!= -1)
2913 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2914 if (uap
->uid
!= KAUTH_UID_NONE
)
2915 VATTR_SET(&va
, va_uid
, uap
->uid
);
2916 if (uap
->gid
!= KAUTH_GID_NONE
)
2917 VATTR_SET(&va
, va_gid
, uap
->gid
);
2920 switch(uap
->xsecurity
) {
2921 case USER_ADDR_NULL
:
2922 VATTR_SET(&va
, va_acl
, NULL
);
2924 case CAST_USER_ADDR_T(-1):
2927 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
2929 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2932 error
= fchmod1(p
, uap
->fd
, &va
);
2935 switch(uap
->xsecurity
) {
2936 case USER_ADDR_NULL
:
2937 case CAST_USER_ADDR_T(-1):
2940 if (xsecdst
!= NULL
)
2941 kauth_filesec_free(xsecdst
);
2947 fchmod(struct proc
*p
, register struct fchmod_args
*uap
, __unused register_t
*retval
)
2949 struct vnode_attr va
;
2952 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2954 return(fchmod1(p
, uap
->fd
, &va
));
2959 * Set ownership given a path name.
2963 chown1(vfs_context_t ctx
, register struct chown_args
*uap
, __unused register_t
*retval
, int follow
)
2965 register struct vnode
*vp
;
2966 struct vnode_attr va
;
2968 struct nameidata nd
;
2969 kauth_action_t action
;
2971 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
2973 NDINIT(&nd
, LOOKUP
, (follow
? FOLLOW
: 0) | AUDITVNPATH1
,
2974 UIO_USERSPACE
, uap
->path
, ctx
);
2983 * XXX A TEMPORARY HACK FOR NOW: Try to track console_user
2984 * by looking for chown() calls on /dev/console from a console process.
2986 if ((vp
) && (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
) && (vp
->v_specinfo
) &&
2987 (major(vp
->v_specinfo
->si_rdev
) == CONSMAJOR
) &&
2988 (minor(vp
->v_specinfo
->si_rdev
) == 0)) {
2989 console_user
= uap
->uid
;
2992 if (uap
->uid
!= VNOVAL
)
2993 VATTR_SET(&va
, va_uid
, uap
->uid
);
2994 if (uap
->gid
!= VNOVAL
)
2995 VATTR_SET(&va
, va_gid
, uap
->gid
);
2997 /* preflight and authorize attribute changes */
2998 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
3000 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
3002 error
= vnode_setattr(vp
, &va
, ctx
);
3006 * EACCES is only allowed from namei(); permissions failure should
3007 * return EPERM, so we need to translate the error code.
3009 if (error
== EACCES
)
3017 chown(struct proc
*p
, register struct chown_args
*uap
, register_t
*retval
)
3019 struct vfs_context context
;
3021 context
.vc_proc
= p
;
3022 context
.vc_ucred
= kauth_cred_get();
3024 return chown1(&context
, uap
, retval
, 1);
3028 lchown(struct proc
*p
, register struct lchown_args
*uap
, register_t
*retval
)
3030 struct vfs_context context
;
3032 context
.vc_proc
= p
;
3033 context
.vc_ucred
= kauth_cred_get();
3035 /* Argument list identical, but machine generated; cast for chown1() */
3036 return chown1(&context
, (struct chown_args
*)uap
, retval
, 0);
3040 * Set ownership given a file descriptor.
3044 fchown(struct proc
*p
, register struct fchown_args
*uap
, __unused register_t
*retval
)
3046 struct vnode_attr va
;
3047 struct vfs_context context
;
3050 kauth_action_t action
;
3052 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
3053 AUDIT_ARG(fd
, uap
->fd
);
3055 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
3058 if ( (error
= vnode_getwithref(vp
)) ) {
3062 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3065 if (uap
->uid
!= VNOVAL
)
3066 VATTR_SET(&va
, va_uid
, uap
->uid
);
3067 if (uap
->gid
!= VNOVAL
)
3068 VATTR_SET(&va
, va_gid
, uap
->gid
);
3070 context
.vc_proc
= p
;
3071 context
.vc_ucred
= kauth_cred_get();
3073 /* preflight and authorize attribute changes */
3074 if ((error
= vnode_authattr(vp
, &va
, &action
, &context
)) != 0)
3076 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0)) {
3077 if (error
== EACCES
)
3081 error
= vnode_setattr(vp
, &va
, &context
);
3084 (void)vnode_put(vp
);
3090 getutimes(usrtvp
, tsp
)
3092 struct timespec
*tsp
;
3094 struct user_timeval tv
[2];
3097 if (usrtvp
== USER_ADDR_NULL
) {
3098 struct timeval old_tv
;
3099 /* XXX Y2038 bug because of microtime argument */
3101 TIMEVAL_TO_TIMESPEC(&old_tv
, &tsp
[0]);
3104 if (IS_64BIT_PROCESS(current_proc())) {
3105 error
= copyin(usrtvp
, (void *)tv
, sizeof(tv
));
3107 struct timeval old_tv
[2];
3108 error
= copyin(usrtvp
, (void *)old_tv
, sizeof(old_tv
));
3109 tv
[0].tv_sec
= old_tv
[0].tv_sec
;
3110 tv
[0].tv_usec
= old_tv
[0].tv_usec
;
3111 tv
[1].tv_sec
= old_tv
[1].tv_sec
;
3112 tv
[1].tv_usec
= old_tv
[1].tv_usec
;
3116 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
3117 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
3123 setutimes(vfs_context_t ctx
, struct vnode
*vp
, const struct timespec
*ts
,
3127 struct vnode_attr va
;
3128 kauth_action_t action
;
3130 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3133 VATTR_SET(&va
, va_access_time
, ts
[0]);
3134 VATTR_SET(&va
, va_modify_time
, ts
[1]);
3136 va
.va_vaflags
|= VA_UTIMES_NULL
;
3138 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
3140 /* since we may not need to auth anything, check here */
3141 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
3143 error
= vnode_setattr(vp
, &va
, ctx
);
3150 * Set the access and modification times of a file.
3154 utimes(struct proc
*p
, register struct utimes_args
*uap
, __unused register_t
*retval
)
3156 struct timespec ts
[2];
3159 struct nameidata nd
;
3160 struct vfs_context context
;
3162 context
.vc_proc
= p
;
3163 context
.vc_ucred
= kauth_cred_get();
3165 /* AUDIT: Needed to change the order of operations to do the
3166 * name lookup first because auditing wants the path.
3168 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3169 UIO_USERSPACE
, uap
->path
, &context
);
3176 * Fetch the user-supplied time. If usrtvp is USER_ADDR_NULL, we fetch
3177 * the current time instead.
3180 if ((error
= getutimes(usrtvp
, ts
)) != 0)
3183 error
= setutimes(&context
, nd
.ni_vp
, ts
, usrtvp
== USER_ADDR_NULL
);
3186 vnode_put(nd
.ni_vp
);
3191 * Set the access and modification times of a file.
3195 futimes(struct proc
*p
, register struct futimes_args
*uap
, __unused register_t
*retval
)
3197 struct timespec ts
[2];
3201 struct vfs_context context
;
3203 context
.vc_proc
= p
;
3204 context
.vc_ucred
= kauth_cred_get();
3206 AUDIT_ARG(fd
, uap
->fd
);
3208 if ((error
= getutimes(usrtvp
, ts
)) != 0)
3210 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
3212 if((error
= vnode_getwithref(vp
))) {
3217 error
= setutimes(&context
, vp
, ts
, usrtvp
== 0);
3224 * Truncate a file given its path name.
3228 truncate(struct proc
*p
, register struct truncate_args
*uap
, __unused register_t
*retval
)
3230 register struct vnode
*vp
;
3231 struct vnode_attr va
;
3232 struct vfs_context context
;
3234 struct nameidata nd
;
3235 kauth_action_t action
;
3237 context
.vc_proc
= p
;
3238 context
.vc_ucred
= kauth_cred_get();
3240 if (uap
->length
< 0)
3242 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3243 UIO_USERSPACE
, uap
->path
, &context
);
3244 if ((error
= namei(&nd
)))
3251 VATTR_SET(&va
, va_data_size
, uap
->length
);
3252 if ((error
= vnode_authattr(vp
, &va
, &action
, &context
)) != 0)
3254 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0))
3256 error
= vnode_setattr(vp
, &va
, &context
);
3263 * Truncate a file given a file descriptor.
3267 ftruncate(p
, uap
, retval
)
3269 register struct ftruncate_args
*uap
;
3272 struct vfs_context context
;
3273 struct vnode_attr va
;
3275 struct fileproc
*fp
;
3279 context
.vc_proc
= current_proc();
3280 context
.vc_ucred
= kauth_cred_get();
3282 AUDIT_ARG(fd
, uap
->fd
);
3283 if (uap
->length
< 0)
3286 if ( (error
= fp_lookup(p
,fd
,&fp
,0)) ) {
3290 if (fp
->f_fglob
->fg_type
== DTYPE_PSXSHM
) {
3291 error
= pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
);
3294 if (fp
->f_fglob
->fg_type
!= DTYPE_VNODE
) {
3299 vp
= (struct vnode
*)fp
->f_fglob
->fg_data
;
3301 if ((fp
->f_fglob
->fg_flag
& FWRITE
) == 0) {
3302 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
3307 if ((error
= vnode_getwithref(vp
)) != 0) {
3311 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3314 VATTR_SET(&va
, va_data_size
, uap
->length
);
3315 error
= vnode_setattr(vp
, &va
, &context
);
3316 (void)vnode_put(vp
);
3324 * Sync an open file.
3328 fsync(struct proc
*p
, struct fsync_args
*uap
, __unused register_t
*retval
)
3331 struct fileproc
*fp
;
3332 struct vfs_context context
;
3335 if ( (error
= fp_getfvp(p
, uap
->fd
, &fp
, &vp
)) )
3337 if ( (error
= vnode_getwithref(vp
)) ) {
3341 context
.vc_proc
= p
;
3342 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
3344 error
= VNOP_FSYNC(vp
, MNT_WAIT
, &context
);
3346 (void)vnode_put(vp
);
3352 * Duplicate files. Source must be a file, target must be a file or
3355 * XXX Copyfile authorisation checking is woefully inadequate, and will not
3356 * perform inheritance correctly.
3360 copyfile(struct proc
*p
, register struct copyfile_args
*uap
, __unused register_t
*retval
)
3362 vnode_t tvp
, fvp
, tdvp
, sdvp
;
3363 struct nameidata fromnd
, tond
;
3365 struct vfs_context context
;
3367 context
.vc_proc
= p
;
3368 context
.vc_ucred
= kauth_cred_get();
3370 /* Check that the flags are valid. */
3372 if (uap
->flags
& ~CPF_MASK
) {
3376 NDINIT(&fromnd
, LOOKUP
, SAVESTART
| AUDITVNPATH1
,
3377 UIO_USERSPACE
, uap
->from
, &context
);
3378 if ((error
= namei(&fromnd
)))
3382 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
| AUDITVNPATH2
,
3383 UIO_USERSPACE
, uap
->to
, &context
);
3384 if ((error
= namei(&tond
))) {
3391 if (!(uap
->flags
& CPF_OVERWRITE
)) {
3396 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
3401 if ((error
= vnode_authorize(tdvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
3407 * If source is the same as the destination (that is the
3408 * same inode number) then there is nothing to do.
3409 * (fixed to have POSIX semantics - CSM 3/2/98)
3414 error
= VNOP_COPYFILE(fvp
,tdvp
,tvp
,&tond
.ni_cnd
,uap
->mode
,uap
->flags
,&context
);
3416 sdvp
= tond
.ni_startdir
;
3418 * nameidone has to happen before we vnode_put(tdvp)
3419 * since it may need to release the fs_nodelock on the tdvp
3430 if (fromnd
.ni_startdir
)
3431 vnode_put(fromnd
.ni_startdir
);
3441 * Rename files. Source and destination must either both be directories,
3442 * or both not be directories. If target is a directory, it must be empty.
3446 rename(proc_t p
, register struct rename_args
*uap
, __unused register_t
*retval
)
3450 struct nameidata fromnd
, tond
;
3451 struct vfs_context context
;
3454 char *oname
, *from_name
, *to_name
;
3455 int from_len
, to_len
;
3456 int holding_mntlock
;
3457 mount_t locked_mp
= NULL
;
3459 fse_info from_finfo
, to_finfo
;
3461 context
.vc_proc
= p
;
3462 context
.vc_ucred
= kauth_cred_get();
3463 holding_mntlock
= 0;
3469 NDINIT(&fromnd
, DELETE
, WANTPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->from
, &context
);
3471 if ( (error
= namei(&fromnd
)) )
3473 fdvp
= fromnd
.ni_dvp
;
3476 NDINIT(&tond
, RENAME
, WANTPARENT
| AUDITVNPATH2
, UIO_USERSPACE
, uap
->to
, &context
);
3477 if (fvp
->v_type
== VDIR
)
3478 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
3480 if ( (error
= namei(&tond
)) ) {
3482 * Translate error code for rename("dir1", "dir2/.").
3484 if (error
== EISDIR
&& fvp
->v_type
== VDIR
)
3492 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
3495 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
3508 * If tvp is a directory and not the same as fdvp, or tdvp is not the same as fdvp,
3509 * the node is moving between directories and we need rights to remove from the
3510 * old and add to the new.
3512 * If tvp already exists and is not a directory, we need to be allowed to delete it.
3514 * Note that we do not inherit when renaming. XXX this needs to be revisited to
3515 * implement the deferred-inherit bit.
3521 if ((tvp
!= NULL
) && vnode_isdir(tvp
)) {
3524 } else if (tdvp
!= fdvp
) {
3528 * must have delete rights to remove the old name even in the simple case of
3531 if ((error
= vnode_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
, &context
)) != 0)
3534 /* moving into tdvp or tvp, must have rights to add */
3535 if ((error
= vnode_authorize(((tvp
!= NULL
) && vnode_isdir(tvp
)) ? tvp
: tdvp
,
3537 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
3541 /* node staying in same directory, must be allowed to add new name */
3542 if ((error
= vnode_authorize(fdvp
, NULL
,
3543 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
3546 /* overwriting tvp */
3547 if ((tvp
!= NULL
) && !vnode_isdir(tvp
) &&
3548 ((error
= vnode_authorize(tvp
, tdvp
, KAUTH_VNODE_DELETE
, &context
)) != 0))
3551 /* XXX more checks? */
3554 /* authorization denied */
3559 * Allow the renaming of mount points.
3560 * - target must not exist
3561 * - target must reside in the same directory as source
3562 * - union mounts cannot be renamed
3563 * - "/" cannot be renamed
3565 if ((fvp
->v_flag
& VROOT
) &&
3566 (fvp
->v_type
== VDIR
) &&
3568 (fvp
->v_mountedhere
== NULL
) &&
3570 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
3571 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
3572 struct vnode
*coveredvp
;
3574 /* switch fvp to the covered vnode */
3575 coveredvp
= fvp
->v_mount
->mnt_vnodecovered
;
3576 if ( (vnode_getwithref(coveredvp
)) ) {
3586 * Check for cross-device rename.
3588 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
3589 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
3594 * Avoid renaming "." and "..".
3596 if (fvp
->v_type
== VDIR
&&
3598 (fromnd
.ni_cnd
.cn_namelen
== 1 && fromnd
.ni_cnd
.cn_nameptr
[0] == '.') ||
3599 ((fromnd
.ni_cnd
.cn_flags
| tond
.ni_cnd
.cn_flags
) & ISDOTDOT
)) ) {
3604 * The following edge case is caught here:
3605 * (to cannot be a descendent of from)
3618 if (tdvp
->v_parent
== fvp
) {
3624 * If source is the same as the destination (that is the
3625 * same inode number) then there is nothing to do...
3626 * EXCEPT if the underlying file system supports case
3627 * insensitivity and is case preserving. In this case
3628 * the file system needs to handle the special case of
3629 * getting the same vnode as target (fvp) and source (tvp).
3631 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
3632 * and _PC_CASE_PRESERVING can have this exception, and they need to
3633 * handle the special case of getting the same vnode as target and
3634 * source. NOTE: Then the target is unlocked going into vnop_rename,
3635 * so not to cause locking problems. There is a single reference on tvp.
3637 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
3638 * that correct behaviour then is just to remove the source (link)
3640 if (fvp
== tvp
&& fdvp
== tdvp
) {
3641 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
3642 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
3643 fromnd
.ni_cnd
.cn_namelen
)) {
3648 if (holding_mntlock
&& fvp
->v_mount
!= locked_mp
) {
3650 * we're holding a reference and lock
3651 * on locked_mp, but it no longer matches
3652 * what we want to do... so drop our hold
3654 mount_unlock_renames(locked_mp
);
3655 mount_drop(locked_mp
, 0);
3656 holding_mntlock
= 0;
3658 if (tdvp
!= fdvp
&& fvp
->v_type
== VDIR
) {
3660 * serialize renames that re-shape
3661 * the tree... if holding_mntlock is
3662 * set, then we're ready to go...
3664 * first need to drop the iocounts
3665 * we picked up, second take the
3666 * lock to serialize the access,
3667 * then finally start the lookup
3668 * process over with the lock held
3670 if (!holding_mntlock
) {
3672 * need to grab a reference on
3673 * the mount point before we
3674 * drop all the iocounts... once
3675 * the iocounts are gone, the mount
3678 locked_mp
= fvp
->v_mount
;
3679 mount_ref(locked_mp
, 0);
3682 * nameidone has to happen before we vnode_put(tvp)
3683 * since it may need to release the fs_nodelock on the tvp
3692 * nameidone has to happen before we vnode_put(fdvp)
3693 * since it may need to release the fs_nodelock on the fvp
3700 mount_lock_renames(locked_mp
);
3701 holding_mntlock
= 1;
3707 * when we dropped the iocounts to take
3708 * the lock, we allowed the identity of
3709 * the various vnodes to change... if they did,
3710 * we may no longer be dealing with a rename
3711 * that reshapes the tree... once we're holding
3712 * the iocounts, the vnodes can't change type
3713 * so we're free to drop the lock at this point
3716 if (holding_mntlock
) {
3717 mount_unlock_renames(locked_mp
);
3718 mount_drop(locked_mp
, 0);
3719 holding_mntlock
= 0;
3722 // save these off so we can later verify that fvp is the same
3723 oname
= fvp
->v_name
;
3724 oparent
= fvp
->v_parent
;
3726 if (need_fsevent(FSE_RENAME
, fvp
)) {
3727 get_fse_info(fvp
, &from_finfo
, &context
);
3730 get_fse_info(tvp
, &to_finfo
, &context
);
3732 from_name
= get_pathbuff();
3733 from_len
= MAXPATHLEN
;
3734 vn_getpath(fvp
, from_name
, &from_len
);
3736 to_name
= get_pathbuff();
3737 to_len
= MAXPATHLEN
;
3739 if (tvp
&& tvp
->v_type
!= VDIR
) {
3740 vn_getpath(tvp
, to_name
, &to_len
);
3742 vn_getpath(tdvp
, to_name
, &to_len
);
3743 // if the path is not just "/", then append a "/"
3745 to_name
[to_len
-1] = '/';
3749 strcpy(&to_name
[to_len
], tond
.ni_cnd
.cn_nameptr
);
3750 to_len
+= tond
.ni_cnd
.cn_namelen
+ 1;
3751 to_name
[to_len
] = '\0';
3757 error
= VNOP_RENAME(fdvp
, fvp
, &fromnd
.ni_cnd
,
3758 tdvp
, tvp
, &tond
.ni_cnd
,
3761 if (holding_mntlock
) {
3763 * we can drop our serialization
3766 mount_unlock_renames(locked_mp
);
3767 mount_drop(locked_mp
, 0);
3768 holding_mntlock
= 0;
3771 if (to_name
!= NULL
)
3772 release_pathbuff(to_name
);
3773 if (from_name
!= NULL
)
3774 release_pathbuff(from_name
);
3775 from_name
= to_name
= NULL
;
3780 /* call out to allow 3rd party notification of rename.
3781 * Ignore result of kauth_authorize_fileop call.
3783 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_RENAME
,
3784 (uintptr_t)from_name
, (uintptr_t)to_name
);
3786 if (from_name
!= NULL
&& to_name
!= NULL
) {
3788 add_fsevent(FSE_RENAME
, &context
,
3789 FSE_ARG_STRING
, from_len
, from_name
,
3790 FSE_ARG_FINFO
, &from_finfo
,
3791 FSE_ARG_STRING
, to_len
, to_name
,
3792 FSE_ARG_FINFO
, &to_finfo
,
3795 add_fsevent(FSE_RENAME
, &context
,
3796 FSE_ARG_STRING
, from_len
, from_name
,
3797 FSE_ARG_FINFO
, &from_finfo
,
3798 FSE_ARG_STRING
, to_len
, to_name
,
3802 if (to_name
!= NULL
)
3803 release_pathbuff(to_name
);
3804 if (from_name
!= NULL
)
3805 release_pathbuff(from_name
);
3806 from_name
= to_name
= NULL
;
3809 * update filesystem's mount point data
3812 char *cp
, *pathend
, *mpname
;
3818 mp
= fvp
->v_mountedhere
;
3820 if (vfs_busy(mp
, LK_NOWAIT
)) {
3824 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
3826 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
3828 /* find current mount point prefix */
3829 pathend
= &mp
->mnt_vfsstat
.f_mntonname
[0];
3830 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
3834 /* find last component of target name */
3835 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
3839 /* append name to prefix */
3840 maxlen
= MAXPATHLEN
- (pathend
- mp
->mnt_vfsstat
.f_mntonname
);
3841 bzero(pathend
, maxlen
);
3842 strncpy(pathend
, mpname
, maxlen
- 1);
3844 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
3849 * fix up name & parent pointers. note that we first
3850 * check that fvp has the same name/parent pointers it
3851 * had before the rename call... this is a 'weak' check
3854 if (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
) {
3857 update_flags
= VNODE_UPDATE_NAME
;
3860 update_flags
|= VNODE_UPDATE_PARENT
;
3862 vnode_update_identity(fvp
, tdvp
, tond
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_namelen
, tond
.ni_cnd
.cn_hash
, update_flags
);
3865 if (holding_mntlock
) {
3866 mount_unlock_renames(locked_mp
);
3867 mount_drop(locked_mp
, 0);
3871 * nameidone has to happen before we vnode_put(tdvp)
3872 * since it may need to release the fs_nodelock on the tdvp
3882 * nameidone has to happen before we vnode_put(fdvp)
3883 * since it may need to release the fs_nodelock on the fdvp
3895 * Make a directory file.
3899 mkdir1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
3903 int update_flags
= 0;
3904 struct nameidata nd
;
3906 AUDIT_ARG(mode
, vap
->va_mode
);
3907 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
3908 UIO_USERSPACE
, path
, ctx
);
3909 nd
.ni_cnd
.cn_flags
|= WILLBEDIR
;
3921 /* authorize addition of a directory to the parent */
3922 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
)) != 0)
3925 VATTR_SET(vap
, va_type
, VDIR
);
3927 /* make the directory */
3928 if ((error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
)) != 0)
3931 // Make sure the name & parent pointers are hooked up
3932 if (vp
->v_name
== NULL
)
3933 update_flags
|= VNODE_UPDATE_NAME
;
3934 if (vp
->v_parent
== NULLVP
)
3935 update_flags
|= VNODE_UPDATE_PARENT
;
3938 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
3940 add_fsevent(FSE_CREATE_DIR
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
3944 * nameidone has to happen before we vnode_put(dvp)
3945 * since it may need to release the fs_nodelock on the dvp
3958 mkdir_extended(struct proc
*p
, register struct mkdir_extended_args
*uap
, __unused register_t
*retval
)
3960 struct vfs_context context
;
3962 kauth_filesec_t xsecdst
;
3963 struct vnode_attr va
;
3966 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
3967 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
3970 context
.vc_proc
= p
;
3971 context
.vc_ucred
= kauth_cred_get();
3974 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
3975 if (xsecdst
!= NULL
)
3976 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
3978 ciferror
= mkdir1(&context
, uap
->path
, &va
);
3979 if (xsecdst
!= NULL
)
3980 kauth_filesec_free(xsecdst
);
3985 mkdir(struct proc
*p
, register struct mkdir_args
*uap
, __unused register_t
*retval
)
3987 struct vfs_context context
;
3988 struct vnode_attr va
;
3990 context
.vc_proc
= p
;
3991 context
.vc_ucred
= kauth_cred_get();
3994 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
3996 return(mkdir1(&context
, uap
->path
, &va
));
4000 * Remove a directory file.
4004 rmdir(struct proc
*p
, struct rmdir_args
*uap
, __unused register_t
*retval
)
4008 struct nameidata nd
;
4009 struct vfs_context context
;
4011 context
.vc_proc
= p
;
4012 context
.vc_ucred
= kauth_cred_get();
4014 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
4015 UIO_USERSPACE
, uap
->path
, &context
);
4022 if (vp
->v_type
!= VDIR
) {
4024 * rmdir only deals with directories
4027 } else if (dvp
== vp
) {
4029 * No rmdir "." please.
4032 } else if (vp
->v_flag
& VROOT
) {
4034 * The root of a mounted filesystem cannot be deleted.
4038 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, &context
);
4045 if (need_fsevent(FSE_DELETE
, dvp
)) {
4046 path
= get_pathbuff();
4048 vn_getpath(vp
, path
, &len
);
4049 get_fse_info(vp
, &finfo
, &context
);
4051 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, &context
);
4053 if (!error
&& path
!= NULL
) {
4054 add_fsevent(FSE_DELETE
, &context
,
4055 FSE_ARG_STRING
, len
, path
,
4056 FSE_ARG_FINFO
, &finfo
,
4060 release_pathbuff(path
);
4063 * nameidone has to happen before we vnode_put(dvp)
4064 * since it may need to release the fs_nodelock on the dvp
4076 * Read a block of directory entries in a file system independent format.
4079 getdirentries(p
, uap
, retval
)
4081 register struct getdirentries_args
*uap
;
4085 struct vfs_context context
;
4086 struct fileproc
*fp
;
4088 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4092 char uio_buf
[ UIO_SIZEOF(1) ];
4094 AUDIT_ARG(fd
, uap
->fd
);
4095 error
= fp_getfvp(p
, fd
, &fp
, &vp
);
4099 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
4100 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4104 if ( (error
= vnode_getwithref(vp
)) ) {
4108 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4111 if (vp
->v_type
!= VDIR
) {
4112 (void)vnode_put(vp
);
4116 context
.vc_proc
= p
;
4117 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
4119 loff
= fp
->f_fglob
->fg_offset
;
4120 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
4121 &uio_buf
[0], sizeof(uio_buf
));
4122 uio_addiov(auio
, uap
->buf
, uap
->count
);
4124 error
= VNOP_READDIR(vp
, auio
, 0, &eofflag
, (int *)NULL
, &context
);
4125 fp
->f_fglob
->fg_offset
= uio_offset(auio
);
4127 (void)vnode_put(vp
);
4133 if ((uap
->count
== uio_resid(auio
)) &&
4134 (vp
->v_op
== union_vnodeop_p
)) {
4137 lvp
= union_dircache(vp
, p
);
4138 if (lvp
!= NULLVP
) {
4139 struct vnode_attr va
;
4141 * If the directory is opaque,
4142 * then don't show lower entries
4145 VATTR_WANTED(&va
, va_flags
);
4146 error
= vnode_getattr(vp
, &va
, &context
);
4147 if (va
.va_flags
& OPAQUE
) {
4153 if (lvp
!= NULLVP
) {
4154 error
= VNOP_OPEN(lvp
, FREAD
, &context
);
4160 fp
->f_fglob
->fg_data
= (caddr_t
) lvp
;
4161 fp
->f_fglob
->fg_offset
= 0;
4162 error
= VNOP_CLOSE(vp
, FREAD
, &context
);
4174 if (((user_ssize_t
)uap
->count
== uio_resid(auio
)) &&
4175 (vp
->v_flag
& VROOT
) &&
4176 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
4177 struct vnode
*tvp
= vp
;
4178 vp
= vp
->v_mount
->mnt_vnodecovered
;
4179 vnode_getwithref(vp
);
4181 fp
->f_fglob
->fg_data
= (caddr_t
) vp
;
4182 fp
->f_fglob
->fg_offset
= 0;
4188 error
= copyout((caddr_t
)&loff
, uap
->basep
, sizeof(long));
4189 // LP64todo - fix this
4190 *retval
= uap
->count
- uio_resid(auio
);
4197 * Set the mode mask for creation of filesystem nodes.
4199 #warning XXX implement xsecurity
4201 #define UMASK_NOXSECURITY (void *)1 /* leave existing xsecurity alone */
4203 umask1(struct proc
*p
, int newmask
, __unused kauth_filesec_t fsec
, register_t
*retval
)
4205 register struct filedesc
*fdp
;
4207 AUDIT_ARG(mask
, newmask
);
4209 *retval
= fdp
->fd_cmask
;
4210 fdp
->fd_cmask
= newmask
& ALLPERMS
;
4216 umask_extended(struct proc
*p
, struct umask_extended_args
*uap
, register_t
*retval
)
4219 kauth_filesec_t xsecdst
;
4221 xsecdst
= KAUTH_FILESEC_NONE
;
4222 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
4223 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
4226 xsecdst
= KAUTH_FILESEC_NONE
;
4229 ciferror
= umask1(p
, uap
->newmask
, xsecdst
, retval
);
4231 if (xsecdst
!= KAUTH_FILESEC_NONE
)
4232 kauth_filesec_free(xsecdst
);
4237 umask(struct proc
*p
, struct umask_args
*uap
, register_t
*retval
)
4239 return(umask1(p
, uap
->newmask
, UMASK_NOXSECURITY
, retval
));
4243 * Void all references to file by ripping underlying filesystem
4248 revoke(struct proc
*p
, register struct revoke_args
*uap
, __unused register_t
*retval
)
4250 register struct vnode
*vp
;
4251 struct vnode_attr va
;
4252 struct vfs_context context
;
4254 struct nameidata nd
;
4256 context
.vc_proc
= p
;
4257 context
.vc_ucred
= kauth_cred_get();
4259 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4260 UIO_USERSPACE
, uap
->path
, &context
);
4269 VATTR_WANTED(&va
, va_uid
);
4270 if ((error
= vnode_getattr(vp
, &va
, &context
)))
4272 if (kauth_cred_getuid(context
.vc_ucred
) != va
.va_uid
&&
4273 (error
= suser(context
.vc_ucred
, &p
->p_acflag
)))
4275 if (vp
->v_usecount
> 1 || (vp
->v_flag
& VALIASED
))
4276 VNOP_REVOKE(vp
, REVOKEALL
, &context
);
4284 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
4285 * The following system calls are designed to support features
4286 * which are specific to the HFS & HFS Plus volume formats
4289 #ifdef __APPLE_API_OBSOLETE
4291 /************************************************/
4292 /* *** Following calls will be deleted soon *** */
4293 /************************************************/
4296 * Make a complex file. A complex file is one with multiple forks (data streams)
4300 mkcomplex(__unused
struct proc
*p
, __unused
struct mkcomplex_args
*uap
, __unused register_t
*retval
)
4306 * Extended stat call which returns volumeid and vnodeid as well as other info
4310 statv(__unused
struct proc
*p
,
4311 __unused
struct statv_args
*uap
,
4312 __unused register_t
*retval
)
4314 return (ENOTSUP
); /* We'll just return an error for now */
4316 } /* end of statv system call */
4319 * Extended lstat call which returns volumeid and vnodeid as well as other info
4323 lstatv(__unused
struct proc
*p
,
4324 __unused
struct lstatv_args
*uap
,
4325 __unused register_t
*retval
)
4327 return (ENOTSUP
); /* We'll just return an error for now */
4328 } /* end of lstatv system call */
4331 * Extended fstat call which returns volumeid and vnodeid as well as other info
4335 fstatv(__unused
struct proc
*p
,
4336 __unused
struct fstatv_args
*uap
,
4337 __unused register_t
*retval
)
4339 return (ENOTSUP
); /* We'll just return an error for now */
4340 } /* end of fstatv system call */
4343 /************************************************/
4344 /* *** Preceding calls will be deleted soon *** */
4345 /************************************************/
4347 #endif /* __APPLE_API_OBSOLETE */
4350 * Obtain attribute information on objects in a directory while enumerating
4351 * the directory. This call does not yet support union mounted directories.
4353 * 1.union mounted directories.
4358 getdirentriesattr (struct proc
*p
, struct getdirentriesattr_args
*uap
, register_t
*retval
)
4361 struct fileproc
*fp
;
4363 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4364 uint64_t actualcount
;
4369 struct attrlist attributelist
;
4370 struct vfs_context context
;
4372 char uio_buf
[ UIO_SIZEOF(1) ];
4373 kauth_action_t action
;
4377 /* Get the attributes into kernel space */
4378 if ((error
= copyin(uap
->alist
, (caddr_t
) &attributelist
, sizeof (attributelist
))))
4380 actualcount
= fuulong(uap
->count
);
4381 if (actualcount
== -1ULL)
4384 if ( (error
= fp_getfvp(p
, fd
, &fp
, &vp
)) )
4387 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
4388 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4392 if ( (error
= vnode_getwithref(vp
)) )
4395 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4397 if (vp
->v_type
!= VDIR
) {
4398 (void)vnode_put(vp
);
4403 /* set up the uio structure which will contain the users return buffer */
4404 loff
= fp
->f_fglob
->fg_offset
;
4405 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
4406 &uio_buf
[0], sizeof(uio_buf
));
4407 uio_addiov(auio
, uap
->buffer
, uap
->buffersize
);
4409 context
.vc_proc
= p
;
4410 context
.vc_ucred
= kauth_cred_get();
4411 tmpcount
= (u_long
) actualcount
;
4414 * If the only item requested is file names, we can let that past with
4415 * just LIST_DIRECTORY. If they want any other attributes, that means
4416 * they need SEARCH as well.
4418 action
= KAUTH_VNODE_LIST_DIRECTORY
;
4419 if ((attributelist
.commonattr
& ~ATTR_CMN_NAME
) ||
4420 attributelist
.fileattr
|| attributelist
.dirattr
)
4421 action
|= KAUTH_VNODE_SEARCH
;
4423 if ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) == 0)
4424 error
= VNOP_READDIRATTR(vp
, &attributelist
, auio
,
4425 tmpcount
, uap
->options
, &newstate
, &eofflag
,
4426 &tmpcount
, &context
);
4427 (void)vnode_put(vp
);
4428 actualcount
= tmpcount
;
4432 fp
->f_fglob
->fg_offset
= uio_offset(auio
); /* should be multiple of dirent, not variable */
4434 if ((error
= suulong(uap
->count
, actualcount
)) != 0)
4436 if ((error
= suulong(uap
->newstate
, (uint64_t)newstate
)) != 0)
4438 if ((error
= suulong(uap
->basep
, (uint64_t)loff
)) != 0)
4441 *retval
= eofflag
; /* similar to getdirentries */
4445 return (error
); /* return error earlier, an retval of 0 or 1 now */
4447 } /* end of getdirentryattr system call */
4450 * Exchange data between two files
4455 exchangedata (struct proc
*p
, register struct exchangedata_args
*uap
, __unused register_t
*retval
)
4458 struct nameidata fnd
, snd
;
4459 struct vfs_context context
;
4460 struct vnode
*fvp
, *svp
;
4466 fse_info f_finfo
, s_finfo
;
4468 context
.vc_proc
= p
;
4469 context
.vc_ucred
= kauth_cred_get();
4472 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4474 NDINIT(&fnd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4475 UIO_USERSPACE
, uap
->path1
, &context
);
4477 error
= namei(&fnd
);
4484 NDINIT(&snd
, LOOKUP
, nameiflags
| AUDITVNPATH2
,
4485 UIO_USERSPACE
, uap
->path2
, &context
);
4487 error
= namei(&snd
);
4496 * if the files are the same, return an inval error
4504 * if the files are on different volumes, return an error
4506 if (svp
->v_mount
!= fvp
->v_mount
) {
4510 if (((error
= vnode_authorize(fvp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0) ||
4511 ((error
= vnode_authorize(svp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0))
4514 if (need_fsevent(FSE_EXCHANGE
, fvp
) || kauth_authorize_fileop_has_listeners()) {
4515 fpath
= get_pathbuff();
4516 spath
= get_pathbuff();
4519 if (vn_getpath(fvp
, fpath
, &flen
) != 0 || fpath
[0] == '\0') {
4520 printf("exchange: vn_getpath(fvp=0x%x) failed <<%s>>\n",
4523 if (vn_getpath(svp
, spath
, &slen
) != 0 || spath
[0] == '\0') {
4524 printf("exchange: vn_getpath(svp=0x%x) failed <<%s>>\n",
4527 get_fse_info(fvp
, &f_finfo
, &context
);
4528 get_fse_info(svp
, &s_finfo
, &context
);
4530 /* Ok, make the call */
4531 error
= VNOP_EXCHANGE(fvp
, svp
, 0, &context
);
4536 if (fpath
!= NULL
&& spath
!= NULL
) {
4537 /* call out to allow 3rd party notification of exchangedata.
4538 * Ignore result of kauth_authorize_fileop call.
4540 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_EXCHANGE
,
4541 (uintptr_t)fpath
, (uintptr_t)spath
);
4545 tmpname
= fvp
->v_name
;
4546 fvp
->v_name
= svp
->v_name
;
4547 svp
->v_name
= tmpname
;
4549 if (fvp
->v_parent
!= svp
->v_parent
) {
4552 tmp
= fvp
->v_parent
;
4553 fvp
->v_parent
= svp
->v_parent
;
4554 svp
->v_parent
= tmp
;
4556 name_cache_unlock();
4558 if (fpath
!= NULL
&& spath
!= NULL
) {
4559 add_fsevent(FSE_EXCHANGE
, &context
,
4560 FSE_ARG_STRING
, flen
, fpath
,
4561 FSE_ARG_FINFO
, &f_finfo
,
4562 FSE_ARG_STRING
, slen
, spath
,
4563 FSE_ARG_FINFO
, &s_finfo
,
4568 release_pathbuff(spath
);
4570 release_pathbuff(fpath
);
4580 #ifdef __APPLE_API_OBSOLETE
4582 /************************************************/
4583 /* *** Following calls will be deleted soon *** */
4584 /************************************************/
4587 * Check users access to a file
4591 #warning "checkuseraccess copies a cred in from user space but"
4592 #warning "user space has no way of knowing what one looks like"
4593 #warning "this code should use the access_extended spoof-as functionality"
4595 checkuseraccess (struct proc
*p
, register struct checkuseraccess_args
*uap
, __unused register_t
*retval
)
4597 register struct vnode
*vp
;
4599 struct nameidata nd
;
4600 struct ucred cred
; /* XXX ILLEGAL */
4601 int flags
; /*what will actually get passed to access*/
4603 struct vfs_context context
;
4605 /* Make sure that the number of groups is correct before we do anything */
4607 if ((uap
->ngroups
<= 0) || (uap
->ngroups
> NGROUPS
))
4610 /* Verify that the caller is root */
4612 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
4615 /* Fill in the credential structure */
4618 cred
.cr_uid
= uap
->userid
;
4619 cred
.cr_ngroups
= uap
->ngroups
;
4620 if ((error
= copyin(CAST_USER_ADDR_T(uap
->groups
), (caddr_t
) &(cred
.cr_groups
), (sizeof(gid_t
))*uap
->ngroups
)))
4623 context
.vc_proc
= p
;
4624 context
.vc_ucred
= &cred
;
4626 /* Get our hands on the file */
4628 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4629 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4630 UIO_USERSPACE
, CAST_USER_ADDR_T(uap
->path
), &context
);
4632 if ((error
= namei(&nd
)))
4637 /* Flags == 0 means only check for existence. */
4641 if (uap
->accessrequired
) {
4642 if (uap
->accessrequired
& R_OK
)
4643 flags
|= KAUTH_VNODE_READ_DATA
;
4644 if (uap
->accessrequired
& W_OK
)
4645 flags
|= KAUTH_VNODE_WRITE_DATA
;
4646 if (uap
->accessrequired
& X_OK
)
4647 flags
|= KAUTH_VNODE_EXECUTE
;
4649 error
= vnode_authorize(vp
, NULL
, flags
, &context
);
4658 } /* end of checkuseraccess system call */
4660 /************************************************/
4661 /* *** Preceding calls will be deleted soon *** */
4662 /************************************************/
4664 #endif /* __APPLE_API_OBSOLETE */
4671 searchfs (struct proc
*p
, register struct searchfs_args
*uap
, __unused register_t
*retval
)
4673 register struct vnode
*vp
;
4676 struct nameidata nd
;
4677 struct user_fssearchblock searchblock
;
4678 struct searchstate
*state
;
4679 struct attrlist
*returnattrs
;
4680 void *searchparams1
,*searchparams2
;
4682 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4686 struct vfs_context context
;
4687 char uio_buf
[ UIO_SIZEOF(1) ];
4689 context
.vc_proc
= p
;
4690 context
.vc_ucred
= kauth_cred_get();
4692 /* Start by copying in fsearchblock paramater list */
4693 if (IS_64BIT_PROCESS(p
)) {
4694 error
= copyin(uap
->searchblock
, (caddr_t
) &searchblock
, sizeof(searchblock
));
4697 struct fssearchblock tmp_searchblock
;
4698 error
= copyin(uap
->searchblock
, (caddr_t
) &tmp_searchblock
, sizeof(tmp_searchblock
));
4699 // munge into 64-bit version
4700 searchblock
.returnattrs
= CAST_USER_ADDR_T(tmp_searchblock
.returnattrs
);
4701 searchblock
.returnbuffer
= CAST_USER_ADDR_T(tmp_searchblock
.returnbuffer
);
4702 searchblock
.returnbuffersize
= tmp_searchblock
.returnbuffersize
;
4703 searchblock
.maxmatches
= tmp_searchblock
.maxmatches
;
4704 searchblock
.timelimit
= tmp_searchblock
.timelimit
;
4705 searchblock
.searchparams1
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams1
);
4706 searchblock
.sizeofsearchparams1
= tmp_searchblock
.sizeofsearchparams1
;
4707 searchblock
.searchparams2
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams2
);
4708 searchblock
.sizeofsearchparams2
= tmp_searchblock
.sizeofsearchparams2
;
4709 searchblock
.searchattrs
= tmp_searchblock
.searchattrs
;
4714 /* Do a sanity check on sizeofsearchparams1 and sizeofsearchparams2.
4716 if (searchblock
.sizeofsearchparams1
> SEARCHFS_MAX_SEARCHPARMS
||
4717 searchblock
.sizeofsearchparams2
> SEARCHFS_MAX_SEARCHPARMS
)
4720 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
4721 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
4722 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
4725 mallocsize
= searchblock
.sizeofsearchparams1
+ searchblock
.sizeofsearchparams2
+
4726 sizeof(struct attrlist
) + sizeof(struct searchstate
);
4728 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
4730 /* Now set up the various pointers to the correct place in our newly allocated memory */
4732 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
4733 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
4734 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
4736 /* Now copy in the stuff given our local variables. */
4738 if ((error
= copyin(searchblock
.searchparams1
, searchparams1
, searchblock
.sizeofsearchparams1
)))
4741 if ((error
= copyin(searchblock
.searchparams2
, searchparams2
, searchblock
.sizeofsearchparams2
)))
4744 if ((error
= copyin(searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
))))
4747 if ((error
= copyin(uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
))))
4750 /* set up the uio structure which will contain the users return buffer */
4752 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
4753 &uio_buf
[0], sizeof(uio_buf
));
4754 uio_addiov(auio
, searchblock
.returnbuffer
, searchblock
.returnbuffersize
);
4757 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4758 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4759 UIO_USERSPACE
, uap
->path
, &context
);
4770 * If searchblock.maxmatches == 0, then skip the search. This has happened
4771 * before and sometimes the underlyning code doesnt deal with it well.
4773 if (searchblock
.maxmatches
== 0) {
4779 Allright, we have everything we need, so lets make that call.
4781 We keep special track of the return value from the file system:
4782 EAGAIN is an acceptable error condition that shouldn't keep us
4783 from copying out any results...
4786 fserror
= VNOP_SEARCHFS(vp
,
4789 &searchblock
.searchattrs
,
4790 searchblock
.maxmatches
,
4791 &searchblock
.timelimit
,
4804 /* Now copy out the stuff that needs copying out. That means the number of matches, the
4805 search state. Everything was already put into he return buffer by the vop call. */
4807 if ((error
= copyout((caddr_t
) state
, uap
->state
, sizeof(struct searchstate
))) != 0)
4810 if ((error
= suulong(uap
->nummatches
, (uint64_t)nummatches
)) != 0)
4817 FREE(searchparams1
,M_TEMP
);
4822 } /* end of searchfs system call */
4826 * Make a filesystem-specific control call:
4830 fsctl (struct proc
*p
, struct fsctl_args
*uap
, __unused register_t
*retval
)
4834 struct nameidata nd
;
4836 u_long cmd
= uap
->cmd
;
4837 register u_int size
;
4838 #define STK_PARAMS 128
4839 char stkbuf
[STK_PARAMS
];
4841 struct vfs_context context
;
4843 context
.vc_proc
= p
;
4844 context
.vc_ucred
= kauth_cred_get();
4846 size
= IOCPARM_LEN(cmd
);
4847 if (size
> IOCPARM_MAX
) return (EINVAL
);
4849 is64bit
= proc_is64bit(p
);
4852 if (size
> sizeof (stkbuf
)) {
4853 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
4861 error
= copyin(uap
->data
, data
, size
);
4862 if (error
) goto FSCtl_Exit
;
4865 *(user_addr_t
*)data
= uap
->data
;
4868 *(uint32_t *)data
= (uint32_t)uap
->data
;
4871 } else if ((cmd
& IOC_OUT
) && size
) {
4873 * Zero the buffer so the user always
4874 * gets back something deterministic.
4877 } else if (cmd
& IOC_VOID
) {
4879 *(user_addr_t
*)data
= uap
->data
;
4882 *(uint32_t *)data
= (uint32_t)uap
->data
;
4886 /* Get the vnode for the file we are getting info on: */
4888 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4889 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, uap
->path
, &context
);
4890 if ((error
= namei(&nd
))) goto FSCtl_Exit
;
4892 /* Invoke the filesystem-specific code */
4893 error
= VNOP_IOCTL(nd
.ni_vp
, IOCBASECMD(cmd
), data
, uap
->options
, &context
);
4895 vnode_put(nd
.ni_vp
);
4899 * Copy any data to user, size was
4900 * already set and checked above.
4902 if (error
== 0 && (cmd
& IOC_OUT
) && size
)
4903 error
= copyout(data
, uap
->data
, size
);
4906 if (memp
) kfree(memp
, size
);
4910 /* end of fsctl system call */
4913 * An in-kernel sync for power management to call.
4915 __private_extern__
int
4920 struct sync_args data
;
4925 error
= sync(current_proc(), &data
, &retval
[0]);
4929 } /* end of sync_internal call */
4933 * Retrieve the data of an extended attribute.
4936 getxattr(struct proc
*p
, struct getxattr_args
*uap
, user_ssize_t
*retval
)
4939 struct nameidata nd
;
4940 char attrname
[XATTR_MAXNAMELEN
+1];
4941 struct vfs_context context
;
4943 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4944 size_t attrsize
= 0;
4948 char uio_buf
[ UIO_SIZEOF(1) ];
4950 context
.vc_proc
= p
;
4951 context
.vc_ucred
= kauth_cred_get();
4953 if (uap
->options
& XATTR_NOSECURITY
)
4956 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
4957 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
4958 if ((error
= namei(&nd
))) {
4964 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
4967 if (xattr_protected(attrname
)) {
4971 if (uap
->value
&& uap
->size
> 0) {
4972 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
4973 &uio_buf
[0], sizeof(uio_buf
));
4974 uio_addiov(auio
, uap
->value
, uap
->size
);
4977 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, &context
);
4982 *retval
= uap
->size
- uio_resid(auio
);
4984 *retval
= (user_ssize_t
)attrsize
;
4991 * Retrieve the data of an extended attribute.
4994 fgetxattr(struct proc
*p
, struct fgetxattr_args
*uap
, user_ssize_t
*retval
)
4997 char attrname
[XATTR_MAXNAMELEN
+1];
4998 struct vfs_context context
;
5000 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5001 size_t attrsize
= 0;
5004 char uio_buf
[ UIO_SIZEOF(1) ];
5006 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5009 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5012 if ( (error
= vnode_getwithref(vp
)) ) {
5016 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5019 if (xattr_protected(attrname
)) {
5023 if (uap
->value
&& uap
->size
> 0) {
5024 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
5025 &uio_buf
[0], sizeof(uio_buf
));
5026 uio_addiov(auio
, uap
->value
, uap
->size
);
5028 context
.vc_proc
= p
;
5029 context
.vc_ucred
= kauth_cred_get();
5031 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, &context
);
5033 (void)vnode_put(vp
);
5037 *retval
= uap
->size
- uio_resid(auio
);
5039 *retval
= (user_ssize_t
)attrsize
;
5045 * Set the data of an extended attribute.
5048 setxattr(struct proc
*p
, struct setxattr_args
*uap
, int *retval
)
5051 struct nameidata nd
;
5052 char attrname
[XATTR_MAXNAMELEN
+1];
5053 struct vfs_context context
;
5055 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5059 char uio_buf
[ UIO_SIZEOF(1) ];
5061 context
.vc_proc
= p
;
5062 context
.vc_ucred
= kauth_cred_get();
5064 if (uap
->options
& XATTR_NOSECURITY
)
5067 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5070 if (xattr_protected(attrname
))
5072 if (uap
->value
== 0 || uap
->size
== 0) {
5076 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5077 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5078 if ((error
= namei(&nd
))) {
5084 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
5085 &uio_buf
[0], sizeof(uio_buf
));
5086 uio_addiov(auio
, uap
->value
, uap
->size
);
5088 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, &context
);
5095 * Set the data of an extended attribute.
5098 fsetxattr(struct proc
*p
, struct fsetxattr_args
*uap
, int *retval
)
5101 char attrname
[XATTR_MAXNAMELEN
+1];
5102 struct vfs_context context
;
5104 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5107 char uio_buf
[ UIO_SIZEOF(1) ];
5109 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5112 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5115 if (xattr_protected(attrname
))
5117 if (uap
->value
== 0 || uap
->size
== 0) {
5120 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5123 if ( (error
= vnode_getwithref(vp
)) ) {
5127 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
5128 &uio_buf
[0], sizeof(uio_buf
));
5129 uio_addiov(auio
, uap
->value
, uap
->size
);
5130 context
.vc_proc
= p
;
5131 context
.vc_ucred
= kauth_cred_get();
5133 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, &context
);
5141 * Remove an extended attribute.
5143 #warning "code duplication"
5145 removexattr(struct proc
*p
, struct removexattr_args
*uap
, int *retval
)
5148 struct nameidata nd
;
5149 char attrname
[XATTR_MAXNAMELEN
+1];
5150 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5151 struct vfs_context context
;
5156 context
.vc_proc
= p
;
5157 context
.vc_ucred
= kauth_cred_get();
5159 if (uap
->options
& XATTR_NOSECURITY
)
5162 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
5166 if (xattr_protected(attrname
))
5168 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5169 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5170 if ((error
= namei(&nd
))) {
5176 error
= vn_removexattr(vp
, attrname
, uap
->options
, &context
);
5183 * Remove an extended attribute.
5185 #warning "code duplication"
5187 fremovexattr(struct proc
*p
, struct fremovexattr_args
*uap
, int *retval
)
5190 char attrname
[XATTR_MAXNAMELEN
+1];
5191 struct vfs_context context
;
5195 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5198 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
5202 if (xattr_protected(attrname
))
5204 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5207 if ( (error
= vnode_getwithref(vp
)) ) {
5211 context
.vc_proc
= p
;
5212 context
.vc_ucred
= kauth_cred_get();
5214 error
= vn_removexattr(vp
, attrname
, uap
->options
, &context
);
5222 * Retrieve the list of extended attribute names.
5224 #warning "code duplication"
5226 listxattr(struct proc
*p
, struct listxattr_args
*uap
, user_ssize_t
*retval
)
5229 struct nameidata nd
;
5230 struct vfs_context context
;
5232 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5233 size_t attrsize
= 0;
5236 char uio_buf
[ UIO_SIZEOF(1) ];
5238 context
.vc_proc
= p
;
5239 context
.vc_ucred
= kauth_cred_get();
5241 if (uap
->options
& XATTR_NOSECURITY
)
5244 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5245 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5246 if ((error
= namei(&nd
))) {
5251 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
5252 // LP64todo - fix this!
5253 auio
= uio_createwithbuffer(1, 0, spacetype
,
5254 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
5255 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
5258 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, &context
);
5262 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
5264 *retval
= (user_ssize_t
)attrsize
;
5270 * Retrieve the list of extended attribute names.
5272 #warning "code duplication"
5274 flistxattr(struct proc
*p
, struct flistxattr_args
*uap
, user_ssize_t
*retval
)
5277 struct vfs_context context
;
5279 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5280 size_t attrsize
= 0;
5282 char uio_buf
[ UIO_SIZEOF(1) ];
5284 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5287 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5290 if ( (error
= vnode_getwithref(vp
)) ) {
5294 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
5295 // LP64todo - fix this!
5296 auio
= uio_createwithbuffer(1, 0, spacetype
,
5297 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
5298 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
5300 context
.vc_proc
= p
;
5301 context
.vc_ucred
= kauth_cred_get();
5303 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, &context
);
5308 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
5310 *retval
= (user_ssize_t
)attrsize
;
5316 * Common routine to handle various flavors of statfs data heading out
5320 munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
5321 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
5322 boolean_t partial_copy
)
5325 int my_size
, copy_size
;
5328 struct user_statfs sfs
;
5329 my_size
= copy_size
= sizeof(sfs
);
5330 bzero(&sfs
, my_size
);
5331 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
5332 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
5333 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
5334 sfs
.f_bsize
= (user_long_t
)sfsp
->f_bsize
;
5335 sfs
.f_iosize
= (user_long_t
)sfsp
->f_iosize
;
5336 sfs
.f_blocks
= (user_long_t
)sfsp
->f_blocks
;
5337 sfs
.f_bfree
= (user_long_t
)sfsp
->f_bfree
;
5338 sfs
.f_bavail
= (user_long_t
)sfsp
->f_bavail
;
5339 sfs
.f_files
= (user_long_t
)sfsp
->f_files
;
5340 sfs
.f_ffree
= (user_long_t
)sfsp
->f_ffree
;
5341 sfs
.f_fsid
= sfsp
->f_fsid
;
5342 sfs
.f_owner
= sfsp
->f_owner
;
5343 strncpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
-1);
5344 strncpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
-1);
5345 strncpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
-1);
5348 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
5350 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
5354 my_size
= copy_size
= sizeof(sfs
);
5355 bzero(&sfs
, my_size
);
5357 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
5358 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
5359 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
5362 * It's possible for there to be more than 2^^31 blocks in the filesystem, so we
5363 * have to fudge the numbers here in that case. We inflate the blocksize in order
5364 * to reflect the filesystem size as best we can.
5366 if ((sfsp
->f_blocks
> LONG_MAX
)
5367 /* Hack for 4061702 . I think the real fix is for Carbon to
5368 * look for some volume capability and not depend on hidden
5369 * semantics agreed between a FS and carbon.
5370 * f_blocks, f_bfree, and f_bavail set to -1 is the trigger
5371 * for Carbon to set bNoVolumeSizes volume attribute.
5372 * Without this the webdavfs files cannot be copied onto
5373 * disk as they look huge. This change should not affect
5374 * XSAN as they should not setting these to -1..
5376 && (sfsp
->f_blocks
!= 0xffffffffffffffff)
5377 && (sfsp
->f_bfree
!= 0xffffffffffffffff)
5378 && (sfsp
->f_bavail
!= 0xffffffffffffffff)) {
5382 * Work out how far we have to shift the block count down to make it fit.
5383 * Note that it's possible to have to shift so far that the resulting
5384 * blocksize would be unreportably large. At that point, we will clip
5385 * any values that don't fit.
5387 * For safety's sake, we also ensure that f_iosize is never reported as
5388 * being smaller than f_bsize.
5390 for (shift
= 0; shift
< 32; shift
++) {
5391 if ((sfsp
->f_blocks
>> shift
) <= LONG_MAX
)
5393 if ((sfsp
->f_bsize
<< (shift
+ 1)) > LONG_MAX
)
5396 #define __SHIFT_OR_CLIP(x, s) ((((x) >> (s)) > LONG_MAX) ? LONG_MAX : ((x) >> (s)))
5397 sfs
.f_blocks
= (long)__SHIFT_OR_CLIP(sfsp
->f_blocks
, shift
);
5398 sfs
.f_bfree
= (long)__SHIFT_OR_CLIP(sfsp
->f_bfree
, shift
);
5399 sfs
.f_bavail
= (long)__SHIFT_OR_CLIP(sfsp
->f_bavail
, shift
);
5400 #undef __SHIFT_OR_CLIP
5401 sfs
.f_bsize
= (long)(sfsp
->f_bsize
<< shift
);
5402 sfs
.f_iosize
= lmax(sfsp
->f_iosize
, sfsp
->f_bsize
);
5404 /* filesystem is small enough to be reported honestly */
5405 sfs
.f_bsize
= (long)sfsp
->f_bsize
;
5406 sfs
.f_iosize
= (long)sfsp
->f_iosize
;
5407 sfs
.f_blocks
= (long)sfsp
->f_blocks
;
5408 sfs
.f_bfree
= (long)sfsp
->f_bfree
;
5409 sfs
.f_bavail
= (long)sfsp
->f_bavail
;
5411 sfs
.f_files
= (long)sfsp
->f_files
;
5412 sfs
.f_ffree
= (long)sfsp
->f_ffree
;
5413 sfs
.f_fsid
= sfsp
->f_fsid
;
5414 sfs
.f_owner
= sfsp
->f_owner
;
5415 strncpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
-1);
5416 strncpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
-1);
5417 strncpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
-1);
5420 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
5422 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
5425 if (sizep
!= NULL
) {
5432 * copy stat structure into user_stat structure.
5434 void munge_stat(struct stat
*sbp
, struct user_stat
*usbp
)
5436 usbp
->st_dev
= sbp
->st_dev
;
5437 usbp
->st_ino
= sbp
->st_ino
;
5438 usbp
->st_mode
= sbp
->st_mode
;
5439 usbp
->st_nlink
= sbp
->st_nlink
;
5440 usbp
->st_uid
= sbp
->st_uid
;
5441 usbp
->st_gid
= sbp
->st_gid
;
5442 usbp
->st_rdev
= sbp
->st_rdev
;
5443 #ifndef _POSIX_SOURCE
5444 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
5445 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
5446 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
5447 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
5448 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
5449 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
5451 usbp
->st_atime
= sbp
->st_atime
;
5452 usbp
->st_atimensec
= sbp
->st_atimensec
;
5453 usbp
->st_mtime
= sbp
->st_mtime
;
5454 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
5455 usbp
->st_ctime
= sbp
->st_ctime
;
5456 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
5458 usbp
->st_size
= sbp
->st_size
;
5459 usbp
->st_blocks
= sbp
->st_blocks
;
5460 usbp
->st_blksize
= sbp
->st_blksize
;
5461 usbp
->st_flags
= sbp
->st_flags
;
5462 usbp
->st_gen
= sbp
->st_gen
;
5463 usbp
->st_lspare
= sbp
->st_lspare
;
5464 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
5465 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];