{
int ret;
char *next;
- char fpath[128];
- char symlinkpath[128];
- char *name = fpath;
+ char *buf;
+ char *name;
unsigned long root_inum = 1;
unsigned long inum;
int symlink_count = 0; /* Don't allow symlink recursion */
- char link_name[64];
-
- strcpy(fpath, filename);
+ size_t filenamelen;
/* Remove all leading slashes */
- while (*name == '/')
- name++;
+ while (*filename == '/')
+ filename++;
+
+ filenamelen = strlen(filename);
+ buf = kmalloc(filenamelen + 1, GFP_NOFS);
+ if (!buf)
+ return -ENOMEM;
+ memcpy(buf, filename, filenamelen + 1);
+ name = buf;
/*
* Handle root-direcoty ('/')
*/
inum = root_inum;
- if (!name || *name == '\0')
+ if (!name || *name == '\0') {
+ kfree(buf);
return inum;
+ }
for (;;) {
struct inode *inode;
while (*next == '/')
*(next++) = '\0';
}
-
ret = ubifs_finddir(sb, name, root_inum, &inum);
- if (!ret)
+ if (!ret) {
+ kfree(buf);
return 0;
+ }
inode = ubifs_iget(sb, inum);
- if (!inode)
+ if (!inode) {
+ kfree(buf);
return 0;
+ }
ui = ubifs_inode(inode);
if ((inode->i_mode & S_IFMT) == S_IFLNK) {
- char buf[128];
+ size_t newbufsize;
+ char *newbuf;
+ char *linkdata = ui->data;
+ size_t linklen = ui->data_len;
/* We have some sort of symlink recursion, bail out */
if (symlink_count++ > 8) {
ubifs_iput(inode);
printf("Symlink recursion, aborting\n");
+ kfree(buf);
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;
+ while (linklen && *linkdata == '/') {
+ /* Absolute path, i.e. relative to root. */
root_inum = 1;
+ linkdata++;
+ linklen--;
+ }
+ newbufsize =
+ linklen + 1 + (next ? strlen(next) : 0) + 1;
+ newbuf = kmalloc(newbufsize, GFP_NOFS);
+ if (!newbuf) {
+ kfree(buf);
ubifs_iput(inode);
- continue;
+ return -ENOMEM;
}
- /* Relative to cur dir */
- sprintf(buf, "%s/%s",
- link_name, next == NULL ? "" : next);
- memcpy(symlinkpath, buf, sizeof(buf));
- next = name = symlinkpath;
+
+ memcpy(newbuf, linkdata, linklen);
+ sprintf(newbuf + linklen, "/%s", next ?: "");
+ kfree(buf);
+ buf = newbuf;
+ name = newbuf;
ubifs_iput(inode);
continue;
}
/* Found the node! */
if (!next || *next == '\0') {
ubifs_iput(inode);
+ kfree(buf);
return inum;
}
name = next;
}
+ kfree(buf);
return 0;
}