diff options
| author | H. Peter Anvin <hpa@zytor.com> | 2010-06-25 20:36:59 -0700 |
|---|---|---|
| committer | H. Peter Anvin <hpa@zytor.com> | 2010-06-25 20:36:59 -0700 |
| commit | 4deec2c8fb4f93204187f54f9b722072be537832 (patch) | |
| tree | cd539c52dbe8c2980bb61b632580014479b6cd60 | |
| parent | 4b038f7218b382a146a101b685264ca425c13811 (diff) | |
| download | syslinux-4deec2c8fb4f93204187f54f9b722072be537832.tar.gz | |
core, fs: handle .. resolution in the filesystem core
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>
| -rw-r--r-- | core/fs/fs.c | 39 | ||||
| -rw-r--r-- | core/include/fs.h | 8 |
2 files changed, 33 insertions, 14 deletions
diff --git a/core/fs/fs.c b/core/fs/fs.c index c16f9550..a101dfda 100644 --- a/core/fs/fs.c +++ b/core/fs/fs.c @@ -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); diff --git a/core/include/fs.h b/core/include/fs.h index f1d35bbb..bb629c91 100644 --- a/core/include/fs.h +++ b/core/include/fs.h @@ -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) { |
