X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/085641d726105e14354fb72643aaacfc0f2266ba..4a404244ad5a6e8679d302ed44ecc61cac172725:/usr/src/sys/kern/vfs_lookup.c diff --git a/usr/src/sys/kern/vfs_lookup.c b/usr/src/sys/kern/vfs_lookup.c index d0e6431729..c861d1a563 100644 --- a/usr/src/sys/kern/vfs_lookup.c +++ b/usr/src/sys/kern/vfs_lookup.c @@ -1,8 +1,11 @@ -/* vfs_lookup.c 4.6 81/04/28 */ +/* vfs_lookup.c 4.15 82/04/19 */ + +/* merged into kernel: @(#)nami.c 2.3 4/8/82 */ #include "../h/param.h" #include "../h/systm.h" #include "../h/inode.h" +#include "../h/fs.h" #include "../h/mount.h" #include "../h/dir.h" #include "../h/user.h" @@ -11,7 +14,7 @@ /* * Convert a pathname into a pointer to - * an inode. Note that the inode is locked. + * a locked inode. * * func = function called to get next char of name * &uchar if name is in user space @@ -19,208 +22,365 @@ * flag = 0 if name is sought * 1 if name is to be created * 2 if name is to be deleted + * follow = 1 if links are to be followed at the end of the name */ struct inode * -namei(func, flag) -int (*func)(); +namei(func, flag, follow) + int (*func)(), flag, follow; { register struct inode *dp; - register c; register char *cp; - struct buf *bp; + register struct buf *bp, *nbp; register struct direct *ep; - int i; + register struct fs *fs; + struct inode *pdp; + enum {NONE, COMPACT, FOUND} slot; + int entryfree, entrysize; + int spccnt, size, newsize; + int loc, prevoff, curoff; + int i, nlink, bsize; + unsigned pathlen; + daddr_t lbn, bn; dev_t d; - off_t eo; -#ifdef CHAOS - extern long cdevpath; -#endif + /* + * allocate name buffer; copy name + */ + nbp = geteblk(MAXPATHLEN); + nlink = 0; + for (i = 0, cp = nbp->b_un.b_addr; *cp = (*func)(); i++) { + if ((*cp & 0377) == ('/'|0200)) { + u.u_error = EPERM; + break; + } +#ifdef notdef + if (*cp++ & 0200 && flag == 1 || + cp >= nbp->b_un.b_addr + MAXPATHLEN) { +#else + cp++; + if (cp >= nbp->b_un.b_addr + MAXPATHLEN) { +#endif + u.u_error = ENOENT; + break; + } + } + if (u.u_error) { + brelse(nbp); + return (NULL); + } + cp = nbp->b_un.b_addr; /* * If name starts with '/' start from * root; otherwise start from current dir. */ - dp = u.u_cdir; - if((c=(*func)()) == '/') + if (*cp == '/') { + while (*cp == '/') + cp++; if ((dp = u.u_rdir) == NULL) dp = rootdir; - (void) iget(dp->i_dev, dp->i_number); - while(c == '/') - c = (*func)(); - if(c == '\0' && flag != 0) - u.u_error = ENOENT; - -cloop: - /* - * Here dp contains pointer - * to last component matched. - */ - - if(u.u_error) - goto out; - if(c == '\0') - return(dp); - -#ifdef CHAOS - if((dp->i_mode & IFMT) == IFCHR && - (cdevpath & (1 << major(dp->i_un.i_rdev)))) { - u.u_dirp--; - return(dp); } -#endif + ilock(dp); + dp->i_count++; + fs = dp->i_fs; + newsize = 0; +dirloop: /* - * If there is another component, - * Gather up name into - * users' dir buffer. + * dp must be a directory and + * must have X permission. + * cp is a path name relative to that directory. */ - - cp = &u.u_dbuf[0]; - while (c != '/' && c != '\0' && u.u_error == 0 ) { - if (mpxip!=NULL && c=='!') - break; - if (flag==1 && c == ('/'|0200)) { + if ((dp->i_mode&IFMT) != IFDIR) + u.u_error = ENOTDIR; + (void) access(dp, IEXEC); +dirloop2: + for (i = 0; *cp != '\0' && *cp != '/'; cp++) { +#ifdef notdef + if (i >= MAXNAMLEN) { u.u_error = ENOENT; - goto out; + break; + } + u.u_dent.d_name[i] = *cp; +#else + if (i < MAXNAMLEN) { + u.u_dent.d_name[i] = *cp; + i++; } - if (cp < &u.u_dbuf[DIRSIZ]) - *cp++ = c; - c = (*func)(); +#endif } - while(cp < &u.u_dbuf[DIRSIZ]) - *cp++ = '\0'; - while(c == '/') - c = (*func)(); - if (c == '!' && mpxip != NULL) { + if (u.u_error) { iput(dp); - plock(mpxip); - mpxip->i_count++; - return(mpxip); + brelse(nbp); + return (NULL); + } + u.u_dent.d_namlen = i; + u.u_dent.d_name[i] = '\0'; + newsize = DIRSIZ(&u.u_dent); + u.u_pdir = dp; + if (u.u_dent.d_name[0] == '\0') { /* null name, e.g. "/" or "" */ + if (flag != 0) { + u.u_error = ENOENT; + iput(dp); + dp = NULL; + } + u.u_offset = 0; + u.u_count = newsize; + brelse(nbp); + return (dp); } - -seloop: - /* - * dp must be a directory and - * must have X permission. - */ - - if((dp->i_mode&IFMT) != IFDIR) - u.u_error = ENOTDIR; - (void) access(dp, IEXEC); - if(u.u_error) - goto out; - /* * set up to search a directory */ + if (flag == 1) + slot = NONE; + else + slot = FOUND; u.u_offset = 0; u.u_segflg = 1; - eo = 0; bp = NULL; - if (dp == u.u_rdir && u.u_dent.d_name[0] == '.' && - u.u_dent.d_name[1] == '.' && u.u_dent.d_name[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; + irele(dp); + pdp = dp; + dp = iget(d, fs, u.u_dent.d_ino); + if (dp == NULL) { + iput(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; + iput(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); + iput(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); + iput(pdp); + iput(dp); + brelse(nbp); + return (NULL); + } + bcopy(bp->b_un.b_addr, nbp->b_un.b_addr, + (unsigned)dp->i_size); brelse(bp); - goto out; + cp = nbp->b_un.b_addr; + iput(dp); + if (*cp == '/') { + iput(pdp); + while (*cp == '/') + cp++; + if ((dp = u.u_rdir) == NULL) + dp = rootdir; + ilock(dp); + dp->i_count++; + } else { + dp = pdp; + ilock(dp); + } + fs = dp->i_fs; + goto dirloop; } - ep = (struct direct *)bp->b_un.b_addr; - } else - ep++; - - /* - * Note first empty directory slot - * in eo for possible creat. - * String compare the directory entry - * and the current component. - * If they do not match, go back to eloop. - */ - - u.u_offset += sizeof(struct direct); - if(ep->d_ino == 0) { - if(eo == 0) - eo = u.u_offset; - goto eloop; - } - for(i=0; id_name[i]) - goto eloop; - if(u.u_dbuf[i] == 0) - break; + iput(pdp); + if (*cp == '/') { + while (*cp == '/') + cp++; + goto dirloop; + } + /* + * End of path, so return name matched. + */ + u.u_offset -= ep->d_reclen; + u.u_count = newsize; + brelse(nbp); + return (dp); } - /* - * Here a component matched in a directory. - * If there is more pathname, go back to - * cloop, otherwise return. + * Search failed. + * Report what is appropriate as per flag. */ - bcopy((caddr_t)ep, (caddr_t)&u.u_dent, sizeof(struct direct)); - if(bp != NULL) + if (bp != NULL) brelse(bp); - if(flag==2 && c=='\0') { - if(access(dp, IWRITE)) - goto out; - return(dp); + if (flag == 1 && *cp == '\0' && dp->i_nlink != 0) { + brelse(nbp); + if (access(dp, IWRITE)) { + iput(dp); + return (NULL); + } + if (slot == NONE) { + u.u_count = 0; + } else { + u.u_offset = entryfree; + u.u_count = entrysize; + } + dp->i_flag |= IUPD|ICHG; + return (NULL); } - d = dp->i_dev; - if(u.u_dent.d_ino == ROOTINO) - if(dp->i_number == ROOTINO) - if(u.u_dent.d_name[1] == '.') - for(i=1; ii_count++; - plock(dp); - goto seloop; - } + u.u_error = ENOENT; iput(dp); - dp = iget(d, u.u_dent.d_ino); - if(dp == NULL) - return(NULL); - goto cloop; - -out: - iput(dp); - return(NULL); + brelse(nbp); + return (NULL); } /* @@ -230,7 +390,7 @@ out: schar() { - return(*u.u_dirp++ & 0377); + return (*u.u_dirp++ & 0377); } /* @@ -242,7 +402,32 @@ uchar() register c; c = fubyte(u.u_dirp++); - if(c == -1) + if (c == -1) { u.u_error = EFAULT; - return(c); + c = 0; + } + return (c); +} + +#ifndef vax +bcmp(s1, s2, len) + register char *s1, *s2; + register int len; +{ + + while (--len) + if (*s1++ != *s2++) + return (1); + return (0); +} + +strlen(s1) + register char *s1; +{ + register int len; + + for (len = 0; *s1++ != '\0'; len++) + /* void */; + return (len); } +#endif