+ ndp->ni_dvp = dp;
+ } else {
+ vnode_put(dp);
+ }
+ ndp->ni_vp = svp; /* on create this may be null */
+
+ /* Restore the truncated pathname buffer (for audits). */
+ if (ndp->ni_pathlen == 1 && ndp->ni_next[0] == '\0') {
+ ndp->ni_next[0] = '/';
+ }
+ cnp->cn_flags &= ~MAKEENTRY;
+
+ return 0;
+out:
+ return error;
+}
+#endif /* NAMEDRSRCFORK */
+
+/*
+ * iocounts in:
+ * --One on ni_vp. One on ni_dvp if there is more path, or we didn't come through the
+ * cache, or we came through the cache and the caller doesn't want the parent.
+ *
+ * iocounts out:
+ * --Leaves us in the correct state for the next step, whatever that might be.
+ * --If we find a symlink, returns with iocounts on both ni_vp and ni_dvp.
+ * --If we are to look up another component, then we have an iocount on ni_vp and
+ * nothing else.
+ * --If we are done, returns an iocount on ni_vp, and possibly on ni_dvp depending on nameidata flags.
+ * --In the event of an error, may return with ni_dvp NULL'ed out (in which case, iocount
+ * was dropped).
+ */
+static int
+lookup_handle_found_vnode(struct nameidata *ndp, struct componentname *cnp, int rdonly,
+ int vbusyflags, int *keep_going, int nc_generation,
+ int wantparent, int atroot, vfs_context_t ctx)
+{
+ vnode_t dp;
+ int error;
+ char *cp;
+
+ dp = ndp->ni_vp;
+ *keep_going = 0;
+
+ if (ndp->ni_vp == NULLVP) {
+ panic("NULL ni_vp in %s\n", __FUNCTION__);
+ }
+
+ if (atroot) {
+ goto nextname;
+ }
+
+ /*
+ * Take into account any additional components consumed by
+ * the underlying filesystem.
+ */
+ if (cnp->cn_consume > 0) {
+ cnp->cn_nameptr += cnp->cn_consume;
+ ndp->ni_next += cnp->cn_consume;
+ ndp->ni_pathlen -= cnp->cn_consume;
+ cnp->cn_consume = 0;
+ } else {
+ lookup_consider_update_cache(ndp->ni_dvp, dp, cnp, nc_generation);
+ }
+
+ /*
+ * Check to see if the vnode has been mounted on...
+ * if so find the root of the mounted file system.
+ * Updates ndp->ni_vp.
+ */
+ error = lookup_traverse_mountpoints(ndp, cnp, dp, vbusyflags, ctx);
+ dp = ndp->ni_vp;
+ if (error) {
+ goto out;
+ }
+
+#if CONFIG_MACF
+ if (vfs_flags(vnode_mount(dp)) & MNT_MULTILABEL) {
+ error = vnode_label(vnode_mount(dp), NULL, dp, NULL, 0, ctx);
+ if (error)
+ goto out;
+ }
+#endif
+
+ /*
+ * Check for symbolic link
+ */
+ if ((dp->v_type == VLNK) &&
+ ((cnp->cn_flags & FOLLOW) || (ndp->ni_flag & NAMEI_TRAILINGSLASH) || *ndp->ni_next == '/')) {
+ cnp->cn_flags |= ISSYMLINK;
+ *keep_going = 1;
+ return (0);
+ }
+
+ /*
+ * Check for bogus trailing slashes.
+ */
+ if ((ndp->ni_flag & NAMEI_TRAILINGSLASH)) {
+ if (dp->v_type != VDIR) {
+ error = ENOTDIR;
+ goto out;
+ }
+ ndp->ni_flag &= ~(NAMEI_TRAILINGSLASH);
+ }
+
+#if NAMEDSTREAMS
+ /*
+ * Deny namei/lookup requests to resolve paths that point to shadow files.
+ * Access to shadow files must be conducted by explicit calls to VNOP_LOOKUP
+ * directly, and not use lookup/namei
+ */
+ if (vnode_isshadow (dp)) {
+ error = ENOENT;
+ goto out;
+ }
+#endif
+
+nextname:
+ /*
+ * Not a symbolic link. If more pathname,
+ * continue at next component, else return.
+ *
+ * Definitely have a dvp if there's another slash
+ */
+ if (*ndp->ni_next == '/') {
+ cnp->cn_nameptr = ndp->ni_next + 1;
+ ndp->ni_pathlen--;
+ while (*cnp->cn_nameptr == '/') {
+ cnp->cn_nameptr++;
+ ndp->ni_pathlen--;
+ }
+
+ cp = cnp->cn_nameptr;
+ vnode_put(ndp->ni_dvp);
+ ndp->ni_dvp = NULLVP;
+
+ if (*cp == '\0') {
+ goto emptyname;
+ }
+
+ *keep_going = 1;
+ return 0;
+ }
+
+ /*
+ * Disallow directory write attempts on read-only file systems.
+ */
+ if (rdonly &&
+ (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
+ error = EROFS;
+ goto out;
+ }
+
+ /* If SAVESTART is set, we should have a dvp */
+ if (cnp->cn_flags & SAVESTART) {
+ /*
+ * note that we already hold a reference
+ * on both dp and ni_dvp, but for some reason
+ * can't get another one... in this case we
+ * need to do vnode_put on dp in 'bad2'
+ */
+ if ( (vnode_get(ndp->ni_dvp)) ) {
+ error = ENOENT;
+ goto out;
+ }
+ ndp->ni_startdir = ndp->ni_dvp;
+ }
+ if (!wantparent && ndp->ni_dvp) {
+ vnode_put(ndp->ni_dvp);
+ ndp->ni_dvp = NULLVP;
+ }
+
+ if (cnp->cn_flags & AUDITVNPATH1)
+ AUDIT_ARG(vnpath, dp, ARG_VNODE1);
+ else if (cnp->cn_flags & AUDITVNPATH2)
+ AUDIT_ARG(vnpath, dp, ARG_VNODE2);
+
+#if NAMEDRSRCFORK
+ /*
+ * Caller wants the resource fork.
+ */
+ if ((cnp->cn_flags & CN_WANTSRSRCFORK) && (dp != NULLVP)) {
+ error = lookup_handle_rsrc_fork(dp, ndp, cnp, wantparent, ctx);
+ if (error != 0)
+ goto out;