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 <libkern/OSAtomic.h>
103 * The currently logged-in user, for ownership of files/directories whose on-disk
104 * permissions are ignored:
108 static int change_dir(struct nameidata
*ndp
, vfs_context_t ctx
);
109 static void checkdirs(struct vnode
*olddp
, vfs_context_t ctx
);
110 void enablequotas(struct mount
*mp
, vfs_context_t ctx
);
111 static int getfsstat_callback(mount_t mp
, void * arg
);
112 static int getutimes(user_addr_t usrtvp
, struct timespec
*tsp
);
113 static int setutimes(vfs_context_t ctx
, struct vnode
*vp
, const struct timespec
*ts
, int nullflag
);
114 static int sync_callback(mount_t
, void *);
115 static int munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
116 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
117 boolean_t partial_copy
);
119 __private_extern__
int sync_internal(void);
121 #ifdef __APPLE_API_OBSOLETE
123 int fd
; /* file descriptor of the target file */
124 struct vstat
*vsb
; /* vstat structure for returned info */
127 const char *path
; /* pathname of the target file */
128 struct vstat
*vsb
; /* vstat structure for returned info */
130 struct mkcomplex_args
{
131 const char *path
; /* pathname of the file to be created */
132 mode_t mode
; /* access mode for the newly created file */
133 u_long type
; /* format of the complex file */
136 const char *path
; /* pathname of the target file */
137 struct vstat
*vsb
; /* vstat structure for returned info */
140 int fstatv(struct proc
*p
, struct fstatv_args
*uap
, register_t
*retval
);
141 int lstatv(struct proc
*p
, struct lstatv_args
*uap
, register_t
*retval
);
142 int mkcomplex(struct proc
*p
, struct mkcomplex_args
*uap
, register_t
*retval
);
143 int statv(struct proc
*p
, struct statv_args
*uap
, register_t
*retval
);
145 #endif /* __APPLE_API_OBSOLETE */
148 extern int (**union_vnodeop_p
)(void *);
149 extern struct vnode
*union_dircache(struct vnode
*, struct proc
*);
152 /* counts number of mount and unmount operations */
153 unsigned int vfs_nummntops
=0;
155 extern struct fileops vnops
;
157 extern void mount_list_add(mount_t mp
);
158 extern void mount_list_remove(mount_t mp
);
159 extern int mount_refdrain(mount_t mp
);
160 extern int vcount(struct vnode
*vp
);
164 * Virtual File System System Calls
168 * Mount a file system.
172 mount(struct proc
*p
, register struct mount_args
*uap
, __unused register_t
*retval
)
175 struct vnode
*devvp
= NULLVP
;
176 struct vnode
*device_vnode
= NULLVP
;
178 struct vfstable
*vfsp
;
180 struct vnode_attr va
;
181 struct vfs_context context
;
183 struct nameidata nd1
;
184 char fstypename
[MFSNAMELEN
];
186 user_addr_t devpath
= USER_ADDR_NULL
;
187 user_addr_t fsmountargs
= uap
->data
;
192 boolean_t is_rwlock_locked
= FALSE
;
194 AUDIT_ARG(fflags
, uap
->flags
);
197 context
.vc_ucred
= kauth_cred_get();
198 is_64bit
= proc_is64bit(p
);
201 * Get vnode to be covered
203 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
204 UIO_USERSPACE
, uap
->path
, &context
);
210 if ((vp
->v_flag
& VROOT
) &&
211 (vp
->v_mount
->mnt_flag
& MNT_ROOTFS
))
212 uap
->flags
|= MNT_UPDATE
;
214 if (uap
->flags
& MNT_UPDATE
) {
215 if ((vp
->v_flag
& VROOT
) == 0) {
221 /* unmount in progress return error */
223 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
229 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
230 is_rwlock_locked
= TRUE
;
232 * We only allow the filesystem to be reloaded if it
233 * is currently mounted read-only.
235 if ((uap
->flags
& MNT_RELOAD
) &&
236 ((mp
->mnt_flag
& MNT_RDONLY
) == 0)) {
241 * Only root, or the user that did the original mount is
242 * permitted to update it.
244 if (mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(context
.vc_ucred
) &&
245 (error
= suser(context
.vc_ucred
, &p
->p_acflag
))) {
249 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV,
250 * and MNT_NOEXEC if mount point is already MNT_NOEXEC.
252 if (suser(context
.vc_ucred
, NULL
)) {
253 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
254 if (mp
->mnt_flag
& MNT_NOEXEC
)
255 uap
->flags
|= MNT_NOEXEC
;
260 uap
->flags
& (MNT_RELOAD
| MNT_FORCE
| MNT_UPDATE
);
262 vfsp
= mp
->mnt_vtable
;
266 * If the user is not root, ensure that they own the directory
267 * onto which we are attempting to mount.
270 VATTR_WANTED(&va
, va_uid
);
271 if ((error
= vnode_getattr(vp
, &va
, &context
)) ||
272 (va
.va_uid
!= kauth_cred_getuid(context
.vc_ucred
) &&
273 (error
= suser(context
.vc_ucred
, &p
->p_acflag
)))) {
277 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV, and
278 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
280 if (suser(context
.vc_ucred
, NULL
)) {
281 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
282 if (vp
->v_mount
->mnt_flag
& MNT_NOEXEC
)
283 uap
->flags
|= MNT_NOEXEC
;
285 if ( (error
= VNOP_FSYNC(vp
, MNT_WAIT
, &context
)) )
288 if ( (error
= buf_invalidateblks(vp
, BUF_WRITE_DATA
, 0, 0)) )
291 if (vp
->v_type
!= VDIR
) {
295 if ( (error
= copyinstr(uap
->type
, fstypename
, MFSNAMELEN
, &dummy
)) )
298 /* XXXAUDIT: Should we capture the type on the error path as well? */
299 AUDIT_ARG(text
, fstypename
);
301 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
302 if (!strcmp(vfsp
->vfc_name
, fstypename
))
309 if (ISSET(vp
->v_flag
, VMOUNT
) && (vp
->v_mountedhere
!= NULL
)) {
313 SET(vp
->v_flag
, VMOUNT
);
316 * Allocate and initialize the filesystem.
318 MALLOC_ZONE(mp
, struct mount
*, (u_long
)sizeof(struct mount
),
320 bzero((char *)mp
, (u_long
)sizeof(struct mount
));
323 /* Initialize the default IO constraints */
324 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
325 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
326 mp
->mnt_maxsegreadsize
= mp
->mnt_maxreadcnt
;
327 mp
->mnt_maxsegwritesize
= mp
->mnt_maxwritecnt
;
328 mp
->mnt_devblocksize
= DEV_BSIZE
;
330 TAILQ_INIT(&mp
->mnt_vnodelist
);
331 TAILQ_INIT(&mp
->mnt_workerqueue
);
332 TAILQ_INIT(&mp
->mnt_newvnodes
);
334 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
335 is_rwlock_locked
= TRUE
;
336 mp
->mnt_op
= vfsp
->vfc_vfsops
;
337 mp
->mnt_vtable
= vfsp
;
339 vfsp
->vfc_refcount
++;
341 //mp->mnt_stat.f_type = vfsp->vfc_typenum;
342 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
343 strncpy(mp
->mnt_vfsstat
.f_fstypename
, vfsp
->vfc_name
, MFSTYPENAMELEN
);
344 strncpy(mp
->mnt_vfsstat
.f_mntonname
, nd
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
345 mp
->mnt_vnodecovered
= vp
;
346 mp
->mnt_vfsstat
.f_owner
= kauth_cred_getuid(context
.vc_ucred
);
348 /* XXX 3762912 hack to support HFS filesystem 'owner' - filesystem may update later */
349 vfs_setowner(mp
, KAUTH_UID_NONE
, KAUTH_GID_NONE
);
353 * Set the mount level flags.
355 if (uap
->flags
& MNT_RDONLY
)
356 mp
->mnt_flag
|= MNT_RDONLY
;
357 else if (mp
->mnt_flag
& MNT_RDONLY
)
358 mp
->mnt_kern_flag
|= MNTK_WANTRDWR
;
359 mp
->mnt_flag
&= ~(MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
360 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
361 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
);
362 mp
->mnt_flag
|= uap
->flags
& (MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
363 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
364 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
|
367 if (vfsp
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
369 if ( (error
= copyin(fsmountargs
, (caddr_t
)&devpath
, sizeof(devpath
))) )
371 fsmountargs
+= sizeof(devpath
);
374 if ( (error
= copyin(fsmountargs
, (caddr_t
)&tmp
, sizeof(tmp
))) )
376 /* munge into LP64 addr */
377 devpath
= CAST_USER_ADDR_T(tmp
);
378 fsmountargs
+= sizeof(tmp
);
381 /* if it is not update and device name needs to be parsed */
383 NDINIT(&nd1
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, devpath
, &context
);
384 if ( (error
= namei(&nd1
)) )
387 strncpy(mp
->mnt_vfsstat
.f_mntfromname
, nd1
.ni_cnd
.cn_pnbuf
, MAXPATHLEN
);
392 if (devvp
->v_type
!= VBLK
) {
396 if (major(devvp
->v_rdev
) >= nblkdev
) {
401 * If mount by non-root, then verify that user has necessary
402 * permissions on the device.
404 if (suser(context
.vc_ucred
, NULL
) != 0) {
405 accessmode
= KAUTH_VNODE_READ_DATA
;
406 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
407 accessmode
|= KAUTH_VNODE_WRITE_DATA
;
408 if ((error
= vnode_authorize(devvp
, NULL
, accessmode
, &context
)) != 0)
412 if (devpath
&& ((uap
->flags
& MNT_UPDATE
) == 0)) {
413 if ( (error
= vnode_ref(devvp
)) )
416 * Disallow multiple mounts of the same device.
417 * Disallow mounting of a device that is currently in use
418 * (except for root, which might share swap device for miniroot).
419 * Flush out any old buffers remaining from a previous use.
421 if ( (error
= vfs_mountedon(devvp
)) )
424 if (vcount(devvp
) > 1 && !(vfs_flags(mp
) & MNT_ROOTFS
)) {
428 if ( (error
= VNOP_FSYNC(devvp
, MNT_WAIT
, &context
)) ) {
432 if ( (error
= buf_invalidateblks(devvp
, BUF_WRITE_DATA
, 0, 0)) )
435 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
436 if ( (error
= VNOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, &context
)) )
439 mp
->mnt_devvp
= devvp
;
440 device_vnode
= devvp
;
442 if ((mp
->mnt_flag
& MNT_RDONLY
) && (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)) {
444 * If upgrade to read-write by non-root, then verify
445 * that user has necessary permissions on the device.
447 device_vnode
= mp
->mnt_devvp
;
448 if (device_vnode
&& suser(context
.vc_ucred
, NULL
)) {
449 if ((error
= vnode_authorize(device_vnode
, NULL
,
450 KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0)
454 device_vnode
= NULLVP
;
460 * Mount the filesystem.
462 error
= VFS_MOUNT(mp
, device_vnode
, fsmountargs
, &context
);
464 if (uap
->flags
& MNT_UPDATE
) {
465 if (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)
466 mp
->mnt_flag
&= ~MNT_RDONLY
;
468 (MNT_UPDATE
| MNT_RELOAD
| MNT_FORCE
);
469 mp
->mnt_kern_flag
&=~ MNTK_WANTRDWR
;
472 vfs_event_signal(NULL
, VQ_UPDATE
, (intptr_t)NULL
);
473 lck_rw_done(&mp
->mnt_rwlock
);
474 is_rwlock_locked
= FALSE
;
476 enablequotas(mp
,&context
);
480 * Put the new filesystem on the mount list after root.
483 CLR(vp
->v_flag
, VMOUNT
);
486 vp
->v_mountedhere
= mp
;
491 vfs_event_signal(NULL
, VQ_MOUNT
, (intptr_t)NULL
);
492 checkdirs(vp
, &context
);
493 lck_rw_done(&mp
->mnt_rwlock
);
494 is_rwlock_locked
= FALSE
;
497 * there is no cleanup code here so I have made it void
498 * we need to revisit this
500 (void)VFS_START(mp
, 0, &context
);
502 /* increment the operations count */
503 OSAddAtomic(1, (SInt32
*)&vfs_nummntops
);
504 enablequotas(mp
,&context
);
507 device_vnode
->v_specflags
|= SI_MOUNTEDON
;
510 * cache the IO attributes for the underlying physical media...
511 * an error return indicates the underlying driver doesn't
512 * support all the queries necessary... however, reasonable
513 * defaults will have been set, so no reason to bail or care
515 vfs_init_io_attributes(device_vnode
, mp
);
518 CLR(vp
->v_flag
, VMOUNT
);
520 mp
->mnt_vtable
->vfc_refcount
--;
524 VNOP_CLOSE(device_vnode
, ronly
? FREAD
: FREAD
|FWRITE
, &context
);
525 vnode_rele(device_vnode
);
527 lck_rw_done(&mp
->mnt_rwlock
);
528 is_rwlock_locked
= FALSE
;
529 mount_lock_destroy(mp
);
530 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
535 * drop I/O count on covered 'vp' and
536 * on the device vp if there was one
538 if (devpath
&& devvp
)
547 if (devpath
&& devvp
)
550 /* Release mnt_rwlock only when it was taken */
551 if (is_rwlock_locked
== TRUE
) {
552 lck_rw_done(&mp
->mnt_rwlock
);
555 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
564 enablequotas(struct mount
*mp
, vfs_context_t context
)
566 struct nameidata qnd
;
568 char qfpath
[MAXPATHLEN
];
569 const char *qfname
= QUOTAFILENAME
;
570 const char *qfopsname
= QUOTAOPSNAME
;
571 const char *qfextension
[] = INITQFNAMES
;
573 if ((strcmp(mp
->mnt_vfsstat
.f_fstypename
, "hfs") != 0 )
574 && (strcmp( mp
->mnt_vfsstat
.f_fstypename
, "ufs") != 0))
578 * Enable filesystem disk quotas if necessary.
579 * We ignore errors as this should not interfere with final mount
581 for (type
=0; type
< MAXQUOTAS
; type
++) {
582 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfopsname
, qfextension
[type
]);
583 NDINIT(&qnd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE32
, CAST_USER_ADDR_T(qfpath
), context
);
584 if (namei(&qnd
) != 0)
585 continue; /* option file to trigger quotas is not present */
586 vnode_put(qnd
.ni_vp
);
588 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_vfsstat
.f_mntonname
, qfname
, qfextension
[type
]);
590 (void) VFS_QUOTACTL(mp
, QCMD(Q_QUOTAON
, type
), 0, qfpath
, context
);
596 * Scan all active processes to see if any of them have a current
597 * or root directory onto which the new filesystem has just been
598 * mounted. If so, replace them with the new mount point.
601 checkdirs(olddp
, context
)
603 vfs_context_t context
;
605 struct filedesc
*fdp
;
609 struct vnode
*fdp_cvp
;
610 struct vnode
*fdp_rvp
;
611 int cdir_changed
= 0;
612 int rdir_changed
= 0;
613 boolean_t funnel_state
;
615 if (olddp
->v_usecount
== 1)
617 if (VFS_ROOT(olddp
->v_mountedhere
, &newdp
, context
))
618 panic("mount: lost mount");
619 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
621 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
624 if (fdp
== (struct filedesc
*)0) {
628 fdp_cvp
= fdp
->fd_cdir
;
629 fdp_rvp
= fdp
->fd_rdir
;
632 if (fdp_cvp
== olddp
) {
639 if (fdp_rvp
== olddp
) {
646 if (cdir_changed
|| rdir_changed
) {
648 fdp
->fd_cdir
= fdp_cvp
;
649 fdp
->fd_rdir
= fdp_rvp
;
653 if (rootvnode
== olddp
) {
659 thread_funnel_set(kernel_flock
, funnel_state
);
665 * Unmount a file system.
667 * Note: unmount takes a path to the vnode mounted on as argument,
668 * not special file (as before).
672 unmount(struct proc
*p
, register struct unmount_args
*uap
, __unused register_t
*retval
)
674 register struct vnode
*vp
;
678 struct vfs_context context
;
681 context
.vc_ucred
= kauth_cred_get();
683 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
684 UIO_USERSPACE
, uap
->path
, &context
);
693 * Must be the root of the filesystem
695 if ((vp
->v_flag
& VROOT
) == 0) {
700 return (safedounmount(mp
, uap
->flags
, p
));
704 * Do the actual file system unmount, prevent some common foot shooting.
706 * XXX Should take a "vfs_context_t" instead of a "struct proc *"
709 safedounmount(mp
, flags
, p
)
717 * Only root, or the user that did the original mount is
718 * permitted to unmount this filesystem.
720 if ((mp
->mnt_vfsstat
.f_owner
!= kauth_cred_getuid(kauth_cred_get())) &&
721 (error
= suser(kauth_cred_get(), &p
->p_acflag
)))
725 * Don't allow unmounting the root file system.
727 if (mp
->mnt_flag
& MNT_ROOTFS
)
728 return (EBUSY
); /* the root is always busy */
730 return (dounmount(mp
, flags
, p
));
734 * Do the actual file system unmount.
737 dounmount(mp
, flags
, p
)
738 register struct mount
*mp
;
742 struct vnode
*coveredvp
= (vnode_t
)0;
745 struct vfs_context context
;
746 int forcedunmount
= 0;
750 context
.vc_ucred
= kauth_cred_get();
752 if (flags
& MNT_FORCE
)
755 /* XXX post jaguar fix LK_DRAIN - then clean this up */
756 if ((flags
& MNT_FORCE
)) {
757 mp
->mnt_kern_flag
|= MNTK_FRCUNMOUNT
;
758 mp
->mnt_lflag
|= MNT_LFORCE
;
760 if (mp
->mnt_lflag
& MNT_LUNMOUNT
) {
761 mp
->mnt_lflag
|= MNT_LWAIT
;
762 msleep((caddr_t
)mp
, &mp
->mnt_mlock
, (PVFS
| PDROP
), "dounmount", 0 );
764 * The prior unmount attempt has probably succeeded.
765 * Do not dereference mp here - returning EBUSY is safest.
769 mp
->mnt_kern_flag
|= MNTK_UNMOUNT
;
770 mp
->mnt_lflag
|= MNT_LUNMOUNT
;
771 mp
->mnt_flag
&=~ MNT_ASYNC
;
773 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
774 fsevent_unmount(mp
); /* has to come first! */
776 if (forcedunmount
== 0) {
777 ubc_umount(mp
); /* release cached vnodes */
778 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
779 error
= VFS_SYNC(mp
, MNT_WAIT
, &context
);
782 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
783 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
784 mp
->mnt_lflag
&= ~MNT_LFORCE
;
791 lflags
|= FORCECLOSE
;
792 error
= vflush(mp
, NULLVP
, SKIPSWAP
| SKIPSYSTEM
| SKIPROOT
| lflags
);
793 if ((forcedunmount
== 0) && error
) {
795 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
796 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
797 mp
->mnt_lflag
&= ~MNT_LFORCE
;
801 /* make sure there are no one in the mount iterations or lookup */
804 error
= VFS_UNMOUNT(mp
, flags
, &context
);
808 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
809 mp
->mnt_lflag
&= ~MNT_LUNMOUNT
;
810 mp
->mnt_lflag
&= ~MNT_LFORCE
;
814 /* increment the operations count */
816 OSAddAtomic(1, (SInt32
*)&vfs_nummntops
);
818 if ( mp
->mnt_devvp
&& mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFSLOCALARGS
) {
819 mp
->mnt_devvp
->v_specflags
&= ~SI_MOUNTEDON
;
820 VNOP_CLOSE(mp
->mnt_devvp
, mp
->mnt_flag
& MNT_RDONLY
? FREAD
: FREAD
|FWRITE
,
822 vnode_rele(mp
->mnt_devvp
);
824 lck_rw_done(&mp
->mnt_rwlock
);
825 mount_list_remove(mp
);
826 lck_rw_lock_exclusive(&mp
->mnt_rwlock
);
828 /* mark the mount point hook in the vp but not drop the ref yet */
829 if ((coveredvp
= mp
->mnt_vnodecovered
) != NULLVP
) {
830 vnode_getwithref(coveredvp
);
831 vnode_lock(coveredvp
);
832 coveredvp
->v_mountedhere
= (struct mount
*)0;
833 vnode_unlock(coveredvp
);
834 vnode_put(coveredvp
);
838 mp
->mnt_vtable
->vfc_refcount
--;
841 cache_purgevfs(mp
); /* remove cache entries for this file sys */
842 vfs_event_signal(NULL
, VQ_UNMOUNT
, (intptr_t)NULL
);
844 mp
->mnt_lflag
|= MNT_LDEAD
;
846 if (mp
->mnt_lflag
& MNT_LWAIT
) {
849 * in case we block in mount_refdrain
850 * which will drop the mount lock
851 * and allow anyone blocked in vfs_busy
852 * to wakeup and see the LDEAD state
854 mp
->mnt_lflag
&= ~MNT_LWAIT
;
859 if (mp
->mnt_lflag
& MNT_LWAIT
) {
860 mp
->mnt_lflag
&= ~MNT_LWAIT
;
864 lck_rw_done(&mp
->mnt_rwlock
);
869 if ((coveredvp
!= NULLVP
)) {
870 vnode_getwithref(coveredvp
);
871 vnode_rele(coveredvp
);
872 vnode_lock(coveredvp
);
873 if(mp
->mnt_crossref
== 0) {
874 vnode_unlock(coveredvp
);
875 mount_lock_destroy(mp
);
876 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
878 coveredvp
->v_lflag
|= VL_MOUNTDEAD
;
879 vnode_unlock(coveredvp
);
881 vnode_put(coveredvp
);
882 } else if (mp
->mnt_flag
& MNT_ROOTFS
) {
883 mount_lock_destroy(mp
);
884 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
886 panic("dounmount: no coveredvp");
892 mount_dropcrossref(mount_t mp
, vnode_t dp
, int need_put
)
896 if (mp
->mnt_crossref
< 0)
897 panic("mount cross refs -ve");
898 if (((dp
->v_lflag
& VL_MOUNTDEAD
) == VL_MOUNTDEAD
) && (mp
->mnt_crossref
== 0)) {
899 dp
->v_lflag
&= ~VL_MOUNTDEAD
;
901 vnode_put_locked(dp
);
903 mount_lock_destroy(mp
);
904 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
908 vnode_put_locked(dp
);
914 * Sync each mounted filesystem.
918 struct ctldebug debug0
= { "syncprt", &syncprt
};
921 int print_vmpage_stat
=0;
924 sync_callback(mount_t mp
, __unused
void * arg
)
926 struct proc
* p
= current_proc();
928 struct vfs_context context
;
931 context
.vc_ucred
= kauth_cred_get();
933 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
934 asyncflag
= mp
->mnt_flag
& MNT_ASYNC
;
935 mp
->mnt_flag
&= ~MNT_ASYNC
;
936 VFS_SYNC(mp
, MNT_NOWAIT
, &context
);
938 mp
->mnt_flag
|= MNT_ASYNC
;
940 return(VFS_RETURNED
);
944 extern unsigned int vp_pagein
, vp_pgodirty
, vp_pgoclean
;
945 extern unsigned int dp_pgins
, dp_pgouts
;
949 sync(__unused
struct proc
*p
, __unused
struct sync_args
*uap
, __unused register_t
*retval
)
952 vfs_iterate(LK_NOWAIT
, sync_callback
, (void *)0);
954 if(print_vmpage_stat
) {
955 vm_countdirtypages();
956 printf("VP: %d: %d: %d: %d: %d\n", vp_pgodirty
, vp_pgoclean
, vp_pagein
,
957 dp_pgins
, dp_pgouts
);
963 #endif /* DIAGNOSTIC */
968 * Change filesystem quotas.
972 quotactl(struct proc
*p
, register struct quotactl_args
*uap
, __unused register_t
*retval
)
974 register struct mount
*mp
;
975 int error
, quota_cmd
, quota_status
;
979 struct vfs_context context
;
980 struct dqblk my_dqblk
;
983 context
.vc_ucred
= kauth_cred_get();
985 AUDIT_ARG(uid
, uap
->uid
, 0, 0, 0);
986 AUDIT_ARG(cmd
, uap
->cmd
);
987 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
988 UIO_USERSPACE
, uap
->path
, &context
);
992 mp
= nd
.ni_vp
->v_mount
;
996 /* copyin any data we will need for downstream code */
997 quota_cmd
= uap
->cmd
>> SUBCMDSHIFT
;
1001 /* uap->arg specifies a file from which to take the quotas */
1002 fnamelen
= MAXPATHLEN
;
1003 datap
= kalloc(MAXPATHLEN
);
1004 error
= copyinstr(uap
->arg
, datap
, MAXPATHLEN
, &fnamelen
);
1007 /* uap->arg is a pointer to a dqblk structure. */
1008 datap
= (caddr_t
) &my_dqblk
;
1012 /* uap->arg is a pointer to a dqblk structure. */
1013 datap
= (caddr_t
) &my_dqblk
;
1014 if (proc_is64bit(p
)) {
1015 struct user_dqblk my_dqblk64
;
1016 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk64
, sizeof (my_dqblk64
));
1018 munge_dqblk(&my_dqblk
, &my_dqblk64
, FALSE
);
1022 error
= copyin(uap
->arg
, (caddr_t
)&my_dqblk
, sizeof (my_dqblk
));
1026 /* uap->arg is a pointer to an integer */
1027 datap
= (caddr_t
) "a_status
;
1035 error
= VFS_QUOTACTL(mp
, uap
->cmd
, uap
->uid
, datap
, &context
);
1038 switch (quota_cmd
) {
1041 kfree(datap
, MAXPATHLEN
);
1044 /* uap->arg is a pointer to a dqblk structure we need to copy out to */
1046 if (proc_is64bit(p
)) {
1047 struct user_dqblk my_dqblk64
;
1048 munge_dqblk(&my_dqblk
, &my_dqblk64
, TRUE
);
1049 error
= copyout((caddr_t
)&my_dqblk64
, uap
->arg
, sizeof (my_dqblk64
));
1052 error
= copyout(datap
, uap
->arg
, sizeof (struct dqblk
));
1057 /* uap->arg is a pointer to an integer */
1059 error
= copyout(datap
, uap
->arg
, sizeof(quota_status
));
1070 * Get filesystem statistics.
1074 statfs(struct proc
*p
, register struct statfs_args
*uap
, __unused register_t
*retval
)
1077 struct vfsstatfs
*sp
;
1079 struct nameidata nd
;
1080 struct vfs_context context
;
1083 context
.vc_proc
= p
;
1084 context
.vc_ucred
= kauth_cred_get();
1086 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1087 UIO_USERSPACE
, uap
->path
, &context
);
1093 sp
= &mp
->mnt_vfsstat
;
1096 error
= vfs_update_vfsstat(mp
, &context
);
1101 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1106 * Get filesystem statistics.
1110 fstatfs(struct proc
*p
, register struct fstatfs_args
*uap
, __unused register_t
*retval
)
1114 struct vfsstatfs
*sp
;
1116 struct vfs_context context
;
1118 context
.vc_proc
= p
;
1119 context
.vc_ucred
= kauth_cred_get();
1121 AUDIT_ARG(fd
, uap
->fd
);
1123 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1126 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
1133 sp
= &mp
->mnt_vfsstat
;
1134 if ((error
= vfs_update_vfsstat(mp
, &context
)) != 0) {
1140 error
= munge_statfs(mp
, sp
, uap
->buf
, NULL
, IS_64BIT_PROCESS(p
), TRUE
);
1146 struct getfsstat_struct
{
1156 getfsstat_callback(mount_t mp
, void * arg
)
1159 struct getfsstat_struct
*fstp
= (struct getfsstat_struct
*)arg
;
1160 struct vfsstatfs
*sp
;
1161 struct proc
* p
= current_proc();
1163 struct vfs_context context
;
1165 context
.vc_proc
= p
;
1166 context
.vc_ucred
= kauth_cred_get();
1168 if (fstp
->sfsp
&& fstp
->count
< fstp
->maxcount
) {
1169 sp
= &mp
->mnt_vfsstat
;
1171 * If MNT_NOWAIT is specified, do not refresh the
1172 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
1174 if (((fstp
->flags
& MNT_NOWAIT
) == 0 || (fstp
->flags
& MNT_WAIT
)) &&
1175 (error
= vfs_update_vfsstat(mp
, &context
))) {
1176 KAUTH_DEBUG("vfs_update_vfsstat returned %d", error
);
1177 return(VFS_RETURNED
);
1181 * Need to handle LP64 version of struct statfs
1183 error
= munge_statfs(mp
, sp
, fstp
->sfsp
, &my_size
, IS_64BIT_PROCESS(p
), FALSE
);
1185 fstp
->error
= error
;
1186 return(VFS_RETURNED_DONE
);
1188 fstp
->sfsp
+= my_size
;
1191 return(VFS_RETURNED
);
1195 * Get statistics on all filesystems.
1198 getfsstat(__unused proc_t p
, struct getfsstat_args
*uap
, int *retval
)
1201 int count
, maxcount
;
1202 struct getfsstat_struct fst
;
1204 if (IS_64BIT_PROCESS(p
)) {
1205 maxcount
= uap
->bufsize
/ sizeof(struct user_statfs
);
1208 maxcount
= uap
->bufsize
/ sizeof(struct statfs
);
1214 fst
.flags
= uap
->flags
;
1217 fst
.maxcount
= maxcount
;
1220 vfs_iterate(0, getfsstat_callback
, &fst
);
1223 KAUTH_DEBUG("ERROR - %s gets %d", p
->p_comm
, fst
.error
);
1227 if (fst
.sfsp
&& fst
.count
> fst
.maxcount
)
1228 *retval
= fst
.maxcount
;
1230 *retval
= fst
.count
;
1234 #if COMPAT_GETFSSTAT
1235 ogetfsstat(p
, uap
, retval
)
1237 register struct getfsstat_args
*uap
;
1245 * Change current working directory to a given file descriptor.
1249 fchdir(struct proc
*p
, struct fchdir_args
*uap
, __unused register_t
*retval
)
1251 register struct filedesc
*fdp
= p
->p_fd
;
1252 struct vnode
*vp
, *tdp
, *tvp
;
1255 struct vfs_context context
;
1257 context
.vc_proc
= p
;
1258 context
.vc_ucred
= kauth_cred_get();
1260 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
1262 if ( (error
= vnode_getwithref(vp
)) ) {
1267 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
1269 if (vp
->v_type
!= VDIR
)
1272 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, &context
);
1273 while (!error
&& (mp
= vp
->v_mountedhere
) != NULL
) {
1274 if (vfs_busy(mp
, LK_NOWAIT
)) {
1278 error
= VFS_ROOT(mp
, &tdp
, &context
);
1287 if ( (error
= vnode_ref(vp
)) )
1309 * Change current working directory (``.'').
1313 chdir(struct proc
*p
, struct chdir_args
*uap
, __unused register_t
*retval
)
1315 register struct filedesc
*fdp
= p
->p_fd
;
1317 struct nameidata nd
;
1319 struct vfs_context context
;
1321 context
.vc_proc
= p
;
1322 context
.vc_ucred
= kauth_cred_get();
1324 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1325 UIO_USERSPACE
, uap
->path
, &context
);
1326 error
= change_dir(&nd
, &context
);
1329 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
1330 vnode_put(nd
.ni_vp
);
1334 * drop the iocount we picked up in change_dir
1336 vnode_put(nd
.ni_vp
);
1340 fdp
->fd_cdir
= nd
.ni_vp
;
1350 * Change notion of root (``/'') directory.
1354 chroot(struct proc
*p
, struct chroot_args
*uap
, __unused register_t
*retval
)
1356 register struct filedesc
*fdp
= p
->p_fd
;
1358 struct nameidata nd
;
1359 boolean_t shared_regions_active
;
1361 struct vfs_context context
;
1363 context
.vc_proc
= p
;
1364 context
.vc_ucred
= kauth_cred_get();
1366 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
1369 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1370 UIO_USERSPACE
, uap
->path
, &context
);
1371 error
= change_dir(&nd
, &context
);
1375 if(p
->p_flag
& P_NOSHLIB
) {
1376 shared_regions_active
= FALSE
;
1378 shared_regions_active
= TRUE
;
1380 if ((error
= clone_system_shared_regions(shared_regions_active
,
1381 TRUE
, /* chain_regions */
1383 vnode_put(nd
.ni_vp
);
1386 if ( (error
= vnode_ref(nd
.ni_vp
)) ) {
1387 vnode_put(nd
.ni_vp
);
1390 vnode_put(nd
.ni_vp
);
1394 fdp
->fd_rdir
= nd
.ni_vp
;
1395 fdp
->fd_flags
|= FD_CHROOT
;
1405 * Common routine for chroot and chdir.
1408 change_dir(struct nameidata
*ndp
, vfs_context_t ctx
)
1413 if ((error
= namei(ndp
)))
1417 if (vp
->v_type
!= VDIR
)
1420 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, ctx
);
1428 * Check permissions, allocate an open file structure,
1429 * and call the device open routine if any.
1432 #warning XXX implement uid, gid
1434 open1(vfs_context_t ctx
, user_addr_t upath
, int uflags
, struct vnode_attr
*vap
, register_t
*retval
)
1436 struct proc
*p
= vfs_context_proc(ctx
);
1437 register struct filedesc
*fdp
= p
->p_fd
;
1438 register struct fileproc
*fp
;
1439 register struct vnode
*vp
;
1441 struct fileproc
*nfp
;
1442 int type
, indx
, error
;
1444 struct nameidata nd
;
1448 if ((oflags
& O_ACCMODE
) == O_ACCMODE
)
1450 flags
= FFLAGS(uflags
);
1452 AUDIT_ARG(fflags
, oflags
);
1453 AUDIT_ARG(mode
, vap
->va_mode
);
1455 if ( (error
= falloc(p
, &nfp
, &indx
)) ) {
1459 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1460 UIO_USERSPACE
, upath
, ctx
);
1461 p
->p_dupfd
= -indx
- 1; /* XXX check for fdopen */
1463 if ((error
= vn_open_auth(&nd
, &flags
, vap
))) {
1464 if ((error
== ENODEV
|| error
== ENXIO
) && (p
->p_dupfd
>= 0)) { /* XXX from fdopen */
1465 if ((error
= dupfdopen(fdp
, indx
, p
->p_dupfd
, flags
, error
)) == 0) {
1466 fp_drop(p
, indx
, 0, 0);
1471 if (error
== ERESTART
)
1473 fp_free(p
, indx
, fp
);
1480 fp
->f_fglob
->fg_flag
= flags
& (FMASK
| O_EVTONLY
);
1481 fp
->f_fglob
->fg_type
= DTYPE_VNODE
;
1482 fp
->f_fglob
->fg_ops
= &vnops
;
1483 fp
->f_fglob
->fg_data
= (caddr_t
)vp
;
1485 if (flags
& (O_EXLOCK
| O_SHLOCK
)) {
1486 lf
.l_whence
= SEEK_SET
;
1489 if (flags
& O_EXLOCK
)
1490 lf
.l_type
= F_WRLCK
;
1492 lf
.l_type
= F_RDLCK
;
1494 if ((flags
& FNONBLOCK
) == 0)
1496 if ((error
= VNOP_ADVLOCK(vp
, (caddr_t
)fp
->f_fglob
, F_SETLK
, &lf
, type
, ctx
)))
1498 fp
->f_fglob
->fg_flag
|= FHASLOCK
;
1501 /* try to truncate by setting the size attribute */
1502 if ((flags
& O_TRUNC
) && ((error
= vnode_setsize(vp
, (off_t
)0, 0, ctx
)) != 0))
1508 *fdflags(p
, indx
) &= ~UF_RESERVED
;
1509 fp_drop(p
, indx
, fp
, 1);
1516 vn_close(vp
, fp
->f_fglob
->fg_flag
, fp
->f_fglob
->fg_cred
, p
);
1518 fp_free(p
, indx
, fp
);
1525 * An open system call using an extended argument list compared to the regular
1526 * system call 'open'.
1528 * Parameters: p Process requesting the open
1529 * uap User argument descriptor (see below)
1530 * retval Pointer to an area to receive the
1531 * return calue from the system call
1533 * Indirect: uap->path Path to open (same as 'open')
1534 * uap->flags Flags to open (same as 'open'
1535 * uap->uid UID to set, if creating
1536 * uap->gid GID to set, if creating
1537 * uap->mode File mode, if creating (same as 'open')
1538 * uap->xsecurity ACL to set, if creating
1540 * Returns: 0 Success
1543 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
1545 * XXX: We should enummerate the possible errno values here, and where
1546 * in the code they originated.
1549 open_extended(struct proc
*p
, struct open_extended_args
*uap
, register_t
*retval
)
1551 struct vfs_context context
;
1552 register struct filedesc
*fdp
= p
->p_fd
;
1554 kauth_filesec_t xsecdst
;
1555 struct vnode_attr va
;
1559 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
1560 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
1563 context
.vc_proc
= p
;
1564 context
.vc_ucred
= kauth_cred_get();
1567 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
1568 VATTR_SET(&va
, va_mode
, cmode
);
1569 if (uap
->uid
!= KAUTH_UID_NONE
)
1570 VATTR_SET(&va
, va_uid
, uap
->uid
);
1571 if (uap
->gid
!= KAUTH_GID_NONE
)
1572 VATTR_SET(&va
, va_gid
, uap
->gid
);
1573 if (xsecdst
!= NULL
)
1574 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
1576 ciferror
= open1(&context
, uap
->path
, uap
->flags
, &va
, retval
);
1577 if (xsecdst
!= NULL
)
1578 kauth_filesec_free(xsecdst
);
1584 open(struct proc
*p
, struct open_args
*uap
, register_t
*retval
)
1586 struct vfs_context context
;
1587 register struct filedesc
*fdp
= p
->p_fd
;
1588 struct vnode_attr va
;
1591 context
.vc_proc
= p
;
1592 context
.vc_ucred
= kauth_cred_get();
1595 /* Mask off all but regular access permissions */
1596 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
;
1597 VATTR_SET(&va
, va_mode
, cmode
& ACCESSPERMS
);
1599 return(open1(&context
, uap
->path
, uap
->flags
, &va
, retval
));
1604 * Create a special file.
1606 static int mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
);
1609 mknod(struct proc
*p
, register struct mknod_args
*uap
, __unused register_t
*retval
)
1611 struct vnode_attr va
;
1612 struct vfs_context context
;
1615 struct nameidata nd
;
1618 context
.vc_proc
= p
;
1619 context
.vc_ucred
= kauth_cred_get();
1622 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1623 VATTR_SET(&va
, va_rdev
, uap
->dev
);
1625 /* If it's a mknod() of a FIFO, call mkfifo1() instead */
1626 if ((uap
->mode
& S_IFMT
) == S_IFIFO
)
1627 return(mkfifo1(&context
, uap
->path
, &va
));
1629 AUDIT_ARG(mode
, uap
->mode
);
1630 AUDIT_ARG(dev
, uap
->dev
);
1632 if ((error
= suser(context
.vc_ucred
, &p
->p_acflag
)))
1634 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1635 UIO_USERSPACE
, uap
->path
, &context
);
1647 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
1650 switch (uap
->mode
& S_IFMT
) {
1651 case S_IFMT
: /* used by badsect to flag bad sectors */
1652 VATTR_SET(&va
, va_type
, VBAD
);
1655 VATTR_SET(&va
, va_type
, VCHR
);
1658 VATTR_SET(&va
, va_type
, VBLK
);
1668 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, CREATE
, &context
);
1670 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, &va
, 0, &context
);
1676 int update_flags
= 0;
1678 // Make sure the name & parent pointers are hooked up
1679 if (vp
->v_name
== NULL
)
1680 update_flags
|= VNODE_UPDATE_NAME
;
1681 if (vp
->v_parent
== NULLVP
)
1682 update_flags
|= VNODE_UPDATE_PARENT
;
1685 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
1687 add_fsevent(FSE_CREATE_FILE
, &context
,
1694 * nameidone has to happen before we vnode_put(dvp)
1695 * since it may need to release the fs_nodelock on the dvp
1707 * Create a named pipe.
1710 mkfifo1(vfs_context_t ctx
, user_addr_t upath
, struct vnode_attr
*vap
)
1714 struct nameidata nd
;
1716 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1717 UIO_USERSPACE
, upath
, ctx
);
1724 /* check that this is a new file and authorize addition */
1729 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
)) != 0)
1732 VATTR_SET(vap
, va_type
, VFIFO
);
1734 error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
);
1737 * nameidone has to happen before we vnode_put(dvp)
1738 * since it may need to release the fs_nodelock on the dvp
1751 * A mkfifo system call using an extended argument list compared to the regular
1752 * system call 'mkfifo'.
1754 * Parameters: p Process requesting the open
1755 * uap User argument descriptor (see below)
1758 * Indirect: uap->path Path to fifo (same as 'mkfifo')
1759 * uap->uid UID to set
1760 * uap->gid GID to set
1761 * uap->mode File mode to set (same as 'mkfifo')
1762 * uap->xsecurity ACL to set, if creating
1764 * Returns: 0 Success
1767 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
1769 * XXX: We should enummerate the possible errno values here, and where
1770 * in the code they originated.
1773 mkfifo_extended(struct proc
*p
, struct mkfifo_extended_args
*uap
, __unused register_t
*retval
)
1776 kauth_filesec_t xsecdst
;
1777 struct vfs_context context
;
1778 struct vnode_attr va
;
1780 xsecdst
= KAUTH_FILESEC_NONE
;
1781 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
1782 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
1786 context
.vc_proc
= p
;
1787 context
.vc_ucred
= kauth_cred_get();
1790 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1791 if (uap
->uid
!= KAUTH_UID_NONE
)
1792 VATTR_SET(&va
, va_uid
, uap
->uid
);
1793 if (uap
->gid
!= KAUTH_GID_NONE
)
1794 VATTR_SET(&va
, va_gid
, uap
->gid
);
1795 if (xsecdst
!= KAUTH_FILESEC_NONE
)
1796 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
1798 ciferror
= mkfifo1(&context
, uap
->path
, &va
);
1800 if (xsecdst
!= KAUTH_FILESEC_NONE
)
1801 kauth_filesec_free(xsecdst
);
1807 mkfifo(struct proc
*p
, register struct mkfifo_args
*uap
, __unused register_t
*retval
)
1809 struct vfs_context context
;
1810 struct vnode_attr va
;
1812 context
.vc_proc
= p
;
1813 context
.vc_ucred
= kauth_cred_get();
1816 VATTR_SET(&va
, va_mode
, (uap
->mode
& ALLPERMS
) & ~p
->p_fd
->fd_cmask
);
1818 return(mkfifo1(&context
, uap
->path
, &va
));
1822 * Make a hard file link.
1826 link(struct proc
*p
, register struct link_args
*uap
, __unused register_t
*retval
)
1828 vnode_t vp
, dvp
, lvp
;
1829 struct nameidata nd
;
1830 struct vfs_context context
;
1833 int need_event
, has_listeners
;
1835 context
.vc_proc
= p
;
1836 context
.vc_ucred
= kauth_cred_get();
1837 vp
= dvp
= lvp
= NULLVP
;
1839 /* look up the object we are linking to */
1840 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1841 UIO_USERSPACE
, uap
->path
, &context
);
1849 /* we're not allowed to link to directories */
1850 if (vp
->v_type
== VDIR
) {
1851 error
= EPERM
; /* POSIX */
1855 /* or to anything that kauth doesn't want us to (eg. immutable items) */
1856 if ((error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_LINKTARGET
, &context
)) != 0)
1859 /* lookup the target node */
1860 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1861 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| AUDITVNPATH2
;
1862 nd
.ni_dirp
= uap
->link
;
1868 /* target node must not exist */
1869 if (lvp
!= NULLVP
) {
1873 /* cannot link across mountpoints */
1874 if (vnode_mount(vp
) != vnode_mount(dvp
)) {
1879 /* authorize creation of the target note */
1880 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
1883 /* and finally make the link */
1884 error
= VNOP_LINK(vp
, dvp
, &nd
.ni_cnd
, &context
);
1888 need_event
= need_fsevent(FSE_CREATE_FILE
, dvp
);
1889 has_listeners
= kauth_authorize_fileop_has_listeners();
1891 if (need_event
|| has_listeners
) {
1892 char *target_path
= NULL
;
1893 char *link_to_path
= NULL
;
1894 int len
, link_name_len
;
1896 /* build the path to the new link file */
1897 target_path
= get_pathbuff();
1899 vn_getpath(dvp
, target_path
, &len
);
1900 target_path
[len
-1] = '/';
1901 strcpy(&target_path
[len
], nd
.ni_cnd
.cn_nameptr
);
1902 len
+= nd
.ni_cnd
.cn_namelen
;
1904 if (has_listeners
) {
1905 /* build the path to file we are linking to */
1906 link_to_path
= get_pathbuff();
1907 link_name_len
= MAXPATHLEN
;
1908 vn_getpath(vp
, link_to_path
, &link_name_len
);
1910 /* call out to allow 3rd party notification of rename.
1911 * Ignore result of kauth_authorize_fileop call.
1913 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_LINK
,
1914 (uintptr_t)link_to_path
, (uintptr_t)target_path
);
1915 if (link_to_path
!= NULL
)
1916 release_pathbuff(link_to_path
);
1919 /* construct fsevent */
1920 if (get_fse_info(vp
, &finfo
, &context
) == 0) {
1921 // build the path to the destination of the link
1922 add_fsevent(FSE_CREATE_FILE
, &context
,
1923 FSE_ARG_STRING
, len
, target_path
,
1924 FSE_ARG_FINFO
, &finfo
,
1928 release_pathbuff(target_path
);
1932 * nameidone has to happen before we vnode_put(dvp)
1933 * since it may need to release the fs_nodelock on the dvp
1946 * Make a symbolic link.
1948 * We could add support for ACLs here too...
1952 symlink(struct proc
*p
, register struct symlink_args
*uap
, __unused register_t
*retval
)
1954 struct vnode_attr va
;
1957 struct nameidata nd
;
1958 struct vfs_context context
;
1962 context
.vc_proc
= p
;
1963 context
.vc_ucred
= kauth_cred_get();
1965 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1966 error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
);
1969 AUDIT_ARG(text
, path
); /* This is the link string */
1971 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
1972 UIO_USERSPACE
, uap
->link
, &context
);
1981 VATTR_SET(&va
, va_type
, VLNK
);
1982 VATTR_SET(&va
, va_mode
, ACCESSPERMS
& ~p
->p_fd
->fd_cmask
);
1985 error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
);
1986 /* get default ownership, etc. */
1988 error
= vnode_authattr_new(dvp
, &va
, 0, &context
);
1990 error
= VNOP_SYMLINK(dvp
, &vp
, &nd
.ni_cnd
, &va
, path
, &context
);
1992 /* do fallback attribute handling */
1994 error
= vnode_setattr_fallback(vp
, &va
, &context
);
1997 int update_flags
= 0;
2000 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
2001 nd
.ni_cnd
.cn_flags
= 0;
2009 #if 0 /* XXX - kauth_todo - is KAUTH_FILEOP_SYMLINK needed? */
2010 /* call out to allow 3rd party notification of rename.
2011 * Ignore result of kauth_authorize_fileop call.
2013 if (kauth_authorize_fileop_has_listeners() &&
2015 char *new_link_path
= NULL
;
2018 /* build the path to the new link file */
2019 new_link_path
= get_pathbuff();
2021 vn_getpath(dvp
, new_link_path
, &len
);
2022 new_link_path
[len
- 1] = '/';
2023 strcpy(&new_link_path
[len
], nd
.ni_cnd
.cn_nameptr
);
2025 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_SYMLINK
,
2026 (uintptr_t)path
, (uintptr_t)new_link_path
);
2027 if (new_link_path
!= NULL
)
2028 release_pathbuff(new_link_path
);
2031 // Make sure the name & parent pointers are hooked up
2032 if (vp
->v_name
== NULL
)
2033 update_flags
|= VNODE_UPDATE_NAME
;
2034 if (vp
->v_parent
== NULLVP
)
2035 update_flags
|= VNODE_UPDATE_PARENT
;
2038 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
2040 add_fsevent(FSE_CREATE_FILE
, &context
,
2049 * nameidone has to happen before we vnode_put(dvp)
2050 * since it may need to release the fs_nodelock on the dvp
2058 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
2064 * Delete a whiteout from the filesystem.
2067 #warning XXX authorization not implmented for whiteouts
2069 undelete(struct proc
*p
, register struct undelete_args
*uap
, __unused register_t
*retval
)
2072 struct nameidata nd
;
2073 struct vfs_context context
;
2076 context
.vc_proc
= p
;
2077 context
.vc_ucred
= kauth_cred_get();
2079 NDINIT(&nd
, DELETE
, LOCKPARENT
|DOWHITEOUT
|AUDITVNPATH1
,
2080 UIO_USERSPACE
, uap
->path
, &context
);
2087 if (vp
== NULLVP
&& (nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
2088 error
= VNOP_WHITEOUT(dvp
, &nd
.ni_cnd
, DELETE
, &context
);
2093 * nameidone has to happen before we vnode_put(dvp)
2094 * since it may need to release the fs_nodelock on the dvp
2106 * Delete a name from the filesystem.
2110 _unlink(struct proc
*p
, struct unlink_args
*uap
, __unused register_t
*retval
, int nodelbusy
)
2114 struct nameidata nd
;
2115 struct vfs_context context
;
2116 struct componentname
*cnp
;
2119 context
.vc_proc
= p
;
2120 context
.vc_ucred
= kauth_cred_get();
2122 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
2123 UIO_USERSPACE
, uap
->path
, &context
);
2126 /* With Carbon delete semantics, busy files cannot be deleted */
2128 flags
|= VNODE_REMOVE_NODELETEBUSY
;
2136 if (vp
->v_type
== VDIR
) {
2137 error
= EPERM
; /* POSIX */
2140 * The root of a mounted filesystem cannot be deleted.
2142 if (vp
->v_flag
& VROOT
) {
2146 /* authorize the delete operation */
2148 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, &context
);
2155 if (need_fsevent(FSE_DELETE
, dvp
)) {
2156 path
= get_pathbuff();
2158 vn_getpath(vp
, path
, &len
);
2159 get_fse_info(vp
, &finfo
, &context
);
2161 error
= VNOP_REMOVE(dvp
, vp
, &nd
.ni_cnd
, flags
, &context
);
2163 if ( !error
&& path
!= NULL
) {
2164 add_fsevent(FSE_DELETE
, &context
,
2165 FSE_ARG_STRING
, len
, path
,
2166 FSE_ARG_FINFO
, &finfo
,
2170 release_pathbuff(path
);
2173 * nameidone has to happen before we vnode_put(dvp)
2174 * since it may need to release the fs_nodelock on the dvp
2183 * Delete a name from the filesystem using POSIX semantics.
2186 unlink(p
, uap
, retval
)
2188 struct unlink_args
*uap
;
2191 return _unlink(p
, uap
, retval
, 0);
2195 * Delete a name from the filesystem using Carbon semantics.
2198 delete(p
, uap
, retval
)
2200 struct delete_args
*uap
;
2203 return _unlink(p
, (struct unlink_args
*)uap
, retval
, 1);
2207 * Reposition read/write file offset.
2210 lseek(p
, uap
, retval
)
2212 register struct lseek_args
*uap
;
2215 struct fileproc
*fp
;
2217 struct vfs_context context
;
2218 off_t offset
= uap
->offset
, file_size
;
2221 if ( (error
= fp_getfvp(p
,uap
->fd
, &fp
, &vp
)) ) {
2222 if (error
== ENOTSUP
)
2226 if (vnode_isfifo(vp
)) {
2230 if ( (error
= vnode_getwithref(vp
)) ) {
2235 switch (uap
->whence
) {
2237 offset
+= fp
->f_fglob
->fg_offset
;
2240 context
.vc_proc
= p
;
2241 context
.vc_ucred
= kauth_cred_get();
2242 if ((error
= vnode_size(vp
, &file_size
, &context
)) != 0)
2244 offset
+= file_size
;
2252 if (uap
->offset
> 0 && offset
< 0) {
2253 /* Incremented/relative move past max size */
2257 * Allow negative offsets on character devices, per
2258 * POSIX 1003.1-2001. Most likely for writing disk
2261 if (offset
< 0 && vp
->v_type
!= VCHR
) {
2262 /* Decremented/relative move before start */
2266 fp
->f_fglob
->fg_offset
= offset
;
2267 *retval
= fp
->f_fglob
->fg_offset
;
2271 (void)vnode_put(vp
);
2278 * Check access permissions.
2281 access1(vnode_t vp
, vnode_t dvp
, int uflags
, vfs_context_t ctx
)
2283 kauth_action_t action
;
2287 * If just the regular access bits, convert them to something
2288 * that vnode_authorize will understand.
2290 if (!(uflags
& _ACCESS_EXTENDED_MASK
)) {
2293 action
|= KAUTH_VNODE_READ_DATA
; /* aka KAUTH_VNODE_LIST_DIRECTORY */
2294 if (uflags
& W_OK
) {
2295 if (vnode_isdir(vp
)) {
2296 action
|= KAUTH_VNODE_ADD_FILE
|
2297 KAUTH_VNODE_ADD_SUBDIRECTORY
;
2298 /* might want delete rights here too */
2300 action
|= KAUTH_VNODE_WRITE_DATA
;
2303 if (uflags
& X_OK
) {
2304 if (vnode_isdir(vp
)) {
2305 action
|= KAUTH_VNODE_SEARCH
;
2307 action
|= KAUTH_VNODE_EXECUTE
;
2311 /* take advantage of definition of uflags */
2312 action
= uflags
>> 8;
2315 /* action == 0 means only check for existence */
2317 error
= vnode_authorize(vp
, dvp
, action
| KAUTH_VNODE_ACCESS
, ctx
);
2327 /* XXX need to support the check-as uid argument */
2329 access_extended(__unused
struct proc
*p
, struct access_extended_args
*uap
, __unused register_t
*retval
)
2331 struct accessx_descriptor
*input
;
2333 int error
, limit
, nent
, i
, j
, wantdelete
;
2334 struct vfs_context context
;
2335 struct nameidata nd
;
2344 context
.vc_ucred
= NULL
;
2346 /* check input size and fetch descriptor array into allocated storage */
2347 if (uap
->size
> ACCESSX_MAX_TABLESIZE
)
2349 if (uap
->size
< sizeof(struct accessx_descriptor
))
2351 MALLOC(input
, struct accessx_descriptor
*, uap
->size
, M_TEMP
, M_WAITOK
);
2352 if (input
== NULL
) {
2356 error
= copyin(uap
->entries
, input
, uap
->size
);
2361 * Access is defined as checking against the process'
2362 * real identity, even if operations are checking the
2363 * effective identity. So we need to tweak the credential
2366 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
2367 context
.vc_proc
= current_proc();
2370 * Find out how many entries we have, so we can allocate the result array.
2372 limit
= uap
->size
/ sizeof(struct accessx_descriptor
);
2375 for (i
= 0; i
< nent
; i
++) {
2377 * Take the offset to the name string for this entry and convert to an
2378 * input array index, which would be one off the end of the array if this
2379 * was the lowest-addressed name string.
2381 j
= input
[i
].ad_name_offset
/ sizeof(struct accessx_descriptor
);
2387 /* implicit reference to previous name, not a real offset */
2389 /* first entry must have a name string */
2399 if (nent
> ACCESSX_MAX_DESCRIPTORS
) {
2403 MALLOC(result
, errno_t
*, nent
* sizeof(errno_t
), M_TEMP
, M_WAITOK
);
2404 if (result
== NULL
) {
2413 for (i
= 0; i
< nent
; i
++) {
2415 * Looking up a new name?
2417 if (input
[i
].ad_name_offset
!= 0) {
2418 /* discard old vnodes */
2428 /* scan forwards to see if we need the parent this time */
2429 wantdelete
= input
[i
].ad_flags
& _DELETE_OK
;
2430 for (j
= i
+ 1; (j
< nent
) && (input
[j
].ad_name_offset
== 0); j
++)
2431 if (input
[j
].ad_flags
& _DELETE_OK
)
2434 niopts
= FOLLOW
| AUDITVNPATH1
;
2435 /* need parent for vnode_authorize for deletion test */
2437 niopts
|= WANTPARENT
;
2440 NDINIT(&nd
, LOOKUP
, niopts
, UIO_SYSSPACE
, CAST_USER_ADDR_T((const char *)input
+ input
[i
].ad_name_offset
), &context
);
2451 * Handle lookup errors.
2461 /* run this access check */
2462 result
[i
] = access1(vp
, dvp
, input
[i
].ad_flags
, &context
);
2465 /* fatal lookup error */
2471 /* copy out results */
2472 error
= copyout(result
, uap
->results
, nent
* sizeof(errno_t
));
2476 FREE(input
, M_TEMP
);
2478 FREE(result
, M_TEMP
);
2483 if (context
.vc_ucred
)
2484 kauth_cred_rele(context
.vc_ucred
);
2489 access(__unused
struct proc
*p
, register struct access_args
*uap
, __unused register_t
*retval
)
2492 struct nameidata nd
;
2494 struct vfs_context context
;
2497 * Access is defined as checking against the process'
2498 * real identity, even if operations are checking the
2499 * effective identity. So we need to tweak the credential
2502 context
.vc_ucred
= kauth_cred_copy_real(kauth_cred_get());
2503 context
.vc_proc
= current_proc();
2505 niopts
= FOLLOW
| AUDITVNPATH1
;
2506 /* need parent for vnode_authorize for deletion test */
2507 if (uap
->flags
& _DELETE_OK
)
2508 niopts
|= WANTPARENT
;
2509 NDINIT(&nd
, LOOKUP
, niopts
, UIO_USERSPACE
, uap
->path
, &context
);
2514 error
= access1(nd
.ni_vp
, nd
.ni_dvp
, uap
->flags
, &context
);
2516 vnode_put(nd
.ni_vp
);
2517 if (uap
->flags
& _DELETE_OK
)
2518 vnode_put(nd
.ni_dvp
);
2522 kauth_cred_rele(context
.vc_ucred
);
2528 stat2(vfs_context_t ctx
, struct nameidata
*ndp
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2531 struct user_stat user_sb
;
2534 kauth_filesec_t fsec
;
2535 size_t xsecurity_bufsize
;
2540 fsec
= KAUTH_FILESEC_NONE
;
2541 error
= vn_stat(ndp
->ni_vp
, &sb
, (xsecurity
!= USER_ADDR_NULL
? &fsec
: NULL
), ctx
);
2542 vnode_put(ndp
->ni_vp
);
2547 /* Zap spare fields */
2549 sb
.st_qspare
[0] = 0LL;
2550 sb
.st_qspare
[1] = 0LL;
2551 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
2552 munge_stat(&sb
, &user_sb
);
2553 my_size
= sizeof(user_sb
);
2554 sbp
= (caddr_t
)&user_sb
;
2557 my_size
= sizeof(sb
);
2560 if ((error
= copyout(sbp
, ub
, my_size
)) != 0)
2563 /* caller wants extended security information? */
2564 if (xsecurity
!= USER_ADDR_NULL
) {
2566 /* did we get any? */
2567 if (fsec
== KAUTH_FILESEC_NONE
) {
2568 if (susize(xsecurity_size
, 0) != 0) {
2573 /* find the user buffer size */
2574 xsecurity_bufsize
= fusize(xsecurity_size
);
2576 /* copy out the actual data size */
2577 if (susize(xsecurity_size
, KAUTH_FILESEC_COPYSIZE(fsec
)) != 0) {
2582 /* if the caller supplied enough room, copy out to it */
2583 if (xsecurity_bufsize
>= KAUTH_FILESEC_COPYSIZE(fsec
))
2584 error
= copyout(fsec
, xsecurity
, KAUTH_FILESEC_COPYSIZE(fsec
));
2588 if (fsec
!= KAUTH_FILESEC_NONE
)
2589 kauth_filesec_free(fsec
);
2594 * Get file status; this version follows links.
2597 stat1(struct proc
*p
, user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2599 struct nameidata nd
;
2600 struct vfs_context context
;
2602 context
.vc_proc
= p
;
2603 context
.vc_ucred
= kauth_cred_get();
2605 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2606 UIO_USERSPACE
, path
, &context
);
2607 return(stat2(&context
, &nd
, ub
, xsecurity
, xsecurity_size
));
2611 stat_extended(struct proc
*p
, struct stat_extended_args
*uap
, __unused register_t
*retval
)
2613 return (stat1(p
, uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
));
2617 stat(struct proc
*p
, struct stat_args
*uap
, __unused register_t
*retval
)
2619 return(stat1(p
, uap
->path
, uap
->ub
, 0, 0));
2623 * Get file status; this version does not follow links.
2626 lstat1(struct proc
*p
, user_addr_t path
, user_addr_t ub
, user_addr_t xsecurity
, user_addr_t xsecurity_size
)
2628 struct nameidata nd
;
2629 struct vfs_context context
;
2631 context
.vc_proc
= p
;
2632 context
.vc_ucred
= kauth_cred_get();
2634 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
2635 UIO_USERSPACE
, path
, &context
);
2637 return(stat2(&context
, &nd
, ub
, xsecurity
, xsecurity_size
));
2641 lstat_extended(struct proc
*p
, struct lstat_extended_args
*uap
, __unused register_t
*retval
)
2643 return (lstat1(p
, uap
->path
, uap
->ub
, uap
->xsecurity
, uap
->xsecurity_size
));
2647 lstat(struct proc
*p
, struct lstat_args
*uap
, __unused register_t
*retval
)
2649 return(lstat1(p
, uap
->path
, uap
->ub
, 0, 0));
2653 * Get configurable pathname variables.
2657 pathconf(p
, uap
, retval
)
2659 register struct pathconf_args
*uap
;
2663 struct nameidata nd
;
2664 struct vfs_context context
;
2666 context
.vc_proc
= p
;
2667 context
.vc_ucred
= kauth_cred_get();
2669 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2670 UIO_USERSPACE
, uap
->path
, &context
);
2675 error
= vn_pathconf(nd
.ni_vp
, uap
->name
, retval
, &context
);
2677 vnode_put(nd
.ni_vp
);
2683 * Return target name of a symbolic link.
2687 readlink(p
, uap
, retval
)
2689 register struct readlink_args
*uap
;
2692 register struct vnode
*vp
;
2694 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
2696 struct nameidata nd
;
2697 struct vfs_context context
;
2698 char uio_buf
[ UIO_SIZEOF(1) ];
2700 context
.vc_proc
= p
;
2701 context
.vc_ucred
= kauth_cred_get();
2703 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNPATH1
,
2704 UIO_USERSPACE
, uap
->path
, &context
);
2712 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
2713 &uio_buf
[0], sizeof(uio_buf
));
2714 uio_addiov(auio
, uap
->buf
, uap
->count
);
2715 if (vp
->v_type
!= VLNK
)
2718 error
= vnode_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, &context
);
2720 error
= VNOP_READLINK(vp
, auio
, &context
);
2723 // LP64todo - fix this
2724 *retval
= uap
->count
- (int)uio_resid(auio
);
2729 * Change file flags.
2732 chflags1(vnode_t vp
, int flags
, vfs_context_t ctx
)
2734 struct vnode_attr va
;
2735 kauth_action_t action
;
2739 VATTR_SET(&va
, va_flags
, flags
);
2741 /* request authorisation, disregard immutability */
2742 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
2745 * Request that the auth layer disregard those file flags it's allowed to when
2746 * authorizing this operation; we need to do this in order to be able to
2747 * clear immutable flags.
2749 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
| KAUTH_VNODE_NOIMMUTABLE
, ctx
)) != 0))
2751 error
= vnode_setattr(vp
, &va
, ctx
);
2759 * Change flags of a file given a path name.
2763 chflags(struct proc
*p
, register struct chflags_args
*uap
, __unused register_t
*retval
)
2765 register struct vnode
*vp
;
2766 struct vfs_context context
;
2768 struct nameidata nd
;
2770 context
.vc_proc
= p
;
2771 context
.vc_ucred
= kauth_cred_get();
2773 AUDIT_ARG(fflags
, uap
->flags
);
2774 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2775 UIO_USERSPACE
, uap
->path
, &context
);
2782 error
= chflags1(vp
, uap
->flags
, &context
);
2788 * Change flags of a file given a file descriptor.
2792 fchflags(struct proc
*p
, register struct fchflags_args
*uap
, __unused register_t
*retval
)
2794 struct vfs_context context
;
2798 AUDIT_ARG(fd
, uap
->fd
);
2799 AUDIT_ARG(fflags
, uap
->flags
);
2800 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
2803 if ((error
= vnode_getwithref(vp
))) {
2808 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2810 context
.vc_proc
= p
;
2811 context
.vc_ucred
= kauth_cred_get();
2813 error
= chflags1(vp
, uap
->flags
, &context
);
2820 * Change security information on a filesystem object.
2823 chmod2(vfs_context_t ctx
, struct vnode
*vp
, struct vnode_attr
*vap
)
2825 kauth_action_t action
;
2828 AUDIT_ARG(mode
, (mode_t
)vap
->va_mode
);
2829 #warning XXX audit new args
2831 /* make sure that the caller is allowed to set this security information */
2832 if (((error
= vnode_authattr(vp
, vap
, &action
, ctx
)) != 0) ||
2833 ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0)) {
2834 if (error
== EACCES
)
2839 error
= vnode_setattr(vp
, vap
, ctx
);
2846 * Change mode of a file given path name.
2849 chmod1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
2851 struct nameidata nd
;
2854 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
2855 UIO_USERSPACE
, path
, ctx
);
2856 if ((error
= namei(&nd
)))
2858 error
= chmod2(ctx
, nd
.ni_vp
, vap
);
2859 vnode_put(nd
.ni_vp
);
2865 * A chmod system call using an extended argument list compared to the regular
2866 * system call 'mkfifo'.
2868 * Parameters: p Process requesting the open
2869 * uap User argument descriptor (see below)
2872 * Indirect: uap->path Path to object (same as 'chmod')
2873 * uap->uid UID to set
2874 * uap->gid GID to set
2875 * uap->mode File mode to set (same as 'chmod')
2876 * uap->xsecurity ACL to set (or delete)
2878 * Returns: 0 Success
2881 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
2883 * XXX: We should enummerate the possible errno values here, and where
2884 * in the code they originated.
2887 chmod_extended(struct proc
*p
, struct chmod_extended_args
*uap
, __unused register_t
*retval
)
2889 struct vfs_context context
;
2891 struct vnode_attr va
;
2892 kauth_filesec_t xsecdst
;
2895 if (uap
->mode
!= -1)
2896 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2897 if (uap
->uid
!= KAUTH_UID_NONE
)
2898 VATTR_SET(&va
, va_uid
, uap
->uid
);
2899 if (uap
->gid
!= KAUTH_GID_NONE
)
2900 VATTR_SET(&va
, va_gid
, uap
->gid
);
2903 switch(uap
->xsecurity
) {
2904 /* explicit remove request */
2905 case CAST_USER_ADDR_T((void *)1): /* _FILESEC_REMOVE_ACL */
2906 VATTR_SET(&va
, va_acl
, NULL
);
2909 case USER_ADDR_NULL
:
2912 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
2914 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
2915 KAUTH_DEBUG("CHMOD - setting ACL with %d entries", va
.va_acl
->acl_entrycount
);
2917 context
.vc_proc
= p
;
2918 context
.vc_ucred
= kauth_cred_get();
2920 error
= chmod1(&context
, uap
->path
, &va
);
2922 if (xsecdst
!= NULL
)
2923 kauth_filesec_free(xsecdst
);
2928 chmod(struct proc
*p
, register struct chmod_args
*uap
, __unused register_t
*retval
)
2930 struct vfs_context context
;
2931 struct vnode_attr va
;
2934 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2936 context
.vc_proc
= p
;
2937 context
.vc_ucred
= kauth_cred_get();
2939 return(chmod1(&context
, uap
->path
, &va
));
2943 * Change mode of a file given a file descriptor.
2946 fchmod1(struct proc
*p
, int fd
, struct vnode_attr
*vap
)
2950 struct vfs_context context
;
2952 context
.vc_proc
= p
;
2953 context
.vc_ucred
= kauth_cred_get();
2957 if ((error
= file_vnode(fd
, &vp
)) != 0)
2959 if ((error
= vnode_getwithref(vp
)) != 0) {
2963 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2965 error
= chmod2(&context
, vp
, vap
);
2966 (void)vnode_put(vp
);
2973 fchmod_extended(struct proc
*p
, struct fchmod_extended_args
*uap
, __unused register_t
*retval
)
2976 struct vnode_attr va
;
2977 kauth_filesec_t xsecdst
;
2980 if (uap
->mode
!= -1)
2981 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
2982 if (uap
->uid
!= KAUTH_UID_NONE
)
2983 VATTR_SET(&va
, va_uid
, uap
->uid
);
2984 if (uap
->gid
!= KAUTH_GID_NONE
)
2985 VATTR_SET(&va
, va_gid
, uap
->gid
);
2988 switch(uap
->xsecurity
) {
2989 case USER_ADDR_NULL
:
2990 VATTR_SET(&va
, va_acl
, NULL
);
2992 case CAST_USER_ADDR_T(-1):
2995 if ((error
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
2997 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
3000 error
= fchmod1(p
, uap
->fd
, &va
);
3003 switch(uap
->xsecurity
) {
3004 case USER_ADDR_NULL
:
3005 case CAST_USER_ADDR_T(-1):
3008 if (xsecdst
!= NULL
)
3009 kauth_filesec_free(xsecdst
);
3015 fchmod(struct proc
*p
, register struct fchmod_args
*uap
, __unused register_t
*retval
)
3017 struct vnode_attr va
;
3020 VATTR_SET(&va
, va_mode
, uap
->mode
& ALLPERMS
);
3022 return(fchmod1(p
, uap
->fd
, &va
));
3027 * Set ownership given a path name.
3031 chown1(vfs_context_t ctx
, register struct chown_args
*uap
, __unused register_t
*retval
, int follow
)
3033 register struct vnode
*vp
;
3034 struct vnode_attr va
;
3036 struct nameidata nd
;
3037 kauth_action_t action
;
3039 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
3041 NDINIT(&nd
, LOOKUP
, (follow
? FOLLOW
: 0) | AUDITVNPATH1
,
3042 UIO_USERSPACE
, uap
->path
, ctx
);
3051 * XXX A TEMPORARY HACK FOR NOW: Try to track console_user
3052 * by looking for chown() calls on /dev/console from a console process.
3054 if ((vp
) && (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
) && (vp
->v_specinfo
) &&
3055 (major(vp
->v_specinfo
->si_rdev
) == CONSMAJOR
) &&
3056 (minor(vp
->v_specinfo
->si_rdev
) == 0)) {
3057 console_user
= uap
->uid
;
3060 if (uap
->uid
!= VNOVAL
)
3061 VATTR_SET(&va
, va_uid
, uap
->uid
);
3062 if (uap
->gid
!= VNOVAL
)
3063 VATTR_SET(&va
, va_gid
, uap
->gid
);
3065 /* preflight and authorize attribute changes */
3066 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
3068 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
3070 error
= vnode_setattr(vp
, &va
, ctx
);
3074 * EACCES is only allowed from namei(); permissions failure should
3075 * return EPERM, so we need to translate the error code.
3077 if (error
== EACCES
)
3085 chown(struct proc
*p
, register struct chown_args
*uap
, register_t
*retval
)
3087 struct vfs_context context
;
3089 context
.vc_proc
= p
;
3090 context
.vc_ucred
= kauth_cred_get();
3092 return chown1(&context
, uap
, retval
, 1);
3096 lchown(struct proc
*p
, register struct lchown_args
*uap
, register_t
*retval
)
3098 struct vfs_context context
;
3100 context
.vc_proc
= p
;
3101 context
.vc_ucred
= kauth_cred_get();
3103 /* Argument list identical, but machine generated; cast for chown1() */
3104 return chown1(&context
, (struct chown_args
*)uap
, retval
, 0);
3108 * Set ownership given a file descriptor.
3112 fchown(struct proc
*p
, register struct fchown_args
*uap
, __unused register_t
*retval
)
3114 struct vnode_attr va
;
3115 struct vfs_context context
;
3118 kauth_action_t action
;
3120 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
3121 AUDIT_ARG(fd
, uap
->fd
);
3123 if ( (error
= file_vnode(uap
->fd
, &vp
)) )
3126 if ( (error
= vnode_getwithref(vp
)) ) {
3130 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3133 if (uap
->uid
!= VNOVAL
)
3134 VATTR_SET(&va
, va_uid
, uap
->uid
);
3135 if (uap
->gid
!= VNOVAL
)
3136 VATTR_SET(&va
, va_gid
, uap
->gid
);
3138 context
.vc_proc
= p
;
3139 context
.vc_ucred
= kauth_cred_get();
3141 /* preflight and authorize attribute changes */
3142 if ((error
= vnode_authattr(vp
, &va
, &action
, &context
)) != 0)
3144 if (action
&& ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0)) {
3145 if (error
== EACCES
)
3149 error
= vnode_setattr(vp
, &va
, &context
);
3152 (void)vnode_put(vp
);
3158 getutimes(usrtvp
, tsp
)
3160 struct timespec
*tsp
;
3162 struct user_timeval tv
[2];
3165 if (usrtvp
== USER_ADDR_NULL
) {
3166 struct timeval old_tv
;
3167 /* XXX Y2038 bug because of microtime argument */
3169 TIMEVAL_TO_TIMESPEC(&old_tv
, &tsp
[0]);
3172 if (IS_64BIT_PROCESS(current_proc())) {
3173 error
= copyin(usrtvp
, (void *)tv
, sizeof(tv
));
3175 struct timeval old_tv
[2];
3176 error
= copyin(usrtvp
, (void *)old_tv
, sizeof(old_tv
));
3177 tv
[0].tv_sec
= old_tv
[0].tv_sec
;
3178 tv
[0].tv_usec
= old_tv
[0].tv_usec
;
3179 tv
[1].tv_sec
= old_tv
[1].tv_sec
;
3180 tv
[1].tv_usec
= old_tv
[1].tv_usec
;
3184 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
3185 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
3191 setutimes(vfs_context_t ctx
, struct vnode
*vp
, const struct timespec
*ts
,
3195 struct vnode_attr va
;
3196 kauth_action_t action
;
3198 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3201 VATTR_SET(&va
, va_access_time
, ts
[0]);
3202 VATTR_SET(&va
, va_modify_time
, ts
[1]);
3204 va
.va_vaflags
|= VA_UTIMES_NULL
;
3206 if ((error
= vnode_authattr(vp
, &va
, &action
, ctx
)) != 0)
3208 /* since we may not need to auth anything, check here */
3209 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, ctx
)) != 0))
3211 error
= vnode_setattr(vp
, &va
, ctx
);
3218 * Set the access and modification times of a file.
3222 utimes(struct proc
*p
, register struct utimes_args
*uap
, __unused register_t
*retval
)
3224 struct timespec ts
[2];
3227 struct nameidata nd
;
3228 struct vfs_context context
;
3230 context
.vc_proc
= p
;
3231 context
.vc_ucred
= kauth_cred_get();
3233 /* AUDIT: Needed to change the order of operations to do the
3234 * name lookup first because auditing wants the path.
3236 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3237 UIO_USERSPACE
, uap
->path
, &context
);
3244 * Fetch the user-supplied time. If usrtvp is USER_ADDR_NULL, we fetch
3245 * the current time instead.
3248 if ((error
= getutimes(usrtvp
, ts
)) != 0)
3251 error
= setutimes(&context
, nd
.ni_vp
, ts
, usrtvp
== USER_ADDR_NULL
);
3254 vnode_put(nd
.ni_vp
);
3259 * Set the access and modification times of a file.
3263 futimes(struct proc
*p
, register struct futimes_args
*uap
, __unused register_t
*retval
)
3265 struct timespec ts
[2];
3269 struct vfs_context context
;
3271 context
.vc_proc
= p
;
3272 context
.vc_ucred
= kauth_cred_get();
3274 AUDIT_ARG(fd
, uap
->fd
);
3276 if ((error
= getutimes(usrtvp
, ts
)) != 0)
3278 if ((error
= file_vnode(uap
->fd
, &vp
)) != 0)
3280 if((error
= vnode_getwithref(vp
))) {
3285 error
= setutimes(&context
, vp
, ts
, usrtvp
== 0);
3292 * Truncate a file given its path name.
3296 truncate(struct proc
*p
, register struct truncate_args
*uap
, __unused register_t
*retval
)
3298 register struct vnode
*vp
;
3299 struct vnode_attr va
;
3300 struct vfs_context context
;
3302 struct nameidata nd
;
3303 kauth_action_t action
;
3305 context
.vc_proc
= p
;
3306 context
.vc_ucred
= kauth_cred_get();
3308 if (uap
->length
< 0)
3310 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
3311 UIO_USERSPACE
, uap
->path
, &context
);
3312 if ((error
= namei(&nd
)))
3319 VATTR_SET(&va
, va_data_size
, uap
->length
);
3320 if ((error
= vnode_authattr(vp
, &va
, &action
, &context
)) != 0)
3322 if ((action
!= 0) && ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0))
3324 error
= vnode_setattr(vp
, &va
, &context
);
3331 * Truncate a file given a file descriptor.
3335 ftruncate(p
, uap
, retval
)
3337 register struct ftruncate_args
*uap
;
3340 struct vfs_context context
;
3341 struct vnode_attr va
;
3343 struct fileproc
*fp
;
3347 context
.vc_proc
= current_proc();
3348 context
.vc_ucred
= kauth_cred_get();
3350 AUDIT_ARG(fd
, uap
->fd
);
3351 if (uap
->length
< 0)
3354 if ( (error
= fp_lookup(p
,fd
,&fp
,0)) ) {
3358 if (fp
->f_fglob
->fg_type
== DTYPE_PSXSHM
) {
3359 error
= pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
);
3362 if (fp
->f_fglob
->fg_type
!= DTYPE_VNODE
) {
3367 vp
= (struct vnode
*)fp
->f_fglob
->fg_data
;
3369 if ((fp
->f_fglob
->fg_flag
& FWRITE
) == 0) {
3370 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
3375 if ((error
= vnode_getwithref(vp
)) != 0) {
3379 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
3382 VATTR_SET(&va
, va_data_size
, uap
->length
);
3383 error
= vnode_setattr(vp
, &va
, &context
);
3384 (void)vnode_put(vp
);
3392 * Sync an open file.
3396 fsync(struct proc
*p
, struct fsync_args
*uap
, __unused register_t
*retval
)
3399 struct fileproc
*fp
;
3400 struct vfs_context context
;
3403 if ( (error
= fp_getfvp(p
, uap
->fd
, &fp
, &vp
)) )
3405 if ( (error
= vnode_getwithref(vp
)) ) {
3409 context
.vc_proc
= p
;
3410 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
3412 error
= VNOP_FSYNC(vp
, MNT_WAIT
, &context
);
3414 (void)vnode_put(vp
);
3420 * Duplicate files. Source must be a file, target must be a file or
3423 * XXX Copyfile authorisation checking is woefully inadequate, and will not
3424 * perform inheritance correctly.
3428 copyfile(struct proc
*p
, register struct copyfile_args
*uap
, __unused register_t
*retval
)
3430 vnode_t tvp
, fvp
, tdvp
, sdvp
;
3431 struct nameidata fromnd
, tond
;
3433 struct vfs_context context
;
3435 context
.vc_proc
= p
;
3436 context
.vc_ucred
= kauth_cred_get();
3438 /* Check that the flags are valid. */
3440 if (uap
->flags
& ~CPF_MASK
) {
3444 NDINIT(&fromnd
, LOOKUP
, SAVESTART
| AUDITVNPATH1
,
3445 UIO_USERSPACE
, uap
->from
, &context
);
3446 if ((error
= namei(&fromnd
)))
3450 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
| AUDITVNPATH2
,
3451 UIO_USERSPACE
, uap
->to
, &context
);
3452 if ((error
= namei(&tond
))) {
3459 if (!(uap
->flags
& CPF_OVERWRITE
)) {
3464 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
3469 if ((error
= vnode_authorize(tdvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
3475 * If source is the same as the destination (that is the
3476 * same inode number) then there is nothing to do.
3477 * (fixed to have POSIX semantics - CSM 3/2/98)
3482 error
= VNOP_COPYFILE(fvp
,tdvp
,tvp
,&tond
.ni_cnd
,uap
->mode
,uap
->flags
,&context
);
3484 sdvp
= tond
.ni_startdir
;
3486 * nameidone has to happen before we vnode_put(tdvp)
3487 * since it may need to release the fs_nodelock on the tdvp
3498 if (fromnd
.ni_startdir
)
3499 vnode_put(fromnd
.ni_startdir
);
3509 * Rename files. Source and destination must either both be directories,
3510 * or both not be directories. If target is a directory, it must be empty.
3514 rename(proc_t p
, register struct rename_args
*uap
, __unused register_t
*retval
)
3518 struct nameidata fromnd
, tond
;
3519 struct vfs_context context
;
3522 char *oname
, *from_name
, *to_name
;
3523 int from_len
, to_len
;
3524 int holding_mntlock
;
3525 mount_t locked_mp
= NULL
;
3527 fse_info from_finfo
, to_finfo
;
3529 context
.vc_proc
= p
;
3530 context
.vc_ucred
= kauth_cred_get();
3531 holding_mntlock
= 0;
3537 NDINIT(&fromnd
, DELETE
, WANTPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->from
, &context
);
3539 if ( (error
= namei(&fromnd
)) )
3541 fdvp
= fromnd
.ni_dvp
;
3544 NDINIT(&tond
, RENAME
, WANTPARENT
| AUDITVNPATH2
, UIO_USERSPACE
, uap
->to
, &context
);
3545 if (fvp
->v_type
== VDIR
)
3546 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
3548 if ( (error
= namei(&tond
)) ) {
3550 * Translate error code for rename("dir1", "dir2/.").
3552 if (error
== EISDIR
&& fvp
->v_type
== VDIR
)
3560 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
3563 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
3576 * If tvp is a directory and not the same as fdvp, or tdvp is not the same as fdvp,
3577 * the node is moving between directories and we need rights to remove from the
3578 * old and add to the new.
3580 * If tvp already exists and is not a directory, we need to be allowed to delete it.
3582 * Note that we do not inherit when renaming. XXX this needs to be revisited to
3583 * implement the deferred-inherit bit.
3589 if ((tvp
!= NULL
) && vnode_isdir(tvp
)) {
3592 } else if (tdvp
!= fdvp
) {
3596 * must have delete rights to remove the old name even in the simple case of
3599 if ((error
= vnode_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
, &context
)) != 0)
3602 /* moving into tdvp or tvp, must have rights to add */
3603 if ((error
= vnode_authorize(((tvp
!= NULL
) && vnode_isdir(tvp
)) ? tvp
: tdvp
,
3605 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
3609 /* node staying in same directory, must be allowed to add new name */
3610 if ((error
= vnode_authorize(fdvp
, NULL
,
3611 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
, &context
)) != 0)
3614 /* overwriting tvp */
3615 if ((tvp
!= NULL
) && !vnode_isdir(tvp
) &&
3616 ((error
= vnode_authorize(tvp
, tdvp
, KAUTH_VNODE_DELETE
, &context
)) != 0))
3619 /* XXX more checks? */
3622 /* authorization denied */
3627 * Allow the renaming of mount points.
3628 * - target must not exist
3629 * - target must reside in the same directory as source
3630 * - union mounts cannot be renamed
3631 * - "/" cannot be renamed
3633 if ((fvp
->v_flag
& VROOT
) &&
3634 (fvp
->v_type
== VDIR
) &&
3636 (fvp
->v_mountedhere
== NULL
) &&
3638 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
3639 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
3640 struct vnode
*coveredvp
;
3642 /* switch fvp to the covered vnode */
3643 coveredvp
= fvp
->v_mount
->mnt_vnodecovered
;
3644 if ( (vnode_getwithref(coveredvp
)) ) {
3654 * Check for cross-device rename.
3656 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
3657 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
3662 * Avoid renaming "." and "..".
3664 if (fvp
->v_type
== VDIR
&&
3666 (fromnd
.ni_cnd
.cn_namelen
== 1 && fromnd
.ni_cnd
.cn_nameptr
[0] == '.') ||
3667 ((fromnd
.ni_cnd
.cn_flags
| tond
.ni_cnd
.cn_flags
) & ISDOTDOT
)) ) {
3672 * The following edge case is caught here:
3673 * (to cannot be a descendent of from)
3686 if (tdvp
->v_parent
== fvp
) {
3692 * If source is the same as the destination (that is the
3693 * same inode number) then there is nothing to do...
3694 * EXCEPT if the underlying file system supports case
3695 * insensitivity and is case preserving. In this case
3696 * the file system needs to handle the special case of
3697 * getting the same vnode as target (fvp) and source (tvp).
3699 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
3700 * and _PC_CASE_PRESERVING can have this exception, and they need to
3701 * handle the special case of getting the same vnode as target and
3702 * source. NOTE: Then the target is unlocked going into vnop_rename,
3703 * so not to cause locking problems. There is a single reference on tvp.
3705 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
3706 * that correct behaviour then is just to remove the source (link)
3708 if (fvp
== tvp
&& fdvp
== tdvp
) {
3709 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
3710 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
3711 fromnd
.ni_cnd
.cn_namelen
)) {
3716 if (holding_mntlock
&& fvp
->v_mount
!= locked_mp
) {
3718 * we're holding a reference and lock
3719 * on locked_mp, but it no longer matches
3720 * what we want to do... so drop our hold
3722 mount_unlock_renames(locked_mp
);
3723 mount_drop(locked_mp
, 0);
3724 holding_mntlock
= 0;
3726 if (tdvp
!= fdvp
&& fvp
->v_type
== VDIR
) {
3728 * serialize renames that re-shape
3729 * the tree... if holding_mntlock is
3730 * set, then we're ready to go...
3732 * first need to drop the iocounts
3733 * we picked up, second take the
3734 * lock to serialize the access,
3735 * then finally start the lookup
3736 * process over with the lock held
3738 if (!holding_mntlock
) {
3740 * need to grab a reference on
3741 * the mount point before we
3742 * drop all the iocounts... once
3743 * the iocounts are gone, the mount
3746 locked_mp
= fvp
->v_mount
;
3747 mount_ref(locked_mp
, 0);
3750 * nameidone has to happen before we vnode_put(tvp)
3751 * since it may need to release the fs_nodelock on the tvp
3760 * nameidone has to happen before we vnode_put(fdvp)
3761 * since it may need to release the fs_nodelock on the fvp
3768 mount_lock_renames(locked_mp
);
3769 holding_mntlock
= 1;
3775 * when we dropped the iocounts to take
3776 * the lock, we allowed the identity of
3777 * the various vnodes to change... if they did,
3778 * we may no longer be dealing with a rename
3779 * that reshapes the tree... once we're holding
3780 * the iocounts, the vnodes can't change type
3781 * so we're free to drop the lock at this point
3784 if (holding_mntlock
) {
3785 mount_unlock_renames(locked_mp
);
3786 mount_drop(locked_mp
, 0);
3787 holding_mntlock
= 0;
3790 // save these off so we can later verify that fvp is the same
3791 oname
= fvp
->v_name
;
3792 oparent
= fvp
->v_parent
;
3794 if (need_fsevent(FSE_RENAME
, fvp
)) {
3795 get_fse_info(fvp
, &from_finfo
, &context
);
3798 get_fse_info(tvp
, &to_finfo
, &context
);
3800 from_name
= get_pathbuff();
3801 from_len
= MAXPATHLEN
;
3802 vn_getpath(fvp
, from_name
, &from_len
);
3804 to_name
= get_pathbuff();
3805 to_len
= MAXPATHLEN
;
3807 if (tvp
&& tvp
->v_type
!= VDIR
) {
3808 vn_getpath(tvp
, to_name
, &to_len
);
3810 vn_getpath(tdvp
, to_name
, &to_len
);
3811 // if the path is not just "/", then append a "/"
3813 to_name
[to_len
-1] = '/';
3817 strcpy(&to_name
[to_len
], tond
.ni_cnd
.cn_nameptr
);
3818 to_len
+= tond
.ni_cnd
.cn_namelen
+ 1;
3819 to_name
[to_len
] = '\0';
3825 error
= VNOP_RENAME(fdvp
, fvp
, &fromnd
.ni_cnd
,
3826 tdvp
, tvp
, &tond
.ni_cnd
,
3829 if (holding_mntlock
) {
3831 * we can drop our serialization
3834 mount_unlock_renames(locked_mp
);
3835 mount_drop(locked_mp
, 0);
3836 holding_mntlock
= 0;
3839 if (to_name
!= NULL
)
3840 release_pathbuff(to_name
);
3841 if (from_name
!= NULL
)
3842 release_pathbuff(from_name
);
3843 from_name
= to_name
= NULL
;
3848 /* call out to allow 3rd party notification of rename.
3849 * Ignore result of kauth_authorize_fileop call.
3851 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_RENAME
,
3852 (uintptr_t)from_name
, (uintptr_t)to_name
);
3854 if (from_name
!= NULL
&& to_name
!= NULL
) {
3856 add_fsevent(FSE_RENAME
, &context
,
3857 FSE_ARG_STRING
, from_len
, from_name
,
3858 FSE_ARG_FINFO
, &from_finfo
,
3859 FSE_ARG_STRING
, to_len
, to_name
,
3860 FSE_ARG_FINFO
, &to_finfo
,
3863 add_fsevent(FSE_RENAME
, &context
,
3864 FSE_ARG_STRING
, from_len
, from_name
,
3865 FSE_ARG_FINFO
, &from_finfo
,
3866 FSE_ARG_STRING
, to_len
, to_name
,
3870 if (to_name
!= NULL
)
3871 release_pathbuff(to_name
);
3872 if (from_name
!= NULL
)
3873 release_pathbuff(from_name
);
3874 from_name
= to_name
= NULL
;
3877 * update filesystem's mount point data
3880 char *cp
, *pathend
, *mpname
;
3886 mp
= fvp
->v_mountedhere
;
3888 if (vfs_busy(mp
, LK_NOWAIT
)) {
3892 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
3894 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
3896 /* find current mount point prefix */
3897 pathend
= &mp
->mnt_vfsstat
.f_mntonname
[0];
3898 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
3902 /* find last component of target name */
3903 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
3907 /* append name to prefix */
3908 maxlen
= MAXPATHLEN
- (pathend
- mp
->mnt_vfsstat
.f_mntonname
);
3909 bzero(pathend
, maxlen
);
3910 strncpy(pathend
, mpname
, maxlen
- 1);
3912 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
3917 * fix up name & parent pointers. note that we first
3918 * check that fvp has the same name/parent pointers it
3919 * had before the rename call... this is a 'weak' check
3922 if (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
) {
3925 update_flags
= VNODE_UPDATE_NAME
;
3928 update_flags
|= VNODE_UPDATE_PARENT
;
3930 vnode_update_identity(fvp
, tdvp
, tond
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_namelen
, tond
.ni_cnd
.cn_hash
, update_flags
);
3933 if (holding_mntlock
) {
3934 mount_unlock_renames(locked_mp
);
3935 mount_drop(locked_mp
, 0);
3939 * nameidone has to happen before we vnode_put(tdvp)
3940 * since it may need to release the fs_nodelock on the tdvp
3950 * nameidone has to happen before we vnode_put(fdvp)
3951 * since it may need to release the fs_nodelock on the fdvp
3963 * Make a directory file.
3967 mkdir1(vfs_context_t ctx
, user_addr_t path
, struct vnode_attr
*vap
)
3971 int update_flags
= 0;
3972 struct nameidata nd
;
3974 AUDIT_ARG(mode
, vap
->va_mode
);
3975 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
,
3976 UIO_USERSPACE
, path
, ctx
);
3977 nd
.ni_cnd
.cn_flags
|= WILLBEDIR
;
3989 /* authorize addition of a directory to the parent */
3990 if ((error
= vnode_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
)) != 0)
3993 VATTR_SET(vap
, va_type
, VDIR
);
3995 /* make the directory */
3996 if ((error
= vn_create(dvp
, &vp
, &nd
.ni_cnd
, vap
, 0, ctx
)) != 0)
3999 // Make sure the name & parent pointers are hooked up
4000 if (vp
->v_name
== NULL
)
4001 update_flags
|= VNODE_UPDATE_NAME
;
4002 if (vp
->v_parent
== NULLVP
)
4003 update_flags
|= VNODE_UPDATE_PARENT
;
4006 vnode_update_identity(vp
, dvp
, nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, update_flags
);
4008 add_fsevent(FSE_CREATE_DIR
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
4012 * nameidone has to happen before we vnode_put(dvp)
4013 * since it may need to release the fs_nodelock on the dvp
4026 mkdir_extended(struct proc
*p
, register struct mkdir_extended_args
*uap
, __unused register_t
*retval
)
4028 struct vfs_context context
;
4030 kauth_filesec_t xsecdst
;
4031 struct vnode_attr va
;
4034 if ((uap
->xsecurity
!= USER_ADDR_NULL
) &&
4035 ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0))
4038 context
.vc_proc
= p
;
4039 context
.vc_ucred
= kauth_cred_get();
4042 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
4043 if (xsecdst
!= NULL
)
4044 VATTR_SET(&va
, va_acl
, &xsecdst
->fsec_acl
);
4046 ciferror
= mkdir1(&context
, uap
->path
, &va
);
4047 if (xsecdst
!= NULL
)
4048 kauth_filesec_free(xsecdst
);
4053 mkdir(struct proc
*p
, register struct mkdir_args
*uap
, __unused register_t
*retval
)
4055 struct vfs_context context
;
4056 struct vnode_attr va
;
4058 context
.vc_proc
= p
;
4059 context
.vc_ucred
= kauth_cred_get();
4062 VATTR_SET(&va
, va_mode
, (uap
->mode
& ACCESSPERMS
) & ~p
->p_fd
->fd_cmask
);
4064 return(mkdir1(&context
, uap
->path
, &va
));
4068 * Remove a directory file.
4072 rmdir(struct proc
*p
, struct rmdir_args
*uap
, __unused register_t
*retval
)
4076 struct nameidata nd
;
4077 struct vfs_context context
;
4079 context
.vc_proc
= p
;
4080 context
.vc_ucred
= kauth_cred_get();
4082 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
,
4083 UIO_USERSPACE
, uap
->path
, &context
);
4090 if (vp
->v_type
!= VDIR
) {
4092 * rmdir only deals with directories
4095 } else if (dvp
== vp
) {
4097 * No rmdir "." please.
4100 } else if (vp
->v_flag
& VROOT
) {
4102 * The root of a mounted filesystem cannot be deleted.
4106 error
= vnode_authorize(vp
, nd
.ni_dvp
, KAUTH_VNODE_DELETE
, &context
);
4113 if (need_fsevent(FSE_DELETE
, dvp
)) {
4114 path
= get_pathbuff();
4116 vn_getpath(vp
, path
, &len
);
4117 get_fse_info(vp
, &finfo
, &context
);
4119 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, &context
);
4121 if (!error
&& path
!= NULL
) {
4122 add_fsevent(FSE_DELETE
, &context
,
4123 FSE_ARG_STRING
, len
, path
,
4124 FSE_ARG_FINFO
, &finfo
,
4128 release_pathbuff(path
);
4131 * nameidone has to happen before we vnode_put(dvp)
4132 * since it may need to release the fs_nodelock on the dvp
4144 * Read a block of directory entries in a file system independent format.
4147 getdirentries(p
, uap
, retval
)
4149 register struct getdirentries_args
*uap
;
4153 struct vfs_context context
;
4154 struct fileproc
*fp
;
4156 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4160 char uio_buf
[ UIO_SIZEOF(1) ];
4162 AUDIT_ARG(fd
, uap
->fd
);
4163 error
= fp_getfvp(p
, fd
, &fp
, &vp
);
4167 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
4168 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4172 if ( (error
= vnode_getwithref(vp
)) ) {
4176 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4179 if (vp
->v_type
!= VDIR
) {
4180 (void)vnode_put(vp
);
4184 context
.vc_proc
= p
;
4185 context
.vc_ucred
= fp
->f_fglob
->fg_cred
;
4187 loff
= fp
->f_fglob
->fg_offset
;
4188 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
4189 &uio_buf
[0], sizeof(uio_buf
));
4190 uio_addiov(auio
, uap
->buf
, uap
->count
);
4192 error
= VNOP_READDIR(vp
, auio
, 0, &eofflag
, (int *)NULL
, &context
);
4193 fp
->f_fglob
->fg_offset
= uio_offset(auio
);
4195 (void)vnode_put(vp
);
4201 if ((uap
->count
== uio_resid(auio
)) &&
4202 (vp
->v_op
== union_vnodeop_p
)) {
4205 lvp
= union_dircache(vp
, p
);
4206 if (lvp
!= NULLVP
) {
4207 struct vnode_attr va
;
4209 * If the directory is opaque,
4210 * then don't show lower entries
4213 VATTR_WANTED(&va
, va_flags
);
4214 error
= vnode_getattr(vp
, &va
, &context
);
4215 if (va
.va_flags
& OPAQUE
) {
4221 if (lvp
!= NULLVP
) {
4222 error
= VNOP_OPEN(lvp
, FREAD
, &context
);
4228 fp
->f_fglob
->fg_data
= (caddr_t
) lvp
;
4229 fp
->f_fglob
->fg_offset
= 0;
4230 error
= VNOP_CLOSE(vp
, FREAD
, &context
);
4242 if (((user_ssize_t
)uap
->count
== uio_resid(auio
)) &&
4243 (vp
->v_flag
& VROOT
) &&
4244 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
4245 struct vnode
*tvp
= vp
;
4246 vp
= vp
->v_mount
->mnt_vnodecovered
;
4247 vnode_getwithref(vp
);
4249 fp
->f_fglob
->fg_data
= (caddr_t
) vp
;
4250 fp
->f_fglob
->fg_offset
= 0;
4256 error
= copyout((caddr_t
)&loff
, uap
->basep
, sizeof(long));
4257 // LP64todo - fix this
4258 *retval
= uap
->count
- uio_resid(auio
);
4265 * Set the mode mask for creation of filesystem nodes.
4267 #warning XXX implement xsecurity
4269 #define UMASK_NOXSECURITY (void *)1 /* leave existing xsecurity alone */
4271 umask1(struct proc
*p
, int newmask
, __unused kauth_filesec_t fsec
, register_t
*retval
)
4273 register struct filedesc
*fdp
;
4275 AUDIT_ARG(mask
, newmask
);
4277 *retval
= fdp
->fd_cmask
;
4278 fdp
->fd_cmask
= newmask
& ALLPERMS
;
4284 umask_extended(struct proc
*p
, struct umask_extended_args
*uap
, register_t
*retval
)
4287 kauth_filesec_t xsecdst
;
4289 xsecdst
= KAUTH_FILESEC_NONE
;
4290 if (uap
->xsecurity
!= USER_ADDR_NULL
) {
4291 if ((ciferror
= kauth_copyinfilesec(uap
->xsecurity
, &xsecdst
)) != 0)
4294 xsecdst
= KAUTH_FILESEC_NONE
;
4297 ciferror
= umask1(p
, uap
->newmask
, xsecdst
, retval
);
4299 if (xsecdst
!= KAUTH_FILESEC_NONE
)
4300 kauth_filesec_free(xsecdst
);
4305 umask(struct proc
*p
, struct umask_args
*uap
, register_t
*retval
)
4307 return(umask1(p
, uap
->newmask
, UMASK_NOXSECURITY
, retval
));
4311 * Void all references to file by ripping underlying filesystem
4316 revoke(struct proc
*p
, register struct revoke_args
*uap
, __unused register_t
*retval
)
4318 register struct vnode
*vp
;
4319 struct vnode_attr va
;
4320 struct vfs_context context
;
4322 struct nameidata nd
;
4324 context
.vc_proc
= p
;
4325 context
.vc_ucred
= kauth_cred_get();
4327 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
,
4328 UIO_USERSPACE
, uap
->path
, &context
);
4337 VATTR_WANTED(&va
, va_uid
);
4338 if ((error
= vnode_getattr(vp
, &va
, &context
)))
4340 if (kauth_cred_getuid(context
.vc_ucred
) != va
.va_uid
&&
4341 (error
= suser(context
.vc_ucred
, &p
->p_acflag
)))
4343 if (vp
->v_usecount
> 1 || (vp
->v_flag
& VALIASED
))
4344 VNOP_REVOKE(vp
, REVOKEALL
, &context
);
4352 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
4353 * The following system calls are designed to support features
4354 * which are specific to the HFS & HFS Plus volume formats
4357 #ifdef __APPLE_API_OBSOLETE
4359 /************************************************/
4360 /* *** Following calls will be deleted soon *** */
4361 /************************************************/
4364 * Make a complex file. A complex file is one with multiple forks (data streams)
4368 mkcomplex(__unused
struct proc
*p
, __unused
struct mkcomplex_args
*uap
, __unused register_t
*retval
)
4374 * Extended stat call which returns volumeid and vnodeid as well as other info
4378 statv(__unused
struct proc
*p
,
4379 __unused
struct statv_args
*uap
,
4380 __unused register_t
*retval
)
4382 return (ENOTSUP
); /* We'll just return an error for now */
4384 } /* end of statv system call */
4387 * Extended lstat call which returns volumeid and vnodeid as well as other info
4391 lstatv(__unused
struct proc
*p
,
4392 __unused
struct lstatv_args
*uap
,
4393 __unused register_t
*retval
)
4395 return (ENOTSUP
); /* We'll just return an error for now */
4396 } /* end of lstatv system call */
4399 * Extended fstat call which returns volumeid and vnodeid as well as other info
4403 fstatv(__unused
struct proc
*p
,
4404 __unused
struct fstatv_args
*uap
,
4405 __unused register_t
*retval
)
4407 return (ENOTSUP
); /* We'll just return an error for now */
4408 } /* end of fstatv system call */
4411 /************************************************/
4412 /* *** Preceding calls will be deleted soon *** */
4413 /************************************************/
4415 #endif /* __APPLE_API_OBSOLETE */
4418 * Obtain attribute information on objects in a directory while enumerating
4419 * the directory. This call does not yet support union mounted directories.
4421 * 1.union mounted directories.
4426 getdirentriesattr (struct proc
*p
, struct getdirentriesattr_args
*uap
, register_t
*retval
)
4429 struct fileproc
*fp
;
4431 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4432 uint64_t actualcount
;
4437 struct attrlist attributelist
;
4438 struct vfs_context context
;
4440 char uio_buf
[ UIO_SIZEOF(1) ];
4441 kauth_action_t action
;
4445 /* Get the attributes into kernel space */
4446 if ((error
= copyin(uap
->alist
, (caddr_t
) &attributelist
, sizeof (attributelist
))))
4448 actualcount
= fuulong(uap
->count
);
4449 if (actualcount
== -1ULL)
4452 if ( (error
= fp_getfvp(p
, fd
, &fp
, &vp
)) )
4455 if ((fp
->f_fglob
->fg_flag
& FREAD
) == 0) {
4456 AUDIT_ARG(vnpath_withref
, vp
, ARG_VNODE1
);
4460 if ( (error
= vnode_getwithref(vp
)) )
4463 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
4465 if (vp
->v_type
!= VDIR
) {
4466 (void)vnode_put(vp
);
4471 /* set up the uio structure which will contain the users return buffer */
4472 loff
= fp
->f_fglob
->fg_offset
;
4473 auio
= uio_createwithbuffer(1, loff
, spacetype
, UIO_READ
,
4474 &uio_buf
[0], sizeof(uio_buf
));
4475 uio_addiov(auio
, uap
->buffer
, uap
->buffersize
);
4477 context
.vc_proc
= p
;
4478 context
.vc_ucred
= kauth_cred_get();
4479 tmpcount
= (u_long
) actualcount
;
4482 * If the only item requested is file names, we can let that past with
4483 * just LIST_DIRECTORY. If they want any other attributes, that means
4484 * they need SEARCH as well.
4486 action
= KAUTH_VNODE_LIST_DIRECTORY
;
4487 if ((attributelist
.commonattr
& ~ATTR_CMN_NAME
) ||
4488 attributelist
.fileattr
|| attributelist
.dirattr
)
4489 action
|= KAUTH_VNODE_SEARCH
;
4491 if ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) == 0)
4492 error
= VNOP_READDIRATTR(vp
, &attributelist
, auio
,
4493 tmpcount
, uap
->options
, &newstate
, &eofflag
,
4494 &tmpcount
, &context
);
4495 (void)vnode_put(vp
);
4496 actualcount
= tmpcount
;
4500 fp
->f_fglob
->fg_offset
= uio_offset(auio
); /* should be multiple of dirent, not variable */
4502 if ((error
= suulong(uap
->count
, actualcount
)) != 0)
4504 if ((error
= suulong(uap
->newstate
, (uint64_t)newstate
)) != 0)
4506 if ((error
= suulong(uap
->basep
, (uint64_t)loff
)) != 0)
4509 *retval
= eofflag
; /* similar to getdirentries */
4513 return (error
); /* return error earlier, an retval of 0 or 1 now */
4515 } /* end of getdirentryattr system call */
4518 * Exchange data between two files
4523 exchangedata (struct proc
*p
, register struct exchangedata_args
*uap
, __unused register_t
*retval
)
4526 struct nameidata fnd
, snd
;
4527 struct vfs_context context
;
4528 struct vnode
*fvp
, *svp
;
4534 fse_info f_finfo
, s_finfo
;
4536 context
.vc_proc
= p
;
4537 context
.vc_ucred
= kauth_cred_get();
4540 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4542 NDINIT(&fnd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4543 UIO_USERSPACE
, uap
->path1
, &context
);
4545 error
= namei(&fnd
);
4552 NDINIT(&snd
, LOOKUP
, nameiflags
| AUDITVNPATH2
,
4553 UIO_USERSPACE
, uap
->path2
, &context
);
4555 error
= namei(&snd
);
4564 * if the files are the same, return an inval error
4572 * if the files are on different volumes, return an error
4574 if (svp
->v_mount
!= fvp
->v_mount
) {
4578 if (((error
= vnode_authorize(fvp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0) ||
4579 ((error
= vnode_authorize(svp
, NULL
, KAUTH_VNODE_READ_DATA
| KAUTH_VNODE_WRITE_DATA
, &context
)) != 0))
4582 if (need_fsevent(FSE_EXCHANGE
, fvp
) || kauth_authorize_fileop_has_listeners()) {
4583 fpath
= get_pathbuff();
4584 spath
= get_pathbuff();
4587 if (vn_getpath(fvp
, fpath
, &flen
) != 0 || fpath
[0] == '\0') {
4588 printf("exchange: vn_getpath(fvp=0x%x) failed <<%s>>\n",
4591 if (vn_getpath(svp
, spath
, &slen
) != 0 || spath
[0] == '\0') {
4592 printf("exchange: vn_getpath(svp=0x%x) failed <<%s>>\n",
4595 get_fse_info(fvp
, &f_finfo
, &context
);
4596 get_fse_info(svp
, &s_finfo
, &context
);
4598 /* Ok, make the call */
4599 error
= VNOP_EXCHANGE(fvp
, svp
, 0, &context
);
4604 if (fpath
!= NULL
&& spath
!= NULL
) {
4605 /* call out to allow 3rd party notification of exchangedata.
4606 * Ignore result of kauth_authorize_fileop call.
4608 kauth_authorize_fileop(vfs_context_ucred(&context
), KAUTH_FILEOP_EXCHANGE
,
4609 (uintptr_t)fpath
, (uintptr_t)spath
);
4613 tmpname
= fvp
->v_name
;
4614 fvp
->v_name
= svp
->v_name
;
4615 svp
->v_name
= tmpname
;
4617 if (fvp
->v_parent
!= svp
->v_parent
) {
4620 tmp
= fvp
->v_parent
;
4621 fvp
->v_parent
= svp
->v_parent
;
4622 svp
->v_parent
= tmp
;
4624 name_cache_unlock();
4626 if (fpath
!= NULL
&& spath
!= NULL
) {
4627 add_fsevent(FSE_EXCHANGE
, &context
,
4628 FSE_ARG_STRING
, flen
, fpath
,
4629 FSE_ARG_FINFO
, &f_finfo
,
4630 FSE_ARG_STRING
, slen
, spath
,
4631 FSE_ARG_FINFO
, &s_finfo
,
4636 release_pathbuff(spath
);
4638 release_pathbuff(fpath
);
4648 #ifdef __APPLE_API_OBSOLETE
4650 /************************************************/
4651 /* *** Following calls will be deleted soon *** */
4652 /************************************************/
4655 * Check users access to a file
4659 #warning "checkuseraccess copies a cred in from user space but"
4660 #warning "user space has no way of knowing what one looks like"
4661 #warning "this code should use the access_extended spoof-as functionality"
4663 checkuseraccess (struct proc
*p
, register struct checkuseraccess_args
*uap
, __unused register_t
*retval
)
4665 register struct vnode
*vp
;
4667 struct nameidata nd
;
4668 struct ucred cred
; /* XXX ILLEGAL */
4669 int flags
; /*what will actually get passed to access*/
4671 struct vfs_context context
;
4673 /* Make sure that the number of groups is correct before we do anything */
4675 if ((uap
->ngroups
<= 0) || (uap
->ngroups
> NGROUPS
))
4678 /* Verify that the caller is root */
4680 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
)))
4683 /* Fill in the credential structure */
4686 cred
.cr_uid
= uap
->userid
;
4687 cred
.cr_ngroups
= uap
->ngroups
;
4688 if ((error
= copyin(CAST_USER_ADDR_T(uap
->groups
), (caddr_t
) &(cred
.cr_groups
), (sizeof(gid_t
))*uap
->ngroups
)))
4691 context
.vc_proc
= p
;
4692 context
.vc_ucred
= &cred
;
4694 /* Get our hands on the file */
4696 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4697 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4698 UIO_USERSPACE
, CAST_USER_ADDR_T(uap
->path
), &context
);
4700 if ((error
= namei(&nd
)))
4705 /* Flags == 0 means only check for existence. */
4709 if (uap
->accessrequired
) {
4710 if (uap
->accessrequired
& R_OK
)
4711 flags
|= KAUTH_VNODE_READ_DATA
;
4712 if (uap
->accessrequired
& W_OK
)
4713 flags
|= KAUTH_VNODE_WRITE_DATA
;
4714 if (uap
->accessrequired
& X_OK
)
4715 flags
|= KAUTH_VNODE_EXECUTE
;
4717 error
= vnode_authorize(vp
, NULL
, flags
, &context
);
4726 } /* end of checkuseraccess system call */
4728 /************************************************/
4729 /* *** Preceding calls will be deleted soon *** */
4730 /************************************************/
4732 #endif /* __APPLE_API_OBSOLETE */
4739 searchfs (struct proc
*p
, register struct searchfs_args
*uap
, __unused register_t
*retval
)
4741 register struct vnode
*vp
;
4744 struct nameidata nd
;
4745 struct user_fssearchblock searchblock
;
4746 struct searchstate
*state
;
4747 struct attrlist
*returnattrs
;
4748 void *searchparams1
,*searchparams2
;
4750 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
4754 struct vfs_context context
;
4755 char uio_buf
[ UIO_SIZEOF(1) ];
4757 context
.vc_proc
= p
;
4758 context
.vc_ucred
= kauth_cred_get();
4760 /* Start by copying in fsearchblock paramater list */
4761 if (IS_64BIT_PROCESS(p
)) {
4762 error
= copyin(uap
->searchblock
, (caddr_t
) &searchblock
, sizeof(searchblock
));
4765 struct fssearchblock tmp_searchblock
;
4766 error
= copyin(uap
->searchblock
, (caddr_t
) &tmp_searchblock
, sizeof(tmp_searchblock
));
4767 // munge into 64-bit version
4768 searchblock
.returnattrs
= CAST_USER_ADDR_T(tmp_searchblock
.returnattrs
);
4769 searchblock
.returnbuffer
= CAST_USER_ADDR_T(tmp_searchblock
.returnbuffer
);
4770 searchblock
.returnbuffersize
= tmp_searchblock
.returnbuffersize
;
4771 searchblock
.maxmatches
= tmp_searchblock
.maxmatches
;
4772 searchblock
.timelimit
.tv_sec
= tmp_searchblock
.timelimit
.tv_sec
;
4773 searchblock
.timelimit
.tv_usec
= tmp_searchblock
.timelimit
.tv_usec
;
4774 searchblock
.searchparams1
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams1
);
4775 searchblock
.sizeofsearchparams1
= tmp_searchblock
.sizeofsearchparams1
;
4776 searchblock
.searchparams2
= CAST_USER_ADDR_T(tmp_searchblock
.searchparams2
);
4777 searchblock
.sizeofsearchparams2
= tmp_searchblock
.sizeofsearchparams2
;
4778 searchblock
.searchattrs
= tmp_searchblock
.searchattrs
;
4783 /* Do a sanity check on sizeofsearchparams1 and sizeofsearchparams2.
4785 if (searchblock
.sizeofsearchparams1
> SEARCHFS_MAX_SEARCHPARMS
||
4786 searchblock
.sizeofsearchparams2
> SEARCHFS_MAX_SEARCHPARMS
)
4789 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
4790 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
4791 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
4794 mallocsize
= searchblock
.sizeofsearchparams1
+ searchblock
.sizeofsearchparams2
+
4795 sizeof(struct attrlist
) + sizeof(struct searchstate
);
4797 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
4799 /* Now set up the various pointers to the correct place in our newly allocated memory */
4801 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
4802 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
4803 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
4805 /* Now copy in the stuff given our local variables. */
4807 if ((error
= copyin(searchblock
.searchparams1
, searchparams1
, searchblock
.sizeofsearchparams1
)))
4810 if ((error
= copyin(searchblock
.searchparams2
, searchparams2
, searchblock
.sizeofsearchparams2
)))
4813 if ((error
= copyin(searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
))))
4816 if ((error
= copyin(uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
))))
4819 /* set up the uio structure which will contain the users return buffer */
4821 auio
= uio_createwithbuffer(1, 0, spacetype
, UIO_READ
,
4822 &uio_buf
[0], sizeof(uio_buf
));
4823 uio_addiov(auio
, searchblock
.returnbuffer
, searchblock
.returnbuffersize
);
4826 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4827 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
,
4828 UIO_USERSPACE
, uap
->path
, &context
);
4839 * If searchblock.maxmatches == 0, then skip the search. This has happened
4840 * before and sometimes the underlyning code doesnt deal with it well.
4842 if (searchblock
.maxmatches
== 0) {
4848 Allright, we have everything we need, so lets make that call.
4850 We keep special track of the return value from the file system:
4851 EAGAIN is an acceptable error condition that shouldn't keep us
4852 from copying out any results...
4855 fserror
= VNOP_SEARCHFS(vp
,
4858 &searchblock
.searchattrs
,
4859 searchblock
.maxmatches
,
4860 &searchblock
.timelimit
,
4873 /* Now copy out the stuff that needs copying out. That means the number of matches, the
4874 search state. Everything was already put into he return buffer by the vop call. */
4876 if ((error
= copyout((caddr_t
) state
, uap
->state
, sizeof(struct searchstate
))) != 0)
4879 if ((error
= suulong(uap
->nummatches
, (uint64_t)nummatches
)) != 0)
4886 FREE(searchparams1
,M_TEMP
);
4891 } /* end of searchfs system call */
4895 * Make a filesystem-specific control call:
4899 fsctl (struct proc
*p
, struct fsctl_args
*uap
, __unused register_t
*retval
)
4903 struct nameidata nd
;
4905 u_long cmd
= uap
->cmd
;
4906 register u_int size
;
4907 #define STK_PARAMS 128
4908 char stkbuf
[STK_PARAMS
];
4910 struct vfs_context context
;
4912 context
.vc_proc
= p
;
4913 context
.vc_ucred
= kauth_cred_get();
4915 size
= IOCPARM_LEN(cmd
);
4916 if (size
> IOCPARM_MAX
) return (EINVAL
);
4918 is64bit
= proc_is64bit(p
);
4921 if (size
> sizeof (stkbuf
)) {
4922 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
4930 error
= copyin(uap
->data
, data
, size
);
4931 if (error
) goto FSCtl_Exit
;
4934 *(user_addr_t
*)data
= uap
->data
;
4937 *(uint32_t *)data
= (uint32_t)uap
->data
;
4940 } else if ((cmd
& IOC_OUT
) && size
) {
4942 * Zero the buffer so the user always
4943 * gets back something deterministic.
4946 } else if (cmd
& IOC_VOID
) {
4948 *(user_addr_t
*)data
= uap
->data
;
4951 *(uint32_t *)data
= (uint32_t)uap
->data
;
4955 /* Get the vnode for the file we are getting info on: */
4957 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4958 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, uap
->path
, &context
);
4959 if ((error
= namei(&nd
))) goto FSCtl_Exit
;
4961 /* Invoke the filesystem-specific code */
4962 error
= VNOP_IOCTL(nd
.ni_vp
, IOCBASECMD(cmd
), data
, uap
->options
, &context
);
4964 vnode_put(nd
.ni_vp
);
4968 * Copy any data to user, size was
4969 * already set and checked above.
4971 if (error
== 0 && (cmd
& IOC_OUT
) && size
)
4972 error
= copyout(data
, uap
->data
, size
);
4975 if (memp
) kfree(memp
, size
);
4979 /* end of fsctl system call */
4982 * An in-kernel sync for power management to call.
4984 __private_extern__
int
4989 struct sync_args data
;
4994 error
= sync(current_proc(), &data
, &retval
[0]);
4998 } /* end of sync_internal call */
5002 * Retrieve the data of an extended attribute.
5005 getxattr(struct proc
*p
, struct getxattr_args
*uap
, user_ssize_t
*retval
)
5008 struct nameidata nd
;
5009 char attrname
[XATTR_MAXNAMELEN
+1];
5010 struct vfs_context context
;
5012 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5013 size_t attrsize
= 0;
5017 char uio_buf
[ UIO_SIZEOF(1) ];
5019 context
.vc_proc
= p
;
5020 context
.vc_ucred
= kauth_cred_get();
5022 if (uap
->options
& XATTR_NOSECURITY
)
5025 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5026 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5027 if ((error
= namei(&nd
))) {
5033 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5036 if (xattr_protected(attrname
)) {
5040 if (uap
->value
&& uap
->size
> 0) {
5041 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
5042 &uio_buf
[0], sizeof(uio_buf
));
5043 uio_addiov(auio
, uap
->value
, uap
->size
);
5046 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, &context
);
5051 *retval
= uap
->size
- uio_resid(auio
);
5053 *retval
= (user_ssize_t
)attrsize
;
5060 * Retrieve the data of an extended attribute.
5063 fgetxattr(struct proc
*p
, struct fgetxattr_args
*uap
, user_ssize_t
*retval
)
5066 char attrname
[XATTR_MAXNAMELEN
+1];
5067 struct vfs_context context
;
5069 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5070 size_t attrsize
= 0;
5073 char uio_buf
[ UIO_SIZEOF(1) ];
5075 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5078 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5081 if ( (error
= vnode_getwithref(vp
)) ) {
5085 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5088 if (xattr_protected(attrname
)) {
5092 if (uap
->value
&& uap
->size
> 0) {
5093 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_READ
,
5094 &uio_buf
[0], sizeof(uio_buf
));
5095 uio_addiov(auio
, uap
->value
, uap
->size
);
5097 context
.vc_proc
= p
;
5098 context
.vc_ucred
= kauth_cred_get();
5100 error
= vn_getxattr(vp
, attrname
, auio
, &attrsize
, uap
->options
, &context
);
5102 (void)vnode_put(vp
);
5106 *retval
= uap
->size
- uio_resid(auio
);
5108 *retval
= (user_ssize_t
)attrsize
;
5114 * Set the data of an extended attribute.
5117 setxattr(struct proc
*p
, struct setxattr_args
*uap
, int *retval
)
5120 struct nameidata nd
;
5121 char attrname
[XATTR_MAXNAMELEN
+1];
5122 struct vfs_context context
;
5124 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5128 char uio_buf
[ UIO_SIZEOF(1) ];
5130 context
.vc_proc
= p
;
5131 context
.vc_ucred
= kauth_cred_get();
5133 if (uap
->options
& XATTR_NOSECURITY
)
5136 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5139 if (xattr_protected(attrname
))
5141 if (uap
->value
== 0 || uap
->size
== 0) {
5145 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5146 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5147 if ((error
= namei(&nd
))) {
5153 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
5154 &uio_buf
[0], sizeof(uio_buf
));
5155 uio_addiov(auio
, uap
->value
, uap
->size
);
5157 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, &context
);
5164 * Set the data of an extended attribute.
5167 fsetxattr(struct proc
*p
, struct fsetxattr_args
*uap
, int *retval
)
5170 char attrname
[XATTR_MAXNAMELEN
+1];
5171 struct vfs_context context
;
5173 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5176 char uio_buf
[ UIO_SIZEOF(1) ];
5178 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5181 if ((error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
) != 0)) {
5184 if (xattr_protected(attrname
))
5186 if (uap
->value
== 0 || uap
->size
== 0) {
5189 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5192 if ( (error
= vnode_getwithref(vp
)) ) {
5196 auio
= uio_createwithbuffer(1, uap
->position
, spacetype
, UIO_WRITE
,
5197 &uio_buf
[0], sizeof(uio_buf
));
5198 uio_addiov(auio
, uap
->value
, uap
->size
);
5199 context
.vc_proc
= p
;
5200 context
.vc_ucred
= kauth_cred_get();
5202 error
= vn_setxattr(vp
, attrname
, auio
, uap
->options
, &context
);
5210 * Remove an extended attribute.
5212 #warning "code duplication"
5214 removexattr(struct proc
*p
, struct removexattr_args
*uap
, int *retval
)
5217 struct nameidata nd
;
5218 char attrname
[XATTR_MAXNAMELEN
+1];
5219 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5220 struct vfs_context context
;
5225 context
.vc_proc
= p
;
5226 context
.vc_ucred
= kauth_cred_get();
5228 if (uap
->options
& XATTR_NOSECURITY
)
5231 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
5235 if (xattr_protected(attrname
))
5237 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5238 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5239 if ((error
= namei(&nd
))) {
5245 error
= vn_removexattr(vp
, attrname
, uap
->options
, &context
);
5252 * Remove an extended attribute.
5254 #warning "code duplication"
5256 fremovexattr(struct proc
*p
, struct fremovexattr_args
*uap
, int *retval
)
5259 char attrname
[XATTR_MAXNAMELEN
+1];
5260 struct vfs_context context
;
5264 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5267 error
= copyinstr(uap
->attrname
, attrname
, sizeof(attrname
), &namelen
);
5271 if (xattr_protected(attrname
))
5273 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5276 if ( (error
= vnode_getwithref(vp
)) ) {
5280 context
.vc_proc
= p
;
5281 context
.vc_ucred
= kauth_cred_get();
5283 error
= vn_removexattr(vp
, attrname
, uap
->options
, &context
);
5291 * Retrieve the list of extended attribute names.
5293 #warning "code duplication"
5295 listxattr(struct proc
*p
, struct listxattr_args
*uap
, user_ssize_t
*retval
)
5298 struct nameidata nd
;
5299 struct vfs_context context
;
5301 int spacetype
= IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5302 size_t attrsize
= 0;
5305 char uio_buf
[ UIO_SIZEOF(1) ];
5307 context
.vc_proc
= p
;
5308 context
.vc_ucred
= kauth_cred_get();
5310 if (uap
->options
& XATTR_NOSECURITY
)
5313 nameiflags
= (uap
->options
& XATTR_NOFOLLOW
) ? 0 : FOLLOW
;
5314 NDINIT(&nd
, LOOKUP
, nameiflags
, spacetype
, uap
->path
, &context
);
5315 if ((error
= namei(&nd
))) {
5320 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
5321 // LP64todo - fix this!
5322 auio
= uio_createwithbuffer(1, 0, spacetype
,
5323 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
5324 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
5327 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, &context
);
5331 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
5333 *retval
= (user_ssize_t
)attrsize
;
5339 * Retrieve the list of extended attribute names.
5341 #warning "code duplication"
5343 flistxattr(struct proc
*p
, struct flistxattr_args
*uap
, user_ssize_t
*retval
)
5346 struct vfs_context context
;
5348 int spacetype
= proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
;
5349 size_t attrsize
= 0;
5351 char uio_buf
[ UIO_SIZEOF(1) ];
5353 if (uap
->options
& (XATTR_NOFOLLOW
| XATTR_NOSECURITY
))
5356 if ( (error
= file_vnode(uap
->fd
, &vp
)) ) {
5359 if ( (error
= vnode_getwithref(vp
)) ) {
5363 if (uap
->namebuf
!= 0 && uap
->bufsize
> 0) {
5364 // LP64todo - fix this!
5365 auio
= uio_createwithbuffer(1, 0, spacetype
,
5366 UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
5367 uio_addiov(auio
, uap
->namebuf
, uap
->bufsize
);
5369 context
.vc_proc
= p
;
5370 context
.vc_ucred
= kauth_cred_get();
5372 error
= vn_listxattr(vp
, auio
, &attrsize
, uap
->options
, &context
);
5377 *retval
= (user_ssize_t
)uap
->bufsize
- uio_resid(auio
);
5379 *retval
= (user_ssize_t
)attrsize
;
5385 * Common routine to handle various flavors of statfs data heading out
5389 munge_statfs(struct mount
*mp
, struct vfsstatfs
*sfsp
,
5390 user_addr_t bufp
, int *sizep
, boolean_t is_64_bit
,
5391 boolean_t partial_copy
)
5394 int my_size
, copy_size
;
5397 struct user_statfs sfs
;
5398 my_size
= copy_size
= sizeof(sfs
);
5399 bzero(&sfs
, my_size
);
5400 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
5401 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
5402 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
5403 sfs
.f_bsize
= (user_long_t
)sfsp
->f_bsize
;
5404 sfs
.f_iosize
= (user_long_t
)sfsp
->f_iosize
;
5405 sfs
.f_blocks
= (user_long_t
)sfsp
->f_blocks
;
5406 sfs
.f_bfree
= (user_long_t
)sfsp
->f_bfree
;
5407 sfs
.f_bavail
= (user_long_t
)sfsp
->f_bavail
;
5408 sfs
.f_files
= (user_long_t
)sfsp
->f_files
;
5409 sfs
.f_ffree
= (user_long_t
)sfsp
->f_ffree
;
5410 sfs
.f_fsid
= sfsp
->f_fsid
;
5411 sfs
.f_owner
= sfsp
->f_owner
;
5412 strncpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
-1);
5413 strncpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
-1);
5414 strncpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
-1);
5417 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
5419 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
5423 my_size
= copy_size
= sizeof(sfs
);
5424 bzero(&sfs
, my_size
);
5426 sfs
.f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
5427 sfs
.f_type
= mp
->mnt_vtable
->vfc_typenum
;
5428 sfs
.f_reserved1
= (short)sfsp
->f_fssubtype
;
5431 * It's possible for there to be more than 2^^31 blocks in the filesystem, so we
5432 * have to fudge the numbers here in that case. We inflate the blocksize in order
5433 * to reflect the filesystem size as best we can.
5435 if ((sfsp
->f_blocks
> LONG_MAX
)
5436 /* Hack for 4061702 . I think the real fix is for Carbon to
5437 * look for some volume capability and not depend on hidden
5438 * semantics agreed between a FS and carbon.
5439 * f_blocks, f_bfree, and f_bavail set to -1 is the trigger
5440 * for Carbon to set bNoVolumeSizes volume attribute.
5441 * Without this the webdavfs files cannot be copied onto
5442 * disk as they look huge. This change should not affect
5443 * XSAN as they should not setting these to -1..
5445 && (sfsp
->f_blocks
!= 0xffffffffffffffff)
5446 && (sfsp
->f_bfree
!= 0xffffffffffffffff)
5447 && (sfsp
->f_bavail
!= 0xffffffffffffffff)) {
5451 * Work out how far we have to shift the block count down to make it fit.
5452 * Note that it's possible to have to shift so far that the resulting
5453 * blocksize would be unreportably large. At that point, we will clip
5454 * any values that don't fit.
5456 * For safety's sake, we also ensure that f_iosize is never reported as
5457 * being smaller than f_bsize.
5459 for (shift
= 0; shift
< 32; shift
++) {
5460 if ((sfsp
->f_blocks
>> shift
) <= LONG_MAX
)
5462 if ((sfsp
->f_bsize
<< (shift
+ 1)) > LONG_MAX
)
5465 #define __SHIFT_OR_CLIP(x, s) ((((x) >> (s)) > LONG_MAX) ? LONG_MAX : ((x) >> (s)))
5466 sfs
.f_blocks
= (long)__SHIFT_OR_CLIP(sfsp
->f_blocks
, shift
);
5467 sfs
.f_bfree
= (long)__SHIFT_OR_CLIP(sfsp
->f_bfree
, shift
);
5468 sfs
.f_bavail
= (long)__SHIFT_OR_CLIP(sfsp
->f_bavail
, shift
);
5469 #undef __SHIFT_OR_CLIP
5470 sfs
.f_bsize
= (long)(sfsp
->f_bsize
<< shift
);
5471 sfs
.f_iosize
= lmax(sfsp
->f_iosize
, sfsp
->f_bsize
);
5473 /* filesystem is small enough to be reported honestly */
5474 sfs
.f_bsize
= (long)sfsp
->f_bsize
;
5475 sfs
.f_iosize
= (long)sfsp
->f_iosize
;
5476 sfs
.f_blocks
= (long)sfsp
->f_blocks
;
5477 sfs
.f_bfree
= (long)sfsp
->f_bfree
;
5478 sfs
.f_bavail
= (long)sfsp
->f_bavail
;
5480 sfs
.f_files
= (long)sfsp
->f_files
;
5481 sfs
.f_ffree
= (long)sfsp
->f_ffree
;
5482 sfs
.f_fsid
= sfsp
->f_fsid
;
5483 sfs
.f_owner
= sfsp
->f_owner
;
5484 strncpy(&sfs
.f_fstypename
[0], &sfsp
->f_fstypename
[0], MFSNAMELEN
-1);
5485 strncpy(&sfs
.f_mntonname
[0], &sfsp
->f_mntonname
[0], MNAMELEN
-1);
5486 strncpy(&sfs
.f_mntfromname
[0], &sfsp
->f_mntfromname
[0], MNAMELEN
-1);
5489 copy_size
-= (sizeof(sfs
.f_reserved3
) + sizeof(sfs
.f_reserved4
));
5491 error
= copyout((caddr_t
)&sfs
, bufp
, copy_size
);
5494 if (sizep
!= NULL
) {
5501 * copy stat structure into user_stat structure.
5503 void munge_stat(struct stat
*sbp
, struct user_stat
*usbp
)
5505 bzero(usbp
, sizeof(struct user_stat
));
5507 usbp
->st_dev
= sbp
->st_dev
;
5508 usbp
->st_ino
= sbp
->st_ino
;
5509 usbp
->st_mode
= sbp
->st_mode
;
5510 usbp
->st_nlink
= sbp
->st_nlink
;
5511 usbp
->st_uid
= sbp
->st_uid
;
5512 usbp
->st_gid
= sbp
->st_gid
;
5513 usbp
->st_rdev
= sbp
->st_rdev
;
5514 #ifndef _POSIX_SOURCE
5515 usbp
->st_atimespec
.tv_sec
= sbp
->st_atimespec
.tv_sec
;
5516 usbp
->st_atimespec
.tv_nsec
= sbp
->st_atimespec
.tv_nsec
;
5517 usbp
->st_mtimespec
.tv_sec
= sbp
->st_mtimespec
.tv_sec
;
5518 usbp
->st_mtimespec
.tv_nsec
= sbp
->st_mtimespec
.tv_nsec
;
5519 usbp
->st_ctimespec
.tv_sec
= sbp
->st_ctimespec
.tv_sec
;
5520 usbp
->st_ctimespec
.tv_nsec
= sbp
->st_ctimespec
.tv_nsec
;
5522 usbp
->st_atime
= sbp
->st_atime
;
5523 usbp
->st_atimensec
= sbp
->st_atimensec
;
5524 usbp
->st_mtime
= sbp
->st_mtime
;
5525 usbp
->st_mtimensec
= sbp
->st_mtimensec
;
5526 usbp
->st_ctime
= sbp
->st_ctime
;
5527 usbp
->st_ctimensec
= sbp
->st_ctimensec
;
5529 usbp
->st_size
= sbp
->st_size
;
5530 usbp
->st_blocks
= sbp
->st_blocks
;
5531 usbp
->st_blksize
= sbp
->st_blksize
;
5532 usbp
->st_flags
= sbp
->st_flags
;
5533 usbp
->st_gen
= sbp
->st_gen
;
5534 usbp
->st_lspare
= sbp
->st_lspare
;
5535 usbp
->st_qspare
[0] = sbp
->st_qspare
[0];
5536 usbp
->st_qspare
[1] = sbp
->st_qspare
[1];