Clearer namei
This commit is contained in:
parent
806f4c11f7
commit
ab5c2dbb59
1 changed files with 106 additions and 69 deletions
187
fs.c
187
fs.c
|
@ -476,6 +476,73 @@ writei(struct inode *ip, char *addr, uint off, uint n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skip over the next path element in path,
|
||||||
|
// saving it in *name and its length in *len.
|
||||||
|
// Return a pointer to the element after that
|
||||||
|
// (after any trailing slashes).
|
||||||
|
// Thus the caller can check whether *path=='\0'
|
||||||
|
// to see whether the name just removed was
|
||||||
|
// the last one.
|
||||||
|
// If there is no name to remove, return 0.
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
// skipelem("a/bb/c") = "bb/c", with *name = "a/bb/c", len=1
|
||||||
|
// skipelem("///a/bb") = "b", with *name="a/bb", len=1
|
||||||
|
// skipelem("") = skipelem("////") = 0
|
||||||
|
//
|
||||||
|
static char*
|
||||||
|
skipelem(char *path, char **name, int *len)
|
||||||
|
{
|
||||||
|
while(*path == '/')
|
||||||
|
path++;
|
||||||
|
if(*path == 0)
|
||||||
|
return 0;
|
||||||
|
*name = path;
|
||||||
|
while(*path != '/' && *path != 0)
|
||||||
|
path++;
|
||||||
|
*len = path - *name;
|
||||||
|
while(*path == '/')
|
||||||
|
path++;
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for a directory entry in a directory.
|
||||||
|
// If not found, return -1.
|
||||||
|
// If found:
|
||||||
|
// set *poff to the byte offset of the directory entry
|
||||||
|
// set *pinum to the inode number
|
||||||
|
// return 0.
|
||||||
|
static int
|
||||||
|
lookup(struct inode *dp, char *name, int namelen, uint *poff, uint *pinum)
|
||||||
|
{
|
||||||
|
uint off;
|
||||||
|
struct buf *bp;
|
||||||
|
struct dirent *de;
|
||||||
|
|
||||||
|
if(dp->type != T_DIR)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for(off = 0; off < dp->size; off += BSIZE){
|
||||||
|
bp = bread(dp->dev, bmap(dp, off / BSIZE));
|
||||||
|
for(de = (struct dirent*) bp->data;
|
||||||
|
de < (struct dirent*) (bp->data + BSIZE);
|
||||||
|
de++){
|
||||||
|
if(de->inum == 0)
|
||||||
|
continue;
|
||||||
|
if(memcmp(name, de->name, namelen) == 0 &&
|
||||||
|
(namelen == DIRSIZ || de->name[namelen]== 0)){
|
||||||
|
// entry matches path element
|
||||||
|
*poff = off + (uchar*)de - bp->data;
|
||||||
|
*pinum = de->inum;
|
||||||
|
brelse(bp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
brelse(bp);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// look up a path name, in one of three modes.
|
// look up a path name, in one of three modes.
|
||||||
// NAMEI_LOOKUP: return locked target inode.
|
// NAMEI_LOOKUP: return locked target inode.
|
||||||
// NAMEI_CREATE: return locked parent inode.
|
// NAMEI_CREATE: return locked parent inode.
|
||||||
|
@ -491,12 +558,10 @@ namei(char *path, int mode, uint *ret_off,
|
||||||
{
|
{
|
||||||
struct inode *dp;
|
struct inode *dp;
|
||||||
struct proc *p = curproc[cpu()];
|
struct proc *p = curproc[cpu()];
|
||||||
char *cp = path, *cp1;
|
char *name;
|
||||||
|
int namelen;
|
||||||
uint off, dev;
|
uint off, dev;
|
||||||
struct buf *bp;
|
uint inum;
|
||||||
struct dirent *ep;
|
|
||||||
int i, l, atend;
|
|
||||||
uint ninum;
|
|
||||||
|
|
||||||
if(ret_off)
|
if(ret_off)
|
||||||
*ret_off = 0xffffffff;
|
*ret_off = 0xffffffff;
|
||||||
|
@ -505,91 +570,57 @@ namei(char *path, int mode, uint *ret_off,
|
||||||
if(ret_ip)
|
if(ret_ip)
|
||||||
*ret_ip = 0;
|
*ret_ip = 0;
|
||||||
|
|
||||||
if(*cp == '/')
|
if(*path == '/')
|
||||||
dp = iget(rootdev, 1);
|
dp = iget(rootdev, 1);
|
||||||
else {
|
else {
|
||||||
dp = iincref(p->cwd);
|
dp = iincref(p->cwd);
|
||||||
ilock(dp);
|
ilock(dp);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(;;){
|
while((path = skipelem(path, &name, &namelen)) != 0){
|
||||||
while(*cp == '/')
|
// Truncate names in path to DIRSIZ chars.
|
||||||
cp++;
|
if(namelen > DIRSIZ)
|
||||||
|
namelen = DIRSIZ;
|
||||||
|
|
||||||
|
if(dp->type != T_DIR)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if(lookup(dp, name, namelen, &off, &inum) < 0){
|
||||||
|
if(mode == NAMEI_CREATE && *path == '\0'){
|
||||||
|
*ret_last = name;
|
||||||
|
return dp;
|
||||||
|
}
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mode == NAMEI_DELETE && *path == '\0'){
|
||||||
|
// can't unlink . and ..
|
||||||
|
if((namelen == 1 && memcmp(name, ".", 1) == 0) ||
|
||||||
|
(namelen == 2 && memcmp(name, "..", 2) == 0)){
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
*ret_off = off;
|
||||||
|
return dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = dp->dev;
|
||||||
|
iput(dp);
|
||||||
|
dp = iget(dev, inum);
|
||||||
|
if(dp->type == 0 || dp->nlink < 1)
|
||||||
|
panic("namei");
|
||||||
|
}
|
||||||
|
|
||||||
if(*cp == '\0'){
|
|
||||||
if(mode == NAMEI_LOOKUP)
|
if(mode == NAMEI_LOOKUP)
|
||||||
return dp;
|
return dp;
|
||||||
if(mode == NAMEI_CREATE && ret_ip){
|
if(mode == NAMEI_CREATE && ret_ip){
|
||||||
*ret_ip = dp;
|
*ret_ip = dp;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
fail:
|
||||||
iput(dp);
|
iput(dp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
if(dp->type != T_DIR){
|
|
||||||
iput(dp);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i = 0; cp[i] != 0 && cp[i] != '/'; i++)
|
|
||||||
;
|
|
||||||
l = i;
|
|
||||||
if(i > DIRSIZ)
|
|
||||||
l = DIRSIZ;
|
|
||||||
|
|
||||||
for(off = 0; off < dp->size; off += BSIZE){
|
|
||||||
bp = bread(dp->dev, bmap(dp, off / BSIZE));
|
|
||||||
for(ep = (struct dirent*) bp->data;
|
|
||||||
ep < (struct dirent*) (bp->data + BSIZE);
|
|
||||||
ep++){
|
|
||||||
if(ep->inum == 0)
|
|
||||||
continue;
|
|
||||||
if(memcmp(cp, ep->name, l) == 0 &&
|
|
||||||
(l == DIRSIZ || ep->name[l]== 0)){
|
|
||||||
// entry matches path element
|
|
||||||
off += (uchar*)ep - bp->data;
|
|
||||||
ninum = ep->inum;
|
|
||||||
brelse(bp);
|
|
||||||
cp += i;
|
|
||||||
goto found;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
brelse(bp);
|
|
||||||
}
|
|
||||||
atend = 1;
|
|
||||||
for(cp1 = cp; *cp1; cp1++)
|
|
||||||
if(*cp1 == '/')
|
|
||||||
atend = 0;
|
|
||||||
if(mode == NAMEI_CREATE && atend){
|
|
||||||
if(*cp == '\0'){
|
|
||||||
iput(dp);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*ret_last = cp;
|
|
||||||
return dp;
|
|
||||||
}
|
|
||||||
|
|
||||||
iput(dp);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
found:
|
|
||||||
if(mode == NAMEI_DELETE && *cp == '\0'){
|
|
||||||
// can't unlink . and ..
|
|
||||||
if((i == 1 && memcmp(cp-1, ".", 1) == 0) ||
|
|
||||||
(i == 2 && memcmp(cp-2, "..", 2) == 0)){
|
|
||||||
iput(dp);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*ret_off = off;
|
|
||||||
return dp;
|
|
||||||
}
|
|
||||||
dev = dp->dev;
|
|
||||||
iput(dp);
|
|
||||||
dp = iget(dev, ninum);
|
|
||||||
if(dp->type == 0 || dp->nlink < 1)
|
|
||||||
panic("namei");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write a new directory entry (name, ino) into the directory dp.
|
// Write a new directory entry (name, ino) into the directory dp.
|
||||||
|
@ -676,6 +707,12 @@ unlink(char *cp)
|
||||||
if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de) || de.inum == 0)
|
if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de) || de.inum == 0)
|
||||||
panic("unlink no entry");
|
panic("unlink no entry");
|
||||||
|
|
||||||
|
// Cannot remove "." or ".." - the 2 and 3 count the trailing NUL.
|
||||||
|
if(memcmp(de.name, ".", 2) == 0 || memcmp(de.name, "..", 3) == 0){
|
||||||
|
iput(dp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
inum = de.inum;
|
inum = de.inum;
|
||||||
|
|
||||||
memset(&de, 0, sizeof(de));
|
memset(&de, 0, sizeof(de));
|
||||||
|
|
Loading…
Reference in a new issue