Clearer namei

This commit is contained in:
rsc 2007-08-09 19:05:00 +00:00
parent 806f4c11f7
commit ab5c2dbb59

187
fs.c
View file

@ -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,93 +570,59 @@ 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.
// Caller must have locked dp. // Caller must have locked dp.
void void
@ -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));