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];