- if ((dp->i_mode & IFMT) == IFLNK && (follow || *cp == '/')) {
- pathlen = strlen(cp) + 1;
- if (dp->i_size + pathlen >= MAXPATHLEN - 1 ||
- ++nlink > MAXSYMLINKS) {
- u.u_error = ELOOP;
- irele(pdp);
- iput(dp);
- brelse(nbp);
- return (NULL);
- }
- bcopy(cp, nbp->b_un.b_addr + dp->i_size, pathlen);
- bn = bmap(dp, (daddr_t)0, B_READ);
- if (bn < 0) {
- printf("hole in symlink: %s i = %d\n",
- fs->fs_fsmnt, dp->i_number);
- irele(pdp);
- iput(dp);
- brelse(nbp);
- return (NULL);
- }
- bp = bread(dp->i_dev, fsbtodb(fs, bn),
- (int)blksize(fs, dp, (daddr_t)0));
- if (bp->b_flags & B_ERROR) {
- brelse(bp);
- irele(pdp);
+ 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; 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.
+ * Note that in this case we return the directory
+ * inode, not the inode of the file being deleted.
+ */
+ if (flag == 2 && *cp == 0) {
+ /*
+ * Write access to directory required to delete files.
+ */
+ if (access(dp, IWRITE))
+ goto bad;
+ /*
+ * 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;
+ brelse(nbp);
+ u.u_pdir = dp; /* for dirremove() */
+ 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) {