]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/vfs/kpi_vfs.c
xnu-4570.20.62.tar.gz
[apple/xnu.git] / bsd / vfs / kpi_vfs.c
index 1a71f6b69b1a943c425e4d5051a839ab44598cda..060866928d0df6558df03a3413c98da2436376f6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2014 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2017 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -138,6 +138,8 @@ static void xattrfile_setattr(vnode_t dvp, const char * basename,
                                struct vnode_attr * vap, vfs_context_t ctx);
 #endif /* CONFIG_APPLEDOUBLE */
 
+static errno_t post_rename(vnode_t fdvp, vnode_t fvp, vnode_t tdvp, vnode_t tvp);
+
 /*
  * vnode_setneedinactive
  *
@@ -233,7 +235,7 @@ VFS_UNMOUNT(mount_t mp, int flags, vfs_context_t ctx)
  *
  *             The return codes documented above are those which may currently
  *             be returned by HFS from hfs_vfs_root, which is a simple wrapper
- *             for a call to hfs_vget on the volume mount poit, not including
+ *             for a call to hfs_vget on the volume mount point, not including
  *             additional error codes which may be propagated from underlying
  *             routines called by hfs_vget.
  */
@@ -336,7 +338,7 @@ VFS_VGET(mount_t mp, ino64_t ino, struct vnode **vpp, vfs_context_t ctx)
 }
 
 int 
