+static int
+vn_open_auth_finish(vnode_t vp, int fmode, vfs_context_t ctx)
+{
+ int error;
+
+ if ((error = vnode_ref_ext(vp, fmode, 0)) != 0) {
+ goto bad;
+ }
+
+ /* Call out to allow 3rd party notification of open.
+ * Ignore result of kauth_authorize_fileop call.
+ */
+#if CONFIG_MACF
+ mac_vnode_notify_open(ctx, vp, fmode);
+#endif
+ kauth_authorize_fileop(vfs_context_ucred(ctx), KAUTH_FILEOP_OPEN,
+ (uintptr_t)vp, 0);
+
+ sigpup_attach_vnode(vp);
+
+ return 0;
+
+bad:
+ return error;
+
+}
+
+/*
+ * May do nameidone() to allow safely adding an FSEvent. Cue off of ni_dvp to
+ * determine whether that has happened.
+ */
+static int
+vn_open_auth_do_create(struct nameidata *ndp, struct vnode_attr *vap, int fmode, boolean_t *did_create, boolean_t *did_open, vfs_context_t ctx)
+{
+ uint32_t status = 0;
+ vnode_t dvp = ndp->ni_dvp;
+ int batched;
+ int error;
+ vnode_t vp;
+
+ batched = vnode_compound_open_available(ndp->ni_dvp);
+ *did_open = FALSE;
+
+ VATTR_SET(vap, va_type, VREG);
+ if (fmode & O_EXCL)
+ vap->va_vaflags |= VA_EXCLUSIVE;
+
+#if NAMEDRSRCFORK
+ if (ndp->ni_cnd.cn_flags & CN_WANTSRSRCFORK) {
+ if ((error = vn_authorize_create(dvp, &ndp->ni_cnd, vap, ctx, NULL)) != 0)
+ goto out;
+ if ((error = vnode_makenamedstream(dvp, &ndp->ni_vp, XATTR_RESOURCEFORK_NAME, 0, ctx)) != 0)
+ goto out;
+ *did_create = TRUE;
+ } else {
+#endif
+ if (!batched) {
+ if ((error = vn_authorize_create(dvp, &ndp->ni_cnd, vap, ctx, NULL)) != 0)
+ goto out;
+ }
+
+ error = vn_create(dvp, &ndp->ni_vp, ndp, vap, VN_CREATE_DOOPEN, fmode, &status, ctx);
+ if (error != 0) {
+ if (batched) {
+ *did_create = (status & COMPOUND_OPEN_STATUS_DID_CREATE) ? TRUE : FALSE;
+ } else {
+ *did_create = FALSE;
+ }
+
+ if (error == EKEEPLOOKING) {
+ if (*did_create) {
+ panic("EKEEPLOOKING, but we did a create?");
+ }
+ if (!batched) {
+ panic("EKEEPLOOKING from filesystem that doesn't support compound vnops?");
+ }
+ if ((ndp->ni_flag & NAMEI_CONTLOOKUP) == 0) {
+ panic("EKEEPLOOKING, but continue flag not set?");
+ }
+
+ /*
+ * Do NOT drop the dvp: we need everything to continue the lookup.
+ */
+ return error;
+ }
+ } else {
+ if (batched) {
+ *did_create = (status & COMPOUND_OPEN_STATUS_DID_CREATE) ? 1 : 0;
+ *did_open = TRUE;
+ } else {
+ *did_create = TRUE;
+ }
+ }
+#if NAMEDRSRCFORK
+ }
+#endif
+
+ vp = ndp->ni_vp;
+
+ if (*did_create) {
+ int update_flags = 0;
+
+ // Make sure the name & parent pointers are hooked up
+ if (vp->v_name == NULL)
+ update_flags |= VNODE_UPDATE_NAME;
+ if (vp->v_parent == NULLVP)
+ update_flags |= VNODE_UPDATE_PARENT;
+
+ if (update_flags)
+ vnode_update_identity(vp, dvp, ndp->ni_cnd.cn_nameptr, ndp->ni_cnd.cn_namelen, ndp->ni_cnd.cn_hash, update_flags);
+
+ vnode_put(dvp);
+ ndp->ni_dvp = NULLVP;
+
+#if CONFIG_FSE
+ if (need_fsevent(FSE_CREATE_FILE, vp)) {
+ add_fsevent(FSE_CREATE_FILE, ctx,
+ FSE_ARG_VNODE, vp,
+ FSE_ARG_DONE);
+ }
+#endif
+ }
+out:
+ if (ndp->ni_dvp != NULLVP) {
+ vnode_put(dvp);
+ ndp->ni_dvp = NULLVP;
+ }
+
+ return error;
+}
+