+
+
+/*
+ * relookup - lookup a path name component
+ * Used by lookup to re-aquire things.
+ */
+int
+relookup(dvp, vpp, cnp) /* converted to CN */
+ struct vnode *dvp, **vpp;
+ struct componentname *cnp;
+{
+ register char *cp; /* pointer into pathname argument */
+ register struct vnode *dp = 0; /* the directory we are searching */
+ struct vnode *tdp; /* saved dp */
+ struct mount *mp; /* mount table entry */
+ int docache; /* == 0 do not cache last component */
+ int wantparent; /* 1 => wantparent or lockparent flag */
+ int rdonly; /* lookup read-only flag bit */
+ int error = 0;
+ int newhash;
+
+ /*
+ * Setup: break out flag bits into variables.
+ */
+ wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
+ docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
+ if (cnp->cn_nameiop == DELETE || (wantparent && cnp->cn_nameiop != CREATE))
+ docache = 0;
+ rdonly = cnp->cn_flags & RDONLY;
+ cnp->cn_flags &= ~ISSYMLINK;
+ dp = dvp;
+ VOP_LOCK(dp);
+
+/* dirloop: */
+ /*
+ * Search a new directory.
+ *
+ * The cn_hash value is for use by vfs_cache.
+ * The last component of the filename is left accessible via
+ * cnp->cn_nameptr for callers that need the name. Callers needing
+ * the name set the SAVENAME flag. When done, they assume
+ * responsibility for freeing the pathname buffer.
+ */
+/* NEEDWORK: is hash computed needed */
+ newhash = 0;
+ for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++)
+ newhash += (unsigned char)*cp;
+ if (newhash != cnp->cn_hash)
+ panic("relookup: bad hash");
+ if (cnp->cn_namelen != cp - cnp->cn_nameptr)
+ panic ("relookup: bad len");
+ if (cnp->cn_namelen >= NAME_MAX) {
+ error = ENAMETOOLONG;
+ goto bad;
+ }
+#ifdef NAMEI_DIAGNOSTIC /* NEEDSWORK: should go */
+ { char c = *cp;
+ *cp = '\0';
+ printf("{%s}: ", cnp->cn_nameptr);
+ *cp = c; }
+#endif
+#if 0
+ cnp->cn_pathlen -= cnp->cn_namelen;
+ ndp->ni_next = cp;
+#endif
+#if 0
+ cnp->cn_flags |= MAKEENTRY;
+ if (*cp == '\0' && docache == 0)
+ cnp->cn_flags &= ~MAKEENTRY;
+ if (cnp->cn_namelen == 2 &&
+ cnp->ni_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
+ cnp->cn_flags |= ISDOTDOT;
+ else cnp->cn_flags &= ~ISDOTDOT;
+#endif
+
+ /*
+ * Check for degenerate name (e.g. / or "")
+ * which is a way of talking about a directory,
+ * e.g. like "/." or ".".
+ */
+ if (cnp->cn_nameptr[0] == '\0') {
+ if (cnp->cn_nameiop != LOOKUP || wantparent) {
+ error = EISDIR;
+ goto bad;
+ }
+ if (dp->v_type != VDIR) {
+ error = ENOTDIR;
+ goto bad;
+ }
+ if (!(cnp->cn_flags & LOCKLEAF))
+ VOP_UNLOCK(dp);
+ *vpp = dp;
+ if (cnp->cn_flags & SAVESTART)
+ panic("lookup: SAVESTART");
+ return (0);
+ }
+
+ /*
+ * Handle "..": two special cases.
+ * 1. If at root directory (e.g. after chroot)
+ * then ignore it so can't get out.
+ * 2. If this vnode is the root of a mounted
+ * filesystem, then replace it with the
+ * vnode which was mounted on so we take the
+ * .. in the other file system.
+ */
+#if 0
+ /* This shouldn't happen because rename throws out .. */
+ /* NEEDSWORK: what to do about this? */
+ if (cnp->cn_flags & ISDOTDOT) {
+ for (;;) {
+ if (dp == ndp->ni_rootdir) {
+ ndp->ni_dvp = dp;
+ ndp->ni_vp = dp;
+ VREF(dp);
+ goto nextname;
+ }
+ if ((dp->v_flag & VROOT) == 0 ||
+ (cnp->cn_flags & NOCROSSMOUNT))
+ break;
+ tdp = dp;
+ dp = dp->v_mount->mnt_vnodecovered;
+ vput(tdp);
+ VREF(dp);
+ VOP_LOCK(dp);
+ }
+ }
+#endif
+ if (cnp->cn_flags & ISDOTDOT)
+ panic ("relookup: lookup on dot-dot");
+
+ /*
+ * We now have a segment name to search for, and a directory to search.
+ */
+ if (error = VOP_LOOKUP(dp, vpp, cnp)) {
+#ifdef DIAGNOSTIC
+ if (*vpp != NULL)
+ panic("leaf should be empty");
+#endif
+#ifdef NAMEI_DIAGNOSTIC
+ printf("not found\n");
+#endif
+ if (cnp->cn_nameiop == LOOKUP || cnp->cn_nameiop == DELETE ||
+ error != ENOENT || *cp != 0)
+ goto bad;
+ /*
+ * If creating and at end of pathname, then can consider
+ * allowing file to be created.
+ */
+ if (rdonly || (dvp->v_mount->mnt_flag & MNT_RDONLY)) {
+ error = EROFS;
+ goto bad;
+ }
+ /*
+ * We return with ni_vp NULL to indicate that the entry
+ * doesn't currently exist, leaving a pointer to the
+ * (possibly locked) directory inode in ndp->ni_dvp.
+ */
+#ifdef JOHNH
+ /*
+ * no need because we don't need to do another lookup.
+ * NEEDSWORK: don't do release.
+ * but wait...let's try it a different way.
+ */
+ if (cnp->cn_flags & SAVESTART) {
+#if 0
+ ndp->ni_startdir = ndp->ni_dvp;
+ VREF(ndp->ni_startdir);
+#else
+ /*
+ * startdir == dvp, always
+ */
+ VREF(dvp);
+#endif
+ }
+#endif
+ return (0);
+ }
+#ifdef NAMEI_DIAGNOSTIC
+ printf("found\n");
+#endif
+
+ dp = *vpp;
+ /*
+ * Check for symbolic link
+ */
+#if 0
+ if ((dp->v_type == VLNK) &&
+ ((cnp->cn_flags & FOLLOW) || *ndp->ni_next == '/')) {
+ cnp->cn_flags |= ISSYMLINK;
+ return (0);
+ }
+#endif
+ if (dp->v_type == VLNK) {
+ panic ("relookup: symlink found.\n");
+ };
+
+ /*
+ * Check to see if the vnode has been mounted on;
+ * if so find the root of the mounted file system.
+ */
+#if 0
+ /* NEEDSWORK: mounts should not be crossed in cnlookup */
+ /*
+ * Checked for in rename (returns EXDEV).
+ */
+mntloop:
+ while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
+ (cnp->cn_flags & NOCROSSMOUNT) == 0) {
+ if (mp->mnt_flag & MNT_MLOCK) {
+ mp->mnt_flag |= MNT_MWAIT;
+ sleep((caddr_t)mp, PVFS);
+ goto mntloop;
+ }
+ if (error = VFS_ROOT(dp->v_mountedhere, &tdp))
+ goto bad2;
+ vput(dp);
+ ndp->ni_vp = dp = tdp;
+ }
+#endif
+ if (dp->v_type == VDIR && (dp->v_mountedhere))
+ panic ("relookup: mount point encountered.");
+
+
+nextname:
+ /*
+ * Not a symbolic link. If more pathname,
+ * continue at next component, else return.
+ */
+#if 0
+ if (*ndp->ni_next == '/') {
+ cnp->cn_nameptr = ndp->ni_next;
+ while (*cnp->cn_nameptr == '/') {
+ ndp->ni_nameptr++;
+ ndp->ni_pathlen--;
+ }
+ vrele(ndp->ni_dvp);
+ goto dirloop;
+ }
+#endif
+
+ /*
+ * Check for read-only file systems.
+ */
+ if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) {
+ /*
+ * Disallow directory write attempts on read-only
+ * file systems.
+ */
+ if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) ||
+ (wantparent &&
+ (dvp->v_mount->mnt_flag & MNT_RDONLY))) {
+ error = EROFS;
+ goto bad2;
+ }
+ }
+ if (cnp->cn_flags & SAVESTART) {
+#if 0
+ ndp->ni_startdir = ndp->ni_dvp;
+ VREF(ndp->ni_startdir);
+#endif
+ /* ASSERT(dvp==ndp->ni_startdir) */
+ VREF(dvp);
+ }
+
+ if (!wantparent)
+ vrele(dvp);
+ if ((cnp->cn_flags & LOCKLEAF) == 0)
+ VOP_UNLOCK(dp);
+ return (0);
+
+bad2:
+ if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
+ VOP_UNLOCK(dvp);
+ vrele(dvp);
+bad:
+ vput(dp);
+ *vpp = NULL;
+ return (error);
+}
+
+