summaryrefslogtreecommitdiff
path: root/core/fs/fs.c
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2010-06-25 20:36:59 -0700
committerH. Peter Anvin <hpa@zytor.com>2010-06-25 20:36:59 -0700
commit4deec2c8fb4f93204187f54f9b722072be537832 (patch)
treecd539c52dbe8c2980bb61b632580014479b6cd60 /core/fs/fs.c
parent4b038f7218b382a146a101b685264ca425c13811 (diff)
downloadsyslinux-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>
Diffstat (limited to 'core/fs/fs.c')
-rw-r--r--core/fs/fs.c39
1 files changed, 30 insertions, 9 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);