- if (dp == u.u_rdir && u.u_dbuf[0] == '.' &&
- u.u_dbuf[1] == '.' && u.u_dbuf[2] == 0)
- goto cloop;
-
-eloop:
-
- /*
- * If at the end of the directory,
- * the search failed. Report what
- * is appropriate as per flag.
- */
-
- if(u.u_offset >= dp->i_size) {
- if(bp != NULL)
- brelse(bp);
- if(flag==1 && c=='\0' && dp->i_nlink) {
- if(access(dp, IWRITE))
- goto out;
- u.u_pdir = dp;
- if(eo)
- u.u_offset = eo-sizeof(struct direct);
- else
- dp->i_flag |= IUPD|ICHG;
- return(NULL);
- }
- u.u_error = ENOENT;
- goto out;
- }
-
- /*
- * If offset is on a block boundary,
- * read the next directory block.
- * Release previous if it exists.
- */
-
- if((u.u_offset&BMASK) == 0) {
- if(bp != NULL)
- brelse(bp);
- bp = bread(dp->i_dev,
- bmap(dp, (daddr_t)(u.u_offset>>BSHIFT), B_READ));
- if (bp->b_flags & B_ERROR) {
+ spccnt = 0;
+ loc = 0;
+ while (u.u_offset < dp->i_size) {
+ /*
+ * check to see if enough space has been accumulated to make
+ * an entry by compaction. Reset the free space counter each
+ * time a directory block is crossed.
+ */
+ if (slot == NONE) {
+ if (spccnt >= newsize) {
+ slot = COMPACT;
+ entrysize = u.u_offset - entryfree;
+ } else if (loc % DIRBLKSIZ == 0) {
+ entryfree = NULL;
+ spccnt = 0;
+ }
+ }
+ /*
+ * If offset is on a block boundary,
+ * read the next directory block.
+ * Release previous if it exists.
+ */
+ if (blkoff(fs, u.u_offset) == 0) {
+ if (bp != NULL)
+ brelse(bp);
+ lbn = (daddr_t)lblkno(fs, u.u_offset);
+ bsize = blksize(fs, dp, lbn);
+ if ((bn = bmap(dp, lbn, B_READ)) < 0) {
+ printf("hole in dir: %s i = %d\n",
+ fs->fs_fsmnt, dp->i_number);
+ if (fs->fs_ronly != 0 ||
+ (bn = bmap(dp, lbn, B_WRITE, bsize)) < 0) {
+ u.u_offset += bsize;
+ bp = NULL;
+ continue;
+ }
+ }
+ bp = bread(dp->i_dev, fsbtodb(fs, bn), bsize);
+ if (bp->b_flags & B_ERROR) {
+ brelse(bp);
+ iput(dp);
+ brelse(nbp);
+ return (NULL);
+ }
+ loc = 0;
+ } else {
+ loc += ep->d_reclen;
+ }
+ /*
+ * calculate the next directory entry and run
+ * some rudimentary bounds checks to make sure
+ * that it is reasonable. If the check fails
+ * resync at the beginning of the next directory
+ * block.
+ */
+ ep = (struct direct *)(bp->b_un.b_addr + loc);
+ i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1));
+ if (ep->d_reclen <= 0 || ep->d_reclen > i) {
+ loc += i;
+ u.u_offset += i;
+ continue;
+ }
+ /*
+ * If an appropriate sized hole has not yet been found,
+ * check to see if one is available. Also accumulate space
+ * in the current block so that we can determine if
+ * compaction is viable.
+ */
+ if (slot != FOUND) {
+ size = ep->d_reclen;
+ if (ep->d_ino != 0)
+ size -= DIRSIZ(ep);
+ if (size > 0) {
+ if (size >= newsize) {
+ slot = FOUND;
+ entryfree = u.u_offset;
+ entrysize = DIRSIZ(ep) + newsize;
+ }
+ if (entryfree == NULL)
+ entryfree = u.u_offset;
+ spccnt += size;
+ }
+ }
+ /*
+ * String compare the directory entry
+ * and the current component.
+ * If they do not match, continue to the next entry.
+ */
+ prevoff = curoff;
+ curoff = u.u_offset;
+ u.u_offset += ep->d_reclen;
+ if (ep->d_ino == 0)
+ continue;
+ if (ep->d_namlen != u.u_dent.d_namlen)
+ continue;
+ if (bcmp(u.u_dent.d_name, ep->d_name, ep->d_namlen))
+ continue;
+ /*
+ * Here a component matched in a directory.
+ * If there is more pathname, go back to
+ * dirloop, otherwise return.
+ */
+ bcopy((caddr_t)ep, (caddr_t)&u.u_dent, DIRSIZ(ep));
+ brelse(bp);
+ if (flag == 2 && *cp == '\0') {
+ brelse(nbp);
+ if (access(dp, IWRITE)) {
+ iput(dp);
+ return (NULL);
+ }
+ if (curoff % DIRBLKSIZ == 0) {
+ u.u_offset = curoff;
+ u.u_count = 0;
+ return (dp);
+ }
+ u.u_offset = prevoff;
+ u.u_count = DIRSIZ((struct direct *)
+ (bp->b_un.b_addr + blkoff(fs, prevoff)));
+ return (dp);
+ }
+ /*
+ * Special handling for ".."
+ */
+ 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;
+ ilock(dp);
+ dp->i_count++;
+ fs = dp->i_fs;
+ cp -= 2; /* back over .. */
+ goto dirloop2;
+ }
+ }
+ }
+ d = dp->i_dev;
+ pdp = dp;
+ iunlock(pdp);
+ dp = iget(d, fs, u.u_dent.d_ino);
+ if (dp == NULL) {
+ irele(pdp);
+ brelse(nbp);
+ return (NULL);
+ }
+ fs = dp->i_fs;
+ /*
+ * Check for symbolic link
+ */
+ 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);
+ iput(dp);
+ brelse(nbp);
+ return (NULL);
+ }
+ bcopy(bp->b_un.b_addr, nbp->b_un.b_addr,
+ (unsigned)dp->i_size);