summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/ubifs/ubifs.c68
1 files changed, 43 insertions, 25 deletions
diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c
index 8ede188e1..b03ed0bb8 100644
--- a/fs/ubifs/ubifs.c
+++ b/fs/ubifs/ubifs.c
@@ -379,9 +379,11 @@ static unsigned long ubifs_findfile(struct super_block *sb, char *filename)
int ret;
char *next;
char fpath[128];
+ char symlinkpath[128];
char *name = fpath;
unsigned long root_inum = 1;
unsigned long inum;
+ int symlink_count = 0; /* Don't allow symlink recursion */
strcpy(fpath, filename);
@@ -397,6 +399,9 @@ static unsigned long ubifs_findfile(struct super_block *sb, char *filename)
return inum;
for (;;) {
+ struct inode *inode;
+ struct ubifs_inode *ui;
+
/* Extract the actual part from the pathname. */
next = strchr(name, '/');
if (next) {
@@ -406,18 +411,48 @@ static unsigned long ubifs_findfile(struct super_block *sb, char *filename)
}
ret = ubifs_finddir(sb, name, root_inum, &inum);
+ if (!ret)
+ return 0;
+ inode = ubifs_iget(sb, inum);
+
+ if (!inode)
+ return 0;
+ ui = ubifs_inode(inode);
+
+ if ((inode->i_mode & S_IFMT) == S_IFLNK) {
+ char link_name[64];
+ char buf[128];
+
+ /* We have some sort of symlink recursion, bail out */
+ if (symlink_count++ > 8) {
+ printf("Symlink recursion, aborting\n");
+ return 0;
+ }
+ memcpy(link_name, ui->data, ui->data_len);
+ link_name[ui->data_len] = '\0';
+
+ if (link_name[0] == '/') {
+ /* Absolute path, redo everything without
+ * the leading slash */
+ next = name = link_name + 1;
+ root_inum = 1;
+ continue;
+ }
+ /* Relative to cur dir */
+ sprintf(buf, "%s%s",
+ link_name, next == NULL ? "" : next);
+ memcpy(symlinkpath, buf, sizeof(buf));
+ next = name = symlinkpath;
+ continue;
+ }
/*
* Check if directory with this name exists
*/
/* Found the node! */
- if (!next || *next == '\0') {
- if (ret)
- return inum;
-
- break;
- }
+ if (!next || *next == '\0')
+ return inum;
root_inum = inum;
name = next;
@@ -614,10 +649,10 @@ int ubifs_load(char *filename, u32 addr, u32 size)
int err = 0;
int i;
int count;
- char link_name[64];
- struct ubifs_inode *ui;
c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
+ /* ubifs_findfile will resolve symlinks, so we know that we get
+ * the real file here */
inum = ubifs_findfile(ubifs_sb, filename);
if (!inum) {
err = -1;
@@ -635,23 +670,6 @@ int ubifs_load(char *filename, u32 addr, u32 size)
}
/*
- * Check for symbolic link
- */
- ui = ubifs_inode(inode);
- if (((inode->i_mode & S_IFMT) == S_IFLNK) && ui->data_len) {
- memcpy(link_name, ui->data, ui->data_len);
- link_name[ui->data_len] = '\0';
- printf("%s is linked to %s!\n", filename, link_name);
- ubifs_iput(inode);
-
- /*
- * Now we have the "real" filename, call ubifs_load()
- * again (recursive call) to load this file instead
- */
- return ubifs_load(link_name, addr, size);
- }
-
- /*
* If no size was specified or if size bigger than filesize
* set size to filesize
*/