- u.u_error = error;
- goto bad;
- }
-
- /*
- * Get starting directory.
- */
- cp = nbp->b_un.b_addr;
- if (*cp == '/') {
- while (*cp == '/')
- cp++;
- if ((dp = u.u_rdir) == NULL)
- dp = rootdir;
- } else
- dp = u.u_cdir;
- fs = dp->i_fs;
- ILOCK(dp);
- dp->i_count++;
- ndp->ni_pdir = (struct inode *)0xc0000000; /* illegal */
-
- /*
- * We come to dirloop to search a new directory.
- * The directory must be locked so that it can be
- * iput, and fs must be already set to dp->i_fs.
- */
-dirloop:
- /*
- * Check accessiblity of directory.
- */
- if ((dp->i_mode&IFMT) != IFDIR) {
- u.u_error = ENOTDIR;
- goto bad;
- }
- if (access(dp, IEXEC))
- goto bad;
-
-dirloop2:
- /*
- * Copy next component of name to ndp->ni_dent.
- */
- hash = 0;
- for (i = 0; *cp != 0 && *cp != '/'; cp++) {
- if (i >= MAXNAMLEN) {
- u.u_error = ENOENT;
- goto bad;
- }
- if ((*cp&0377) == ('/'|0200) || (*cp&0200) && flag != DELETE) {
- u.u_error = EPERM;
- goto bad;
- }
- ndp->ni_dent.d_name[i++] = *cp;
- hash += (unsigned char)*cp * i;
- }
- ndp->ni_dent.d_namlen = i;
- ndp->ni_dent.d_name[i] = '\0';
- isdotdot = (i == 2 &&
- ndp->ni_dent.d_name[0] == '.' && ndp->ni_dent.d_name[1] == '.');
-
- /*
- * Check for degenerate name (e.g. / or "")
- * which is a way of talking about a directory,
- * e.g. like "/." or ".".
- */
- if (ndp->ni_dent.d_name[0] == '\0') {
- if (flag != LOOKUP || lockparent) {
- u.u_error = EISDIR;
- goto bad;
- }
- nbp->av_forw = freenamebuf;
- freenamebuf = nbp;
- return (dp);
- }
-
- /*
- * We now have a segment name to search for, and a directory to search.
- *
- * Before tediously performing a linear scan of the directory,
- * check the name cache to see if the directory/name pair
- * we are looking for is known already. We don't do this
- * if the segment name is long, simply so the cache can avoid
- * holding long names (which would either waste space, or
- * add greatly to the complexity).
- */
- if (ndp->ni_dent.d_namlen > NCHNAMLEN) {
- nchstats.ncs_long++;
- docache = 0;
- } else {
- nhp = &nchash[NHASH(hash, dp->i_number, dp->i_dev)];
- for (ncp = nhp->nch_forw; ncp != (struct nch *)nhp;
- ncp = ncp->nc_forw) {
- if (ncp->nc_ino == dp->i_number &&
- ncp->nc_dev == dp->i_dev &&
- ncp->nc_nlen == ndp->ni_dent.d_namlen &&
- !bcmp(ncp->nc_name, ndp->ni_dent.d_name,
- ncp->nc_nlen))
- break;
- }
-
- if (ncp == (struct nch *)nhp) {
- nchstats.ncs_miss++;
- ncp = NULL;
- } else {
- if (ncp->nc_id != ncp->nc_ip->i_id) {
- nchstats.ncs_falsehits++;
- } else if (*cp == '\0' && !docache) {
- nchstats.ncs_badhits++;
- } else {
-
- /*
- * move this slot to end of LRU
- * chain, if not already there
- */
- if (ncp->nc_nxt) {
- /* remove from LRU chain */
- *ncp->nc_prev = ncp->nc_nxt;
- ncp->nc_nxt->nc_prev = ncp->nc_prev;
-
- /* and replace at end of it */
- ncp->nc_nxt = NULL;
- ncp->nc_prev = nchtail;
- *nchtail = ncp;
- nchtail = &ncp->nc_nxt;
- }
-
- /*
- * Get the next inode in the path.
- * See comment above other `IUNLOCK' code for
- * an explaination of the locking protocol.
- */
- pdp = dp;
- dp = ncp->nc_ip;
- if (dp == NULL)
- panic("nami: null cache ino");
- if (pdp == dp)
- dp->i_count++;
- else {
- if (isdotdot) {
- IUNLOCK(pdp);
- igrab(dp);
- } else {
- igrab(dp);
- IUNLOCK(pdp);
- }
- }
-
- /*
- * Verify that the inode that we got
- * did not change while we were waiting
- * for it to be locked.
- */
- if (ncp->nc_id != ncp->nc_ip->i_id) {
- iput(dp);
- ILOCK(pdp);
- dp = pdp;
- nchstats.ncs_falsehits++;
- } else {
- ndp->ni_dent.d_ino = dp->i_number;
- /* ni_dent.d_reclen is garbage ... */
- nchstats.ncs_goodhits++;
- goto haveino;
- }
- }
-
- /*
- * 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;
-
- /* remove from hash chain */
- remque(ncp);
-
- /* 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;
- }