+*#
+*#% rename fdvp U U U
+*#% rename fvp U U U
+*#% rename tdvp L U U
+*#% rename tvp X U U
+*#
+*/
+struct vnop_rename_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_context_t a_context;
+};
+#endif /* 0*/
+errno_t
+VNOP_RENAME(struct vnode *fdvp, struct vnode *fvp, struct componentname *fcnp,
+ struct vnode *tdvp, struct vnode *tvp, struct componentname *tcnp,
+ vfs_context_t ctx)
+{
+ int _err = 0;
+ struct vnop_rename_args a;
+
+ a.a_desc = &vnop_rename_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_context = ctx;
+
+ /* do the rename of the main file. */
+ _err = (*fdvp->v_op[vnop_rename_desc.vdesc_offset])(&a);
+ DTRACE_FSINFO(rename, vnode_t, fdvp);
+
+ if (_err) {
+ return _err;
+ }
+
+ return post_rename(fdvp, fvp, tdvp, tvp);
+}
+
+static errno_t
+post_rename(vnode_t fdvp, vnode_t fvp, vnode_t tdvp, vnode_t tvp)
+{
+ if (tvp && tvp != fvp) {
+ vnode_setneedinactive(tvp);
+ }
+
+ /* 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(fdvp, events);
+ if (fdvp != tdvp) {
+ lock_vnode_and_post(tdvp, events);
+ }
+
+ /* 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,
+ struct vnode *tdvp, struct vnode **tvpp, struct componentname *tcnp, struct vnode_attr *tvap,
+ uint32_t flags, vfs_context_t ctx)
+{
+ int _err = 0;
+ int events;
+ struct vnop_compound_rename_args a;
+ int no_fvp, no_tvp;
+
+ no_fvp = (*fvpp) == NULLVP;
+ no_tvp = (*tvpp) == NULLVP;
+
+ a.a_desc = &vnop_compound_rename_desc;
+
+ a.a_fdvp = fdvp;
+ a.a_fvpp = fvpp;
+ a.a_fcnp = fcnp;
+ a.a_fvap = fvap;
+
+ a.a_tdvp = tdvp;
+ a.a_tvpp = tvpp;
+ a.a_tcnp = tcnp;
+ a.a_tvap = tvap;
+
+ a.a_flags = flags;
+ a.a_context = ctx;
+ a.a_rename_authorizer = vn_authorize_rename;
+ a.a_reserved = NULL;
+
+ /* do the rename of the main file. */
+ _err = (*fdvp->v_op[vnop_compound_rename_desc.vdesc_offset])(&a);
+ DTRACE_FSINFO(compound_rename, vnode_t, fdvp);
+
+ if (_err == 0) {
+ if (*tvpp && *tvpp != *fvpp) {
+ vnode_setneedinactive(*tvpp);
+ }
+ }
+
+ /* Wrote at least one directory. If transplanted a dir, also changed link counts */
+ if (_err == 0 && *fvpp != *tvpp) {
+ if (!*fvpp) {
+ panic("No fvpp after compound rename?");
+ }
+
+ events = NOTE_WRITE;
+ if (vnode_isdir(*fvpp)) {
+ /* 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) && (!*tvpp)) || ((fdvp == tdvp) && (*tvpp))) {
+ events |= NOTE_LINK;
+ }
+ }
+
+ lock_vnode_and_post(fdvp, events);
+ if (fdvp != tdvp) {
+ lock_vnode_and_post(tdvp, events);
+ }
+
+ /* If you're replacing the target, post a deletion for it */
+ if (*tvpp) {
+ lock_vnode_and_post(*tvpp, NOTE_DELETE);
+ }
+
+ lock_vnode_and_post(*fvpp, NOTE_RENAME);
+ }
+
+ if (no_fvp) {
+ lookup_compound_vnop_post_hook(_err, fdvp, *fvpp, fcnp->cn_ndp, 0);
+ }
+ if (no_tvp && *tvpp != NULLVP) {
+ lookup_compound_vnop_post_hook(_err, tdvp, *tvpp, tcnp->cn_ndp, 0);
+ }
+
+ if (_err && _err != EKEEPLOOKING) {
+ if (*fvpp) {
+ vnode_put(*fvpp);
+ *fvpp = NULLVP;
+ }
+ if (*tvpp) {
+ vnode_put(*tvpp);
+ *tvpp = NULLVP;
+ }
+ }
+
+ return _err;
+}
+
+int
+vn_mkdir(struct vnode *dvp, struct vnode **vpp, struct nameidata *ndp,
+ struct vnode_attr *vap, vfs_context_t ctx)
+{
+ if (ndp->ni_cnd.cn_nameiop != CREATE) {
+ panic("Non-CREATE nameiop in vn_mkdir()?");
+ }
+
+ if (vnode_compound_mkdir_available(dvp)) {
+ return VNOP_COMPOUND_MKDIR(dvp, vpp, ndp, vap, ctx);
+ } else {
+ return VNOP_MKDIR(dvp, vpp, &ndp->ni_cnd, vap, ctx);
+ }
+}
+
+#if 0
+/*
+*#
+*#% mkdir dvp L U U
+*#% mkdir vpp - L -
+*#
+*/