-
- /*
- * Last component and we are renaming or deleting,
- * the cache entry is invalid, or otherwise don't
- * want cache entry to exist.
- */
- /* remove from LRU chain */
- *ncp->nc_prev = ncp->nc_nxt;
- if (ncp->nc_nxt)
- ncp->nc_nxt->nc_prev = ncp->nc_prev;
- else
- nchtail = ncp->nc_prev;
- remque(ncp); /* remove from hash chain */
- /* insert at head of LRU list (first to grab) */
- ncp->nc_nxt = nchhead;
- ncp->nc_prev = &nchhead;
- nchhead->nc_prev = &ncp->nc_nxt;
- nchhead = ncp;
- /* and make a dummy hash chain */
- ncp->nc_forw = ncp;
- ncp->nc_back = ncp;
- ncp = NULL;
- }
- }
-
- /*
- * Suppress search for slots unless creating
- * file and at end of pathname, in which case
- * we watch for a place to put the new file in
- * case it doesn't already exist.
- */
- slotstatus = FOUND;
- if (flag == CREATE && *cp == 0) {
- slotstatus = NONE;
- slotfreespace = 0;
- slotneeded = DIRSIZ(&ndp->ni_dent);
- }
- /*
- * If this is the same directory that this process
- * previously searched, pick up where we last left off.
- * We cache only lookups as these are the most common
- * and have the greatest payoff. Caching CREATE has little
- * benefit as it usually must search the entire directory
- * to determine that the entry does not exist. Caching the
- * location of the last DELETE has not reduced profiling time
- * and hence has been removed in the interest of simplicity.
- */
- if (flag != LOOKUP || dp->i_number != u.u_ncache.nc_inumber ||
- dp->i_dev != u.u_ncache.nc_dev) {
- ndp->ni_offset = 0;
- numdirpasses = 1;
- } else {
- if (u.u_ncache.nc_prevoffset > dp->i_size)
- u.u_ncache.nc_prevoffset = 0;
- ndp->ni_offset = u.u_ncache.nc_prevoffset;
- entryoffsetinblock = blkoff(fs, ndp->ni_offset);
- if (entryoffsetinblock != 0) {
- bp = blkatoff(dp, ndp->ni_offset, (char **)0);
- if (bp == 0)
- goto bad;
- }
- numdirpasses = 2;
- nchstats.ncs_2passes++;
- }
- endsearch = roundup(dp->i_size, DIRBLKSIZ);
- enduseful = 0;
-
-searchloop:
- while (ndp->ni_offset < endsearch) {
- /*
- * If offset is on a block boundary,
- * read the next directory block.
- * Release previous if it exists.
- */
- if (blkoff(fs, ndp->ni_offset) == 0) {
- if (bp != NULL)
- brelse(bp);
- bp = blkatoff(dp, ndp->ni_offset, (char **)0);
- if (bp == 0)
- goto bad;
- entryoffsetinblock = 0;
- }
- /*
- * If still looking for a slot, and at a DIRBLKSIZE
- * boundary, have to start looking for free space again.
- */
- if (slotstatus == NONE &&
- (entryoffsetinblock&(DIRBLKSIZ-1)) == 0) {
- slotoffset = -1;
- slotfreespace = 0;
- }
- /*
- * Get pointer to next entry.
- * Full validation checks are slow, so we only check
- * enough to insure forward progress through the
- * directory. Complete checks can be run by patching
- * "dirchk" to be true.
- */
- ep = (struct direct *)(bp->b_un.b_addr + entryoffsetinblock);
- if (ep->d_reclen == 0 ||
- dirchk && dirbadentry(ep, entryoffsetinblock)) {
- dirbad(dp, ndp->ni_offset, "mangled entry");
- i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1));
- ndp->ni_offset += i;
- entryoffsetinblock += i;
- continue;
- }
-
- /*
- * If an appropriate sized slot 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 (slotstatus != FOUND) {
- int size = ep->d_reclen;
-
- if (ep->d_ino != 0)
- size -= DIRSIZ(ep);
- if (size > 0) {
- if (size >= slotneeded) {
- slotstatus = FOUND;
- slotoffset = ndp->ni_offset;
- slotsize = ep->d_reclen;
- } else if (slotstatus == NONE) {
- slotfreespace += size;
- if (slotoffset == -1)
- slotoffset = ndp->ni_offset;
- if (slotfreespace >= slotneeded) {
- slotstatus = COMPACT;
- slotsize = ndp->ni_offset +
- ep->d_reclen - slotoffset;
- }
- }
- }
- }
-
- /*
- * Check for a name match.
- */
- if (ep->d_ino) {
- if (ep->d_namlen == ndp->ni_dent.d_namlen &&
- !bcmp(ndp->ni_dent.d_name, ep->d_name,
- (unsigned)ep->d_namlen))
- goto found;
- }
- prevoff = ndp->ni_offset;
- ndp->ni_offset += ep->d_reclen;
- entryoffsetinblock += ep->d_reclen;
- if (ep->d_ino)
- enduseful = ndp->ni_offset;
- }
-/* notfound: */
- /*
- * If we started in the middle of the directory and failed
- * to find our target, we must check the beginning as well.
- */
- if (numdirpasses == 2) {
- numdirpasses--;
- ndp->ni_offset = 0;
- endsearch = u.u_ncache.nc_prevoffset;
- goto searchloop;
- }
- /*
- * If creating, and at end of pathname and current
- * directory has not been removed, then can consider
- * allowing file to be created.
- */
- if (flag == CREATE && *cp == 0 && dp->i_nlink != 0) {
- /*
- * Access for write is interpreted as allowing
- * creation of files in the directory.
- */
- if (access(dp, IWRITE))
- goto bad;
- /*
- * Return an indication of where the new directory
- * entry should be put. If we didn't find a slot,
- * then set ndp->ni_count to 0 indicating that the new
- * slot belongs at the end of the directory. If we found
- * a slot, then the new entry can be put in the range
- * [ndp->ni_offset .. ndp->ni_offset + ndp->ni_count)
- */
- if (slotstatus == NONE) {
- ndp->ni_offset = roundup(dp->i_size, DIRBLKSIZ);
- ndp->ni_count = 0;
- enduseful = ndp->ni_offset;
- } else {
- ndp->ni_offset = slotoffset;
- ndp->ni_count = slotsize;
- if (enduseful < slotoffset + slotsize)
- enduseful = slotoffset + slotsize;