core, fs: handle .. resolution in the filesystem core
authorH. Peter Anvin <hpa@zytor.com>
Sat, 26 Jun 2010 03:36:59 +0000 (20:36 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Sat, 26 Jun 2010 03:36:59 +0000 (20:36 -0700)
Some filesystems, including btrfs, don't have .. directory entries.
We already handle . in the filesystem core, handle .. as well.

This means keeping chains of parent inodes for all open inodes, at
least for the duration of a path search; we might as well hang onto
them.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
core/fs/fs.c
core/include/fs.h

index c16f955..a101dfd 100644 (file)
@@ -30,6 +30,19 @@ struct inode *alloc_inode(struct fs_info *fs, uint32_t ino, size_t data)
 }
 
 /*
+ * Free a refcounted inode
+ */
+void put_inode(struct inode *inode)
+{
+    if (inode) {
+       if (! --inode->refcnt) {
+           put_inode(inode->parent);
+           free(inode);
+       }
+    }
+}
+
+/*
  * Get an empty file structure
  */
 static struct file *alloc_file(void)
@@ -235,7 +248,20 @@ int searchdir(const char *name)
                p++;
            *p++ = '\0';
 
-           if (part[0] != '.' || part[1] != '\0') {
+           if (part[0] == '.' && part[1] == '.' && part[2] == '\0') {
+               if (inode->parent) {
+                   put_inode(parent);
+                   parent = get_inode(inode->parent);
+                   put_inode(inode);
+                   inode = NULL;
+                   if (!echar) {
+                       /* Terminal double dots */
+                       inode = parent;
+                       parent = inode->parent ?
+                           get_inode(inode->parent) : NULL;
+                   }
+               }
+           } else if (part[0] != '.' || part[1] != '\0') {
                inode = this_fs->fs_ops->iget(part, parent);
                if (!inode)
                    goto err;
@@ -278,7 +304,7 @@ int searchdir(const char *name)
                    goto got_link;
                }
 
-               put_inode(parent);
+               inode->parent = parent;
                parent = NULL;
 
                if (!echar)
@@ -304,16 +330,11 @@ int searchdir(const char *name)
     file->inode  = inode;
     file->offset = 0;
 
-    dprintf("File %s -> %p (inode %p) len %u\n", name, file,
-           inode, inode->size);
-
     return file_to_handle(file);
 
 err:
-    if (inode)
-       put_inode(inode);
-    if (parent)
-       put_inode(parent);
+    put_inode(inode);
+    put_inode(parent);
     if (pathbuf)
        free(pathbuf);
     _close_file(file);
index f1d35bb..bb629c9 100644 (file)
@@ -94,6 +94,7 @@ struct extent {
  */
 struct inode {
     struct fs_info *fs;         /* The filesystem this inode is associated with */
+    struct inode *parent;      /* Parent directory, if any */
     int                 refcnt;
     int          mode;   /* FILE , DIR or SYMLINK */
     uint32_t     size;
@@ -157,11 +158,8 @@ static inline struct inode *get_inode(struct inode *inode)
     inode->refcnt++;
     return inode;
 }
-static inline void put_inode(struct inode *inode)
-{
-    if (! --inode->refcnt)
-       free(inode);
-}
+
+void put_inode(struct inode *inode);
 
 static inline void malloc_error(char *obj)
 {