+ brelse(nbp);
+ /*
+ * We return with the directory locked, so that
+ * the parameters we set up above will still be
+ * valid if we actually decide to do a direnter().
+ * We return NULL to indicate that the entry doesn't
+ * currently exist, leaving a pointer to the (locked)
+ * directory inode in u.u_pdir.
+ */
+ u.u_pdir = dp;
+ return (NULL);
+ }
+ u.u_error = ENOENT;
+ goto bad;
+found:
+ /*
+ * Check that directory length properly reflects presence
+ * of this entry.
+ */
+ if (entryoffsetinblock + DIRSIZ(ep) > dp->i_size) {
+ dirbad(dp, "i_size too small");
+ dp->i_size = entryoffsetinblock + DIRSIZ(ep);
+ dp->i_flag |= IUPD|ICHG;
+ }
+
+ /*
+ * Found component in pathname.
+ * If final component of path name, save information
+ * in the cache as to where the entry was found.
+ */
+ if (*cp == '\0' && flag == LOOKUP) {
+ u.u_ncache.nc_prevoffset = u.u_offset;
+ u.u_ncache.nc_inumber = dp->i_number;
+ u.u_ncache.nc_dev = dp->i_dev;
+ u.u_ncache.nc_time = time.tv_sec;
+ }
+ /*
+ * Save directory entry in u.u_dent,
+ * and release directory buffer.
+ */
+ bcopy((caddr_t)ep, (caddr_t)&u.u_dent, (u_int)DIRSIZ(ep));
+ brelse(bp);
+ bp = NULL;
+
+ /*
+ * If deleting, and at end of pathname, return
+ * parameters which can be used to remove file.
+ * If the lockparent flag isn't set, we return only
+ * the directory (in u.u_pdir), otherwise we go
+ * on and lock the inode, being careful with ".".
+ */
+ if (flag == DELETE && *cp == 0) {
+ /*
+ * Write access to directory required to delete files.
+ */
+ if (access(dp, IWRITE))
+ goto bad;
+ u.u_pdir = dp; /* for dirremove() */
+ /*
+ * Return pointer to current entry in u.u_offset,
+ * and distance past previous entry (if there
+ * is a previous entry in this block) in u.u_count.
+ * Save directory inode pointer in u.u_pdir for dirremove().
+ */
+ if ((u.u_offset&(DIRBLKSIZ-1)) == 0)
+ u.u_count = 0;
+ else
+ u.u_count = u.u_offset - prevoff;
+ if (lockparent) {
+ if (dp->i_number == u.u_dent.d_ino)
+ dp->i_count++;
+ else {
+ dp = iget(dp->i_dev, fs, u.u_dent.d_ino);
+ if (dp == NULL) {
+ iput(u.u_pdir);
+ goto bad;
+ }
+ }
+ }
+ brelse(nbp);
+ return (dp);
+ }
+
+ /*
+ * Special handling for ".." allowing chdir out of mounted
+ * file system: indirect .. in root inode to reevaluate
+ * in directory file system was mounted on.
+ */
+ if (u.u_dent.d_name[0] == '.' && u.u_dent.d_name[1] == '.' &&
+ u.u_dent.d_name[2] == '\0') {
+ if (dp == u.u_rdir)
+ u.u_dent.d_ino = dp->i_number;
+ else if (u.u_dent.d_ino == ROOTINO &&
+ dp->i_number == ROOTINO) {
+ for (i = 1; i < NMOUNT; i++)
+ if (mount[i].m_bufp != NULL &&
+ mount[i].m_dev == dp->i_dev) {
+ iput(dp);
+ dp = mount[i].m_inodp;