+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.
+ */
+ kauth_authorize_fileop(vfs_context_ucred(ctx), KAUTH_FILEOP_OPEN,
+ (uintptr_t)vp, 0);
+
+ 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
+
+ /*
+ * Unlock the fsnode (if locked) here so that we are free
+ * to drop the dvp iocount and prevent deadlock in build_path().
+ * nameidone() will still do the right thing later.
+ */
+ vp = ndp->ni_vp;
+ namei_unlock_fsnode(ndp);
+
+ 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;
+}
+
+/*
+ * Open a file with authorization, updating the contents of the structures
+ * pointed to by ndp, fmodep, and vap as necessary to perform the requested
+ * operation. This function is used for both opens of existing files, and
+ * creation of new files.
+ *
+ * Parameters: ndp The nami data pointer describing the
+ * file
+ * fmodep A pointer to an int containg the mode
+ * information to be used for the open
+ * vap A pointer to the vnode attribute
+ * descriptor to be used for the open
+ *
+ * Indirect: * Contents of the data structures pointed
+ * to by the parameters are modified as
+ * necessary to the requested operation.
+ *
+ * Returns: 0 Success
+ * !0 errno value
+ *
+ * Notes: The kauth_filesec_t in 'vap', if any, is in host byte order.
+ *
+ * The contents of '*ndp' will be modified, based on the other
+ * arguments to this function, and to return file and directory
+ * data necessary to satisfy the requested operation.
+ *
+ * If the file does not exist and we are creating it, then the
+ * O_TRUNC flag will be cleared in '*fmodep' to indicate to the
+ * caller that the file was not truncated.
+ *
+ * If the file exists and the O_EXCL flag was not specified, then
+ * the O_CREAT flag will be cleared in '*fmodep' to indicate to
+ * the caller that the existing file was merely opened rather
+ * than created.
+ *
+ * The contents of '*vap' will be modified as necessary to
+ * complete the operation, including setting of supported
+ * attribute, clearing of fields containing unsupported attributes
+ * in the request, if the request proceeds without them, etc..
+ *
+ * XXX: This function is too complicated in actings on its arguments
+ *
+ * XXX: We should enummerate the possible errno values here, and where
+ * in the code they originated.
+ */