-VFS_FHTOVP(mount_t mp, int fhlen, unsigned char * fhp, vnode_t * vpp, vfs_context_t ctx) 
+VFS_FHTOVP(mount_t mp, int fhlen, unsigned char *fhp, vnode_t *vpp, vfs_context_t ctx) 
 {
        int error;
 
@@ -353,7 +355,7 @@ VFS_FHTOVP(mount_t mp, int fhlen, unsigned char * fhp, vnode_t * vpp, vfs_contex
 }
 
 int 
-VFS_VPTOFH(struct vnode * vp, int *fhlenp, unsigned char * fhp, vfs_context_t ctx)
+VFS_VPTOFH(struct vnode *vp, int *fhlenp, unsigned char *fhp, vfs_context_t ctx)
 {
        int error;
 
@@ -369,6 +371,31 @@ VFS_VPTOFH(struct vnode * vp, int *fhlenp, unsigned char * fhp, vfs_context_t ct
        return(error);
 }
 
+int VFS_IOCTL(struct mount *mp, u_long command, caddr_t data,
+                         int flags, vfs_context_t context)
+{
+       if (mp == dead_mountp || !mp->mnt_op->vfs_ioctl)
+               return ENOTSUP;
+
+       return mp->mnt_op->vfs_ioctl(mp, command, data, flags,
+                                                                context ?: vfs_context_current());
+}
+
+int
+VFS_VGET_SNAPDIR(mount_t mp, vnode_t *vpp, vfs_context_t ctx)
+{
+       int error;
+
+       if ((mp == dead_mountp) || (mp->mnt_op->vfs_vget_snapdir == 0))
+               return(ENOTSUP);
+
+       if (ctx == NULL)
+               ctx = vfs_context_current();
+
+       error = (*mp->mnt_op->vfs_vget_snapdir)(mp, vpp, ctx);
+
+       return (error);
+}
 
 /* returns the cached throttle mask for the mount_t */
 uint64_t
@@ -379,7 +406,7 @@ vfs_throttle_mask(mount_t mp)
 
 /* returns a  copy of vfs type name for the mount_t */
 void 
-vfs_name(mount_t mp, char * buffer)
+vfs_name(mount_t mp, char *buffer)
 {
         strncpy(buffer, mp->mnt_vtable->vfc_name, MFSNAMELEN);
 }
@@ -599,6 +626,22 @@ vfs_clearextendedsecurity(mount_t mp)
        mount_unlock(mp);
 }
 
+void
+vfs_setnoswap(mount_t mp)
+{
+       mount_lock(mp);
+       mp->mnt_kern_flag |= MNTK_NOSWAP;
+       mount_unlock(mp);
+}
+
+void
+vfs_clearnoswap(mount_t mp)
+{
+       mount_lock(mp);
+       mp->mnt_kern_flag &= ~MNTK_NOSWAP;
+       mount_unlock(mp);
+}
+
 int
 vfs_extendedsecurity(mount_t mp)
 {
@@ -736,8 +779,10 @@ vfs_devvp(mount_t mp)
 void
 vfs_ioattr(mount_t mp, struct vfsioattr *ioattrp)
 {
-        if (mp == NULL) {
-               ioattrp->io_maxreadcnt  = MAXPHYS;
+       ioattrp->io_reserved[0] = NULL;
+       ioattrp->io_reserved[1] = NULL;
+       if (mp == NULL) {
+               ioattrp->io_maxreadcnt  = MAXPHYS;
                ioattrp->io_maxwritecnt = MAXPHYS;
                ioattrp->io_segreadcnt  = 32;
                ioattrp->io_segwritecnt = 32;
@@ -745,8 +790,9 @@ vfs_ioattr(mount_t mp, struct vfsioattr *ioattrp)
                ioattrp->io_maxsegwritesize = MAXPHYS;
                ioattrp->io_devblocksize = DEV_BSIZE;
                ioattrp->io_flags = 0;
+               ioattrp->io_max_swappin_available = 0;
        } else {
-               ioattrp->io_maxreadcnt  = mp->mnt_maxreadcnt;
+               ioattrp->io_maxreadcnt  = mp->mnt_maxreadcnt;
                ioattrp->io_maxwritecnt = mp->mnt_maxwritecnt;
                ioattrp->io_segreadcnt  = mp->mnt_segreadcnt;
                ioattrp->io_segwritecnt = mp->mnt_segwritecnt;
@@ -754,9 +800,8 @@ vfs_ioattr(mount_t mp, struct vfsioattr *ioattrp)
                ioattrp->io_maxsegwritesize = mp->mnt_maxsegwritesize;
                ioattrp->io_devblocksize = mp->mnt_devblocksize;
                ioattrp->io_flags = mp->mnt_ioflags;
+               ioattrp->io_max_swappin_available = mp->mnt_max_swappin_available;
        }
-       ioattrp->io_reserved[0] = NULL;
-       ioattrp->io_reserved[1] = NULL;
 }
 
 
@@ -776,6 +821,7 @@ vfs_setioattr(mount_t mp, struct vfsioattr * ioattrp)
        mp->mnt_maxsegwritesize = ioattrp->io_maxsegwritesize;
        mp->mnt_devblocksize = ioattrp->io_devblocksize;
        mp->mnt_ioflags = ioattrp->io_flags;
+       mp->mnt_max_swappin_available = ioattrp->io_max_swappin_available;
 }
  
 /*
@@ -787,7 +833,7 @@ vfs_setioattr(mount_t mp, struct vfsioattr * ioattrp)
 typedef int (*PFI)(void *);
 extern int vfs_opv_numops;
 errno_t
-vfs_fsadd(struct vfs_fsentry *vfe, vfstable_t * handle)
+vfs_fsadd(struct vfs_fsentry *vfe, vfstable_t *handle)
 {
        struct vfstable *newvfstbl = NULL;
        int     i,j;
@@ -854,6 +900,10 @@ vfs_fsadd(struct vfs_fsentry *vfe, vfstable_t * handle)
                newvfstbl->vfc_vfsflags |= VFC_VFSNOMACLABEL;
        if (vfe->vfe_flags & VFS_TBLVNOP_NOUPDATEID_RENAME)
                newvfstbl->vfc_vfsflags |= VFC_VFSVNOP_NOUPDATEID_RENAME;
+       if (vfe->vfe_flags & VFS_TBLVNOP_SECLUDE_RENAME)
+               newvfstbl->vfc_vfsflags |= VFC_VFSVNOP_SECLUDE_RENAME;
+       if (vfe->vfe_flags & VFS_TBLCANMOUNTROOT)
+               newvfstbl->vfc_vfsflags |= VFC_VFSCANMOUNTROOT;
 
        /*
         * Allocate and init the vectors.
@@ -886,6 +936,13 @@ vfs_fsadd(struct vfs_fsentry *vfe, vfstable_t * handle)
        for (j = 0; vfe->vfe_opvdescs[i]->opv_desc_ops[j].opve_op; j++) {
                opve_descp = &(vfe->vfe_opvdescs[i]->opv_desc_ops[j]);
 
+               /* Silently skip known-disabled operations */
+               if (opve_descp->opve_op->vdesc_flags & VDESC_DISABLED) {
+                       printf("vfs_fsadd: Ignoring reference in %p to disabled operation %s.\n",
+                               vfe->vfe_opvdescs[i], opve_descp->opve_op->vdesc_name);
+                       continue;
+               }
+
                /*
                 * Sanity check:  is this operation listed
                 * in the list of operations?  We check this
@@ -904,7 +961,7 @@ vfs_fsadd(struct vfs_fsentry *vfe, vfstable_t * handle)
                 * list of supported operations.
                 */
                if (opve_descp->opve_op->vdesc_offset == 0 &&
-                   opve_descp->opve_op->vdesc_offset != VOFFSET(vnop_default)) {
+                   opve_descp->opve_op != VDESC(vnop_default)) {
                        printf("vfs_fsadd: operation %s not listed in %s.\n",
                               opve_descp->opve_op->vdesc_name,
                               "vfs_op_descs");
@@ -970,7 +1027,7 @@ vfs_fsadd(struct vfs_fsentry *vfe, vfstable_t * handle)
  * file system was added
  */
 errno_t  
-vfs_fsremove(vfstable_t  handle)
+vfs_fsremove(vfstable_t handle)
 {
        struct vfstable * vfstbl =  (struct vfstable *)handle;
        void *old_desc = NULL;
@@ -1002,6 +1059,32 @@ vfs_fsremove(vfstable_t  handle)
        return(err);
 }
 
+void vfs_setowner(mount_t mp, uid_t uid, gid_t gid)
+{
+       mp->mnt_fsowner = uid;
+       mp->mnt_fsgroup = gid;
+}
+
+/*
+ * Callers should be careful how they use this; accessing
+ * mnt_last_write_completed_timestamp is not thread-safe.  Writing to
+ * it isn't either.  Point is: be prepared to deal with strange values
+ * being returned.
+ */
+uint64_t vfs_idle_time(mount_t mp)
+{
+       if (mp->mnt_pending_write_size)
+               return 0;
+
+       struct timeval now;
+
+       microuptime(&now);
+
+       return ((now.tv_sec
+                        - mp->mnt_last_write_completed_timestamp.tv_sec) * 1000000
+                       + now.tv_usec - mp->mnt_last_write_completed_timestamp.tv_usec);
+}
+
 int
 vfs_context_pid(vfs_context_t ctx)
 {
@@ -1295,6 +1378,11 @@ vfs_context_issuser(vfs_context_t ctx)
        return(kauth_cred_issuser(vfs_context_ucred(ctx)));
 }
 
+int vfs_context_iskernel(vfs_context_t ctx)
+{
+       return ctx == &kerncontext;
+}
+
 /*
  * Given a context, for all fields of vfs_context_t which
  * are not held with a reference, set those fields to the
@@ -1316,6 +1404,11 @@ vfs_context_bind(vfs_context_t ctx)
        return 0;
 }
 
+int vfs_isswapmount(mount_t mnt)
+{
+       return mnt && ISSET(mnt->mnt_kern_flag, MNTK_SWAP_MOUNT) ? 1 : 0;
+}
+
 /* XXXXXXXXXXXXXX VNODE KAPIS XXXXXXXXXXXXXXXXXXXXXXXXX */
 
  
@@ -1754,6 +1847,52 @@ vnode_clearnoreadahead(vnode_t vp)
        vnode_unlock(vp);
 }
 
+int
+vnode_isfastdevicecandidate(vnode_t vp)
+{
+       return ((vp->v_flag & VFASTDEVCANDIDATE)? 1 : 0);
+}
+
+void
+vnode_setfastdevicecandidate(vnode_t vp)
+{
+       vnode_lock_spin(vp);
+       vp->v_flag |= VFASTDEVCANDIDATE;
+       vnode_unlock(vp);
+}
+
+void
+vnode_clearfastdevicecandidate(vnode_t vp)
+{
+       vnode_lock_spin(vp);
+       vp->v_flag &= ~VFASTDEVCANDIDATE;
+       vnode_unlock(vp);
+}
+
+int
+vnode_isautocandidate(vnode_t vp)
+{
+       return ((vp->v_flag & VAUTOCANDIDATE)? 1 : 0);
+}
+
+void
+vnode_setautocandidate(vnode_t vp)
+{
+       vnode_lock_spin(vp);
+       vp->v_flag |= VAUTOCANDIDATE;
+       vnode_unlock(vp);
+}
+
+void
+vnode_clearautocandidate(vnode_t vp)
+{
+       vnode_lock_spin(vp);
+       vp->v_flag &= ~VAUTOCANDIDATE;
+       vnode_unlock(vp);
+}
+
+
+
 
 /* mark vnode_t to skip vflush() is SKIPSYSTEM */
 void 
@@ -1833,7 +1972,7 @@ vnode_setname(vnode_t vp, char * name)
 void 
 vnode_vfsname(vnode_t vp, char * buf)
 {
-        strncpy(buf, vp->v_mount->mnt_vtable->vfc_name, MFSNAMELEN);
+        strlcpy(buf, vp->v_mount->mnt_vtable->vfc_name, MFSNAMELEN);
 }
 
 /* return the FS type number */
@@ -2004,10 +2143,10 @@ vnode_get_filesec(vnode_t vp, kauth_filesec_t *fsecp, vfs_context_t ctx)
 
        fsec = NULL;
        fsec_uio = NULL;
-       error = 0;
-       
+
        /* find out how big the EA is */
-       if (vn_getxattr(vp, KAUTH_FILESEC_XATTR, NULL, &xsize, XATTR_NOSECURITY, ctx) != 0) {
+       error = vn_getxattr(vp, KAUTH_FILESEC_XATTR, NULL, &xsize, XATTR_NOSECURITY, ctx);
+       if (error != 0) {
                /* no EA, no filesec */
                if ((error == ENOATTR) || (error == ENOENT) || (error == EJUSTRETURN))
                        error = 0;
@@ -2029,6 +2168,11 @@ vnode_get_filesec(vnode_t vp, kauth_filesec_t *fsecp, vfs_context_t ctx)
                                
        /* how many entries would fit? */
        fsec_size = KAUTH_FILESEC_COUNT(xsize);
+       if (fsec_size > KAUTH_ACL_MAX_ENTRIES) {
+               KAUTH_DEBUG("    ERROR - Bogus (too large) kauth_fiilesec_t: %ld bytes", xsize);
+               error = 0;
+               goto out;
+       }
 
        /* get buffer and uio */
        if (((fsec = kauth_filesec_alloc(fsec_size)) == NULL) ||
@@ -2175,6 +2319,7 @@ out:
 /*
  * Returns:    0                       Success
  *             ENOMEM                  Not enough space [only if has filesec]
+ *             EINVAL                  Requested unknown attributes
  *             VNOP_GETATTR:           ???
  *             vnode_get_filesec:      ???
  *             kauth_cred_guid2uid:    ???
@@ -2190,6 +2335,12 @@ vnode_getattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
        uid_t   nuid;
        gid_t   ngid;
 
+       /*
+        * Reject attempts to fetch unknown attributes.
+        */
+       if (vap->va_active & ~VNODE_ATTR_ALL)
+               return (EINVAL);
+
        /* don't ask for extended security data if the filesystem doesn't support it */
        if (!vfs_extendedsecurity(vnode_mount(vp))) {
                VATTR_CLEAR_ACTIVE(vap, va_acl);
@@ -2416,7 +2567,18 @@ out:
 int
 vnode_setattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
 {
-       int     error, is_perm_change=0;
+       int     error;
+#if CONFIG_FSE
+       uint64_t active;
+       int     is_perm_change = 0;
+       int     is_stat_change = 0;
+#endif
+
+       /*
+        * Reject attempts to set unknown attributes.
+        */
+       if (vap->va_active & ~VNODE_ATTR_ALL)
+               return (EINVAL);
 
        /*
         * Make sure the filesystem is mounted R/W.
@@ -2426,6 +2588,20 @@ vnode_setattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
                error = EROFS;
                goto out;
        }
+
+#if DEVELOPMENT || DEBUG
+       /*
+        * XXX VSWAP: Check for entitlements or special flag here
+        * so we can restrict access appropriately.
+        */
+#else /* DEVELOPMENT || DEBUG */
+
+       if (vnode_isswap(vp) && (ctx != vfs_context_kernel())) {
+               error = EPERM;
+               goto out;
+       }
+#endif /* DEVELOPMENT || DEBUG */
+
 #if NAMEDSTREAMS
        /* For streams, va_data_size is the only setable attribute. */
        if ((vp->v_flag & VISNAMEDSTREAM) && (vap->va_active != VNODE_ATTR_va_data_size)) {
@@ -2433,6 +2609,25 @@ vnode_setattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
                goto out;
        }
 #endif
+       /* Check for truncation */
+       if(VATTR_IS_ACTIVE(vap,  va_data_size)) {
+               switch(vp->v_type) {
+               case VREG:
+                       /* For regular files it's ok */
+                       break;
+               case VDIR:
+                       /* Not allowed to truncate directories */
+                       error = EISDIR;
+                       goto out;
+               default:
+                       /* For everything else we will clear the bit and let underlying FS decide on the rest */
+                       VATTR_CLEAR_ACTIVE(vap, va_data_size);
+                       if (vap->va_active)
+                               break;
+                       /* If it was the only bit set, return success, to handle cases like redirect to /dev/null */
+                       return (0);
+               }
+       }
        
        /*
         * If ownership is being ignored on this volume, we silently discard
@@ -2443,11 +2638,6 @@ vnode_setattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
                VATTR_CLEAR_ACTIVE(vap, va_gid);
        }
 
-       if (   VATTR_IS_ACTIVE(vap, va_uid)  || VATTR_IS_ACTIVE(vap, va_gid)
-           || VATTR_IS_ACTIVE(vap, va_mode) || VATTR_IS_ACTIVE(vap, va_acl)) {
-           is_perm_change = 1;
-       }
-       
        /*
         * Make sure that extended security is enabled if we're going to try
         * to set any.
@@ -2459,23 +2649,60 @@ vnode_setattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
                goto out;
        }
 
+       /* Never allow the setting of any unsupported superuser flags. */
+       if (VATTR_IS_ACTIVE(vap, va_flags)) {
+           vap->va_flags &= (SF_SUPPORTED | UF_SETTABLE);
+       }
+
+#if CONFIG_FSE
+       /*
+        * Remember all of the active attributes that we're
+        * attempting to modify.
+        */
+       active = vap->va_active & ~VNODE_ATTR_RDONLY;
+#endif
+
        error = VNOP_SETATTR(vp, vap, ctx);
 
        if ((error == 0) && !VATTR_ALL_SUPPORTED(vap))
                error = vnode_setattr_fallback(vp, vap, ctx);
 
 #if CONFIG_FSE
-       // only send a stat_changed event if this is more than
-       // just an access or backup time update
-       if (error == 0 && (vap->va_active != VNODE_ATTR_BIT(va_access_time)) && (vap->va_active != VNODE_ATTR_BIT(va_backup_time))) {
+#define        PERMISSION_BITS (VNODE_ATTR_BIT(va_uid) | VNODE_ATTR_BIT(va_uuuid) | \
+                        VNODE_ATTR_BIT(va_gid) | VNODE_ATTR_BIT(va_guuid) | \
+                        VNODE_ATTR_BIT(va_mode) | VNODE_ATTR_BIT(va_acl))
+
+       /*
+        * Now that we've changed them, decide whether to send an
+        * FSevent.
+        */
+       if ((active & PERMISSION_BITS) & vap->va_supported) {
+               is_perm_change = 1;
+       } else {
+               /*
+                * We've already checked the permission bits, and we
+                * also want to filter out access time / backup time
+                * changes.
+                */
+               active &= ~(PERMISSION_BITS |
+                           VNODE_ATTR_BIT(va_access_time) |
+                           VNODE_ATTR_BIT(va_backup_time));
+
+               /* Anything left to notify about? */
+               if (active & vap->va_supported)
+                       is_stat_change = 1;
+       }
+
+       if (error == 0) {
            if (is_perm_change) {
                if (need_fsevent(FSE_CHOWN, vp)) {
                    add_fsevent(FSE_CHOWN, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE);
                }
-           } else if(need_fsevent(FSE_STAT_CHANGED, vp)) {
+           } else if (is_stat_change && need_fsevent(FSE_STAT_CHANGED, vp)) {
                add_fsevent(FSE_STAT_CHANGED, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE);
            }
        }
+#undef PERMISSION_BITS
 #endif
 
 out:
@@ -3326,7 +3553,7 @@ VNOP_IOCTL(vnode_t vp, u_long command, caddr_t data, int fflag, vfs_context_t ct
         * We have to be able to use the root filesystem's device vnode even when
         * devfs isn't mounted (yet/anymore), so we can't go looking at its mount
         * structure.  If there is no data pointer, it doesn't matter whether
-        * the device is 64-bit ready.  Any command (like DKIOCSYNCHRONIZECACHE)
+        * the device is 64-bit ready.  Any command (like DKIOCSYNCHRONIZE)
         * which passes NULL for its data pointer can therefore be used during
         * mount or unmount of the root filesystem.
         *
@@ -3711,7 +3938,7 @@ VNOP_LINK(vnode_t vp, vnode_t tdvp, struct componentname * cnp, vfs_context_t ct
 errno_t
 vn_rename(struct vnode *fdvp, struct vnode **fvpp, struct componentname *fcnp, struct vnode_attr *fvap,
             struct vnode *tdvp, struct vnode **tvpp, struct componentname *tcnp, struct vnode_attr *tvap,
-            uint32_t flags, vfs_context_t ctx)
+            vfs_rename_flags_t flags, vfs_context_t ctx)
 {
        int _err;
        struct nameidata *fromnd = NULL;
@@ -3734,13 +3961,6 @@ vn_rename(struct vnode *fdvp, struct vnode **fvpp, struct componentname *fcnp, s
                        panic("Not batched, and no fvp?");
        }
 
-#if CONFIG_SECLUDED_RENAME
-       if ((fcnp->cn_flags & CN_SECLUDE_RENAME) && 
-           (((*fvpp)->v_mount->mnt_vtable->vfc_vfsflags & VFC_VFSVNOP_SECLUDE_RENAME) == 0)) {
-           return ENOTSUP;
-       }
-#endif
-
 #if CONFIG_APPLEDOUBLE
        /* 
         * We need to preflight any potential AppleDouble file for the source file
@@ -3824,13 +4044,18 @@ vn_rename(struct vnode *fdvp, struct vnode **fvpp, struct componentname *fcnp, s
                        printf("VNOP_COMPOUND_RENAME() returned %d\n", _err);
                }
        } else {
-               _err = VNOP_RENAME(fdvp, *fvpp, fcnp, tdvp, *tvpp, tcnp, ctx);
-       }
-#if CONFIG_MACF
-       if (_err == 0) {
-               mac_vnode_notify_rename(ctx, *fvpp, tdvp, tcnp);
+               if (flags) {
+                       _err = VNOP_RENAMEX(fdvp, *fvpp, fcnp, tdvp, *tvpp, tcnp, flags, ctx);
+                       if (_err == ENOTSUP && flags == VFS_RENAME_SECLUDE) {
+                               // Legacy...
+                               if ((*fvpp)->v_mount->mnt_vtable->vfc_vfsflags & VFC_VFSVNOP_SECLUDE_RENAME) {
+                                       fcnp->cn_flags |= CN_SECLUDE_RENAME;
+                                       _err = VNOP_RENAME(fdvp, *fvpp, fcnp, tdvp, *tvpp, tcnp, ctx);
+                               }
+                       }
+               } else
+                       _err = VNOP_RENAME(fdvp, *fvpp, fcnp, tdvp, *tvpp, tcnp, ctx);
        }
-#endif
 
        /*
         * If moved to a new directory that is restricted,
@@ -3838,18 +4063,27 @@ vn_rename(struct vnode *fdvp, struct vnode **fvpp, struct componentname *fcnp, s
         */
        if (_err == 0) {
                _err = vnode_flags(tdvp, &tdfflags, ctx);
-               if (_err == 0 && (tdfflags & SF_RESTRICTED)) {
-                       uint32_t fflags;
-                       _err = vnode_flags(*fvpp, &fflags, ctx);
-                       if (_err == 0 && !(fflags & SF_RESTRICTED)) {
-                               struct vnode_attr va;
-                               VATTR_INIT(&va);
-                               VATTR_SET(&va, va_flags, fflags | SF_RESTRICTED);
-                               _err = vnode_setattr(*fvpp, &va, ctx);
+               if (_err == 0) {
+                       uint32_t inherit_flags = tdfflags & (UF_DATAVAULT | SF_RESTRICTED);
+                       if (inherit_flags) {
+                               uint32_t fflags;
+                               _err = vnode_flags(*fvpp, &fflags, ctx);
+                               if (_err == 0 && fflags != (fflags | inherit_flags)) {
+                                       struct vnode_attr va;
+                                       VATTR_INIT(&va);
+                                       VATTR_SET(&va, va_flags, fflags | inherit_flags);
+                                       _err = vnode_setattr(*fvpp, &va, ctx);
+                               }
                        }
                }
        }
 
+#if CONFIG_MACF
+       if (_err == 0) {
+               mac_vnode_notify_rename(ctx, *fvpp, tdvp, tcnp);
+       }
+#endif
+
 #if CONFIG_APPLEDOUBLE
        /* 
         * Rename any associated extended attribute file (._ AppleDouble file).
@@ -3996,7 +4230,6 @@ VNOP_RENAME(struct vnode *fdvp, struct vnode *fvp, struct componentname *fcnp,
             vfs_context_t ctx)
 {
        int _err = 0;
-       int events;
        struct vnop_rename_args a;
 
        a.a_desc = &vnop_rename_desc;
@@ -4012,41 +4245,96 @@ VNOP_RENAME(struct vnode *fdvp, struct vnode *fvp, struct componentname *fcnp,
        _err = (*fdvp->v_op[vnop_rename_desc.vdesc_offset])(&a);
        DTRACE_FSINFO(rename, vnode_t, fdvp);
 
-       if (_err == 0) {
-               if (tvp && tvp != fvp)
-                       vnode_setneedinactive(tvp);
-       }
+       if (_err)
+               return _err;
 
-       /* Wrote at least one directory.  If transplanted a dir, also changed link counts */
-       if (_err == 0) {
-               events = NOTE_WRITE;
-               if (vnode_isdir(fvp)) {
-                       /* Link count on dir changed only if we are moving a dir and...
-                        *      --Moved to new dir, not overwriting there
-                        *      --Kept in same dir and DID overwrite
-                        */
-                       if (((fdvp != tdvp) && (!tvp)) || ((fdvp == tdvp) && (tvp))) {
-                               events |= NOTE_LINK;
-                       }
-               }
+       return post_rename(fdvp, fvp, tdvp, tvp);
+}
 
-               lock_vnode_and_post(fdvp, events);
-               if (fdvp != tdvp) {
-                       lock_vnode_and_post(tdvp,  events);
-               }
+static errno_t
+post_rename(vnode_t fdvp, vnode_t fvp, vnode_t tdvp, vnode_t tvp)
+{
+       if (tvp && tvp != fvp)
+               vnode_setneedinactive(tvp);
 
-               /* If you're replacing the target, post a deletion for it */
-               if (tvp)
-               {
-                       lock_vnode_and_post(tvp, NOTE_DELETE);
+       /* Wrote at least one directory.  If transplanted a dir, also changed link counts */
+       int events = NOTE_WRITE;
+       if (vnode_isdir(fvp)) {
+               /* Link count on dir changed only if we are moving a dir and...
+                *      --Moved to new dir, not overwriting there
+                *      --Kept in same dir and DID overwrite
+                */
+               if (((fdvp != tdvp) && (!tvp)) || ((fdvp == tdvp) && (tvp))) {
+                       events |= NOTE_LINK;
                }
+       }
 
-               lock_vnode_and_post(fvp, NOTE_RENAME);
+       lock_vnode_and_post(fdvp, events);
+       if (fdvp != tdvp) {
+               lock_vnode_and_post(tdvp,  events);
        }
 
-       return (_err);
+       /* If you're replacing the target, post a deletion for it */
+       if (tvp)
+       {
+               lock_vnode_and_post(tvp, NOTE_DELETE);
+       }
+
+       lock_vnode_and_post(fvp, NOTE_RENAME);
+
+       return 0;
+}
+
+#if 0
+/*
+ *#
+ *#% renamex      fdvp    U U U
+ *#% renamex      fvp     U U U
+ *#% renamex      tdvp    L U U
+ *#% renamex      tvp     X U U
+ *#
+ */
+struct vnop_renamex_args {
+       struct vnodeop_desc *a_desc;
+       vnode_t a_fdvp;
+       vnode_t a_fvp;
+       struct componentname *a_fcnp;
+       vnode_t a_tdvp;
+       vnode_t a_tvp;
+       struct componentname *a_tcnp;
+       vfs_rename_flags_t a_flags;
+       vfs_context_t a_context;
+};
+#endif /* 0*/
+errno_t
+VNOP_RENAMEX(struct vnode *fdvp, struct vnode *fvp, struct componentname *fcnp,
+                        struct vnode *tdvp, struct vnode *tvp, struct componentname *tcnp,
+                        vfs_rename_flags_t flags, vfs_context_t ctx)
+{
+       int _err = 0;
+       struct vnop_renamex_args a;
+
+       a.a_desc = &vnop_renamex_desc;
+       a.a_fdvp = fdvp;
+       a.a_fvp = fvp;
+       a.a_fcnp = fcnp;
+       a.a_tdvp = tdvp;
+       a.a_tvp = tvp;
+       a.a_tcnp = tcnp;
+       a.a_flags = flags;
+       a.a_context = ctx;
+
+       /* do the rename of the main file. */
+       _err = (*fdvp->v_op[vnop_renamex_desc.vdesc_offset])(&a);
+       DTRACE_FSINFO(renamex, vnode_t, fdvp);
+
+       if (_err)
+               return _err;
+
+       return post_rename(fdvp, fvp, tdvp, tvp);
 }
 
+
 int
 VNOP_COMPOUND_RENAME( 
                struct vnode *fdvp,  struct vnode **fvpp,  struct componentname *fcnp, struct vnode_attr *fvap,
@@ -4891,11 +5179,16 @@ VNOP_ADVLOCK(struct vnode *vp, caddr_t id, int op, struct flock *fl, int flags,
                if ((vp->v_flag & VLOCKLOCAL)) {
                        /* Advisory locking done at this layer */
                        _err = lf_advlock(&a);
+               } else if (flags & F_OFD_LOCK) {
+                       /* Non-local locking doesn't work for OFD locks */
+                       _err = err_advlock(&a);
                } else {
                        /* Advisory locking done by underlying filesystem */
                        _err = (*vp->v_op[vnop_advlock_desc.vdesc_offset])(&a);
                }
                DTRACE_FSINFO(advlock, vnode_t, vp);
+               if (op == F_UNLCK && flags == F_FLOCK)
+                       post_event_if_success(vp, _err, NOTE_FUNLOCK);
        }
 
        return (_err);
@@ -5126,6 +5419,61 @@ VNOP_COPYFILE(struct vnode *fvp, struct vnode *tdvp, struct vnode *tvp, struct c
        return (_err);
 }
 
+#if 0
+struct vnop_clonefile_args {
+       struct vnodeop_desc *a_desc;
+       vnode_t a_fvp;
+       vnode_t a_dvp;
+       vnode_t *a_vpp;
+       struct componentname *a_cnp;
+       struct vnode_attr *a_vap;
+       uint32_t a_flags;
+       vfs_context_t a_context;
+       int (*a_dir_clone_authorizer)(  /* Authorization callback */
+                       struct vnode_attr *vap, /* attribute to be authorized */
+                       kauth_action_t action, /* action for which attribute is to be authorized */
+                       struct vnode_attr *dvap, /* target directory attributes */
+                       vnode_t sdvp, /* source directory vnode pointer (optional) */
+                       mount_t mp, /* mount point of filesystem */
+                       dir_clone_authorizer_op_t vattr_op, /* specific operation requested : setup, authorization or cleanup  */
+                       uint32_t flags; /* value passed in a_flags to the VNOP */
+                       vfs_context_t ctx,              /* As passed to VNOP */
+                       void *reserved);                /* Always NULL */
+       void *a_reserved;               /* Currently unused */
+};
+#endif /* 0 */
+
+errno_t
+VNOP_CLONEFILE(vnode_t fvp, vnode_t dvp, vnode_t *vpp,
+    struct componentname *cnp, struct vnode_attr *vap, uint32_t flags,
+    vfs_context_t ctx)
+{
+       int _err;
+       struct vnop_clonefile_args a;
+       a.a_desc = &vnop_clonefile_desc;
+       a.a_fvp = fvp;
+       a.a_dvp = dvp;
+       a.a_vpp = vpp;
+       a.a_cnp = cnp;
+       a.a_vap = vap;
+       a.a_flags = flags;
+       a.a_context = ctx;
+
+       if (vnode_vtype(fvp) == VDIR)
+               a.a_dir_clone_authorizer = vnode_attr_authorize_dir_clone;
+       else
+               a.a_dir_clone_authorizer = NULL;
+
+       _err = (*dvp->v_op[vnop_clonefile_desc.vdesc_offset])(&a);
+
+       if (_err == 0 && *vpp)
+               DTRACE_FSINFO(clonefile, vnode_t, *vpp);
+
+       post_event_if_success(dvp, _err, NOTE_WRITE);
+
+       return (_err);
+}
+
 errno_t
 VNOP_GETXATTR(vnode_t vp, const char *name, uio_t uio, size_t *size, int options, vfs_context_t ctx)
 {