summaryrefslogtreecommitdiff
path: root/fs.c
diff options
context:
space:
mode:
authorrsc <rsc>2007-08-09 19:05:00 +0000
committerrsc <rsc>2007-08-09 19:05:00 +0000
commitab5c2dbb592fde4219fd3b2bf8d82e2299f6f9c9 (patch)
tree39aeb715aa750fdc2ed79002a05aa09c49f187c8 /fs.c
parent806f4c11f7fc737ac4f964d3489f5f37260ccea3 (diff)
downloadxv6-labs-ab5c2dbb592fde4219fd3b2bf8d82e2299f6f9c9.tar.gz
xv6-labs-ab5c2dbb592fde4219fd3b2bf8d82e2299f6f9c9.tar.bz2
xv6-labs-ab5c2dbb592fde4219fd3b2bf8d82e2299f6f9c9.zip
Clearer namei
Diffstat (limited to 'fs.c')
-rw-r--r--fs.c175
1 files changed, 106 insertions, 69 deletions
diff --git a/fs.c b/fs.c
index d3d10e1..c62ce67 100644
--- a/fs.c
+++ b/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.
// NAMEI_LOOKUP: return locked target inode.
// NAMEI_CREATE: return locked parent inode.
@@ -491,12 +558,10 @@ namei(char *path, int mode, uint *ret_off,
{
struct inode *dp;
struct proc *p = curproc[cpu()];
- char *cp = path, *cp1;
+ char *name;
+ int namelen;
uint off, dev;
- struct buf *bp;
- struct dirent *ep;
- int i, l, atend;
- uint ninum;
+ uint inum;
if(ret_off)
*ret_off = 0xffffffff;
@@ -505,91 +570,57 @@ namei(char *path, int mode, uint *ret_off,
if(ret_ip)
*ret_ip = 0;
- if(*cp == '/')
+ if(*path == '/')
dp = iget(rootdev, 1);
else {
dp = iincref(p->cwd);
ilock(dp);
}
- for(;;){
- while(*cp == '/')
- cp++;
-
- if(*cp == '\0'){
- if(mode == NAMEI_LOOKUP)
- return dp;
- if(mode == NAMEI_CREATE && ret_ip){
- *ret_ip = dp;
- return 0;
- }
- iput(dp);
- return 0;
- }
+ while((path = skipelem(path, &name, &namelen)) != 0){
+ // Truncate names in path to DIRSIZ chars.
+ if(namelen > DIRSIZ)
+ namelen = DIRSIZ;
- if(dp->type != T_DIR){
- iput(dp);
- return 0;
- }
+ if(dp->type != T_DIR)
+ goto fail;
- 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;
+ if(lookup(dp, name, namelen, &off, &inum) < 0){
+ if(mode == NAMEI_CREATE && *path == '\0'){
+ *ret_last = name;
+ return dp;
}
- *ret_last = cp;
- return dp;
+ goto fail;
}
- iput(dp);
- return 0;
-
- found:
- if(mode == NAMEI_DELETE && *cp == '\0'){
+ if(mode == NAMEI_DELETE && *path == '\0'){
// can't unlink . and ..
- if((i == 1 && memcmp(cp-1, ".", 1) == 0) ||
- (i == 2 && memcmp(cp-2, "..", 2) == 0)){
- iput(dp);
- return 0;
+ 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, ninum);
+ dp = iget(dev, inum);
if(dp->type == 0 || dp->nlink < 1)
panic("namei");
}
+
+ if(mode == NAMEI_LOOKUP)
+ return dp;
+ if(mode == NAMEI_CREATE && ret_ip){
+ *ret_ip = dp;
+ return 0;
+ }
+ goto fail;
+
+fail:
+ iput(dp);
+ return 0;
}
// Write a new directory entry (name, ino) into the directory dp.
@@ -675,6 +706,12 @@ unlink(char *cp)
if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de) || de.inum == 0)
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;