X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/39236c6e673c41db228275375ab7fdb0f837b292..4d15aeb193b2c68f1d38666c317f8d3734f5f083:/bsd/vfs/kpi_vfs.c diff --git a/bsd/vfs/kpi_vfs.c b/bsd/vfs/kpi_vfs.c index 200cb51c4..dd3560fed 100644 --- a/bsd/vfs/kpi_vfs.c +++ b/bsd/vfs/kpi_vfs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2011 Apple Inc. All rights reserved. + * Copyright (c) 2000-2016 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); } @@ -476,7 +503,7 @@ vfs_isreload(mount_t mp) int vfs_isforce(mount_t mp) { - if ((mp->mnt_lflag & MNT_LFORCE) || (mp->mnt_kern_flag & MNTK_FRCUNMOUNT)) + if (mp->mnt_lflag & MNT_LFORCE) return(1); else return(0); @@ -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; @@ -822,7 +868,7 @@ vfs_fsadd(struct vfs_fsentry *vfe, vfstable_t * handle) newvfstbl->vfc_vfsops = vfe->vfe_vfsops; strncpy(&newvfstbl->vfc_name[0], vfe->vfe_fsname, MFSNAMELEN); if ((vfe->vfe_flags & VFS_TBLNOTYPENUM)) - newvfstbl->vfc_typenum = maxvfsconf++; + newvfstbl->vfc_typenum = maxvfstypenum++; else newvfstbl->vfc_typenum = vfe->vfe_fstypenum; @@ -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. @@ -872,6 +922,7 @@ vfs_fsadd(struct vfs_fsentry *vfe, vfstable_t * handle) newvfstbl->vfc_descptr = descptr; newvfstbl->vfc_descsize = descsize; + newvfstbl->vfc_sysctl = NULL; for (i= 0; i< desccount; i++ ) { opv_desc_vector_p = vfe->vfe_opvdescs[i]->opv_desc_vector_p; @@ -885,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 @@ -903,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"); @@ -941,8 +999,8 @@ vfs_fsadd(struct vfs_fsentry *vfe, vfstable_t * handle) *handle = vfstable_add(newvfstbl); - if (newvfstbl->vfc_typenum <= maxvfsconf ) - maxvfsconf = newvfstbl->vfc_typenum + 1; + if (newvfstbl->vfc_typenum <= maxvfstypenum ) + maxvfstypenum = newvfstbl->vfc_typenum + 1; if (newvfstbl->vfc_vfsops->vfs_init) { struct vfsconf vfsc; @@ -969,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; @@ -1001,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) { @@ -1294,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 @@ -1315,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 */ @@ -1371,6 +1465,17 @@ vnode_mount(vnode_t vp) return (vp->v_mount); } +#if CONFIG_IOSCHED +vnode_t +vnode_mountdevvp(vnode_t vp) +{ + if (vp->v_mount) + return (vp->v_mount->mnt_devvp); + else + return ((vnode_t)0); +} +#endif + mount_t vnode_mountedhere(vnode_t vp) { @@ -1742,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 @@ -1821,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 */ @@ -1992,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; @@ -2414,6 +2565,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)) { @@ -2421,6 +2586,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 @@ -2447,6 +2631,11 @@ 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); + } + error = VNOP_SETATTR(vp, vap, ctx); if ((error == 0) && !VATTR_ALL_SUPPORTED(vap)) @@ -2800,7 +2989,7 @@ VNOP_COMPOUND_OPEN(vnode_t dvp, vnode_t *vpp, struct nameidata *ndp, int32_t fla uint32_t tmp_status = 0; struct componentname *cnp = &ndp->ni_cnd; - want_create = (flags & VNOP_COMPOUND_OPEN_DO_CREATE); + want_create = (flags & O_CREAT); a.a_desc = &vnop_compound_open_desc; a.a_dvp = dvp; @@ -2926,23 +3115,10 @@ struct vnop_whiteout_args { }; #endif /* 0*/ errno_t -VNOP_WHITEOUT(vnode_t dvp, struct componentname * cnp, int flags, vfs_context_t ctx) +VNOP_WHITEOUT(__unused vnode_t dvp, __unused struct componentname *cnp, + __unused int flags, __unused vfs_context_t ctx) { - int _err; - struct vnop_whiteout_args a; - - a.a_desc = &vnop_whiteout_desc; - a.a_dvp = dvp; - a.a_cnp = cnp; - a.a_flags = flags; - a.a_context = ctx; - - _err = (*dvp->v_op[vnop_whiteout_desc.vdesc_offset])(&a); - DTRACE_FSINFO(whiteout, vnode_t, dvp); - - post_event_if_success(dvp, _err, NOTE_WRITE); - - return (_err); + return (ENOTSUP); // XXX OBSOLETE } #if 0 @@ -3235,7 +3411,7 @@ VNOP_READ(vnode_t vp, struct uio * uio, int ioflag, vfs_context_t ctx) #endif if (ctx == NULL) { - ctx = vfs_context_current(); + return EINVAL; } a.a_desc = &vnop_read_desc; @@ -3276,7 +3452,7 @@ VNOP_WRITE(vnode_t vp, struct uio * uio, int ioflag, vfs_context_t ctx) #endif if (ctx == NULL) { - ctx = vfs_context_current(); + return EINVAL; } a.a_desc = &vnop_write_desc; @@ -3327,7 +3503,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. * @@ -3712,7 +3888,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; @@ -3726,6 +3902,7 @@ vn_rename(struct vnode *fdvp, struct vnode **fvpp, struct componentname *fcnp, s char *xtoname = NULL; #endif /* CONFIG_APPLEDOUBLE */ int batched; + uint32_t tdfflags; // Target directory file flags batched = vnode_compound_rename_available(fdvp); @@ -3817,8 +3994,37 @@ 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 (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); + } + + /* + * If moved to a new directory that is restricted, + * set the restricted flag on the item moved. + */ + 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 CONFIG_MACF if (_err == 0) { mac_vnode_notify_rename(ctx, *fvpp, tdvp, tcnp); @@ -3971,7 +4177,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; @@ -3987,41 +4192,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, @@ -4610,6 +4870,49 @@ VNOP_READDIRATTR(struct vnode *vp, struct attrlist *alist, struct uio *uio, uint return (_err); } +#if 0 +struct vnop_getttrlistbulk_args { + struct vnodeop_desc *a_desc; + vnode_t a_vp; + struct attrlist *a_alist; + struct vnode_attr *a_vap; + struct uio *a_uio; + void *a_private + uint64_t a_options; + int *a_eofflag; + uint32_t *a_actualcount; + vfs_context_t a_context; +}; +#endif /* 0*/ +errno_t +VNOP_GETATTRLISTBULK(struct vnode *vp, struct attrlist *alist, + struct vnode_attr *vap, struct uio *uio, void *private, uint64_t options, + int32_t *eofflag, int32_t *actualcount, vfs_context_t ctx) +{ + int _err; + struct vnop_getattrlistbulk_args a; +#if CONFIG_DTRACE + user_ssize_t resid = uio_resid(uio); +#endif + + a.a_desc = &vnop_getattrlistbulk_desc; + a.a_vp = vp; + a.a_alist = alist; + a.a_vap = vap; + a.a_uio = uio; + a.a_private = private; + a.a_options = options; + a.a_eofflag = eofflag; + a.a_actualcount = actualcount; + a.a_context = ctx; + + _err = (*vp->v_op[vnop_getattrlistbulk_desc.vdesc_offset])(&a); + DTRACE_FSINFO_IO(getattrlistbulk, + vnode_t, vp, user_ssize_t, (resid - uio_resid(uio))); + + return (_err); +} + #if 0 /* *# @@ -4823,11 +5126,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); @@ -5058,6 +5366,60 @@ 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 */ + 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) {