summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler Hall <tylerwhall@gmail.com>2017-04-12 16:29:17 -0400
committerTom Rini <trini@konsulko.com>2017-04-18 10:27:58 -0400
commitd39a0d2c8413b33a5cd29466c1f6c4bda022ee58 (patch)
treebe3fc94030d9aa9d71580e3ceeedcf06e8d6f4a9
parenta6ea791cb96f76fd600f6547a715e24ef66ba5e2 (diff)
cramfs: basic symlink support
Handle symlinks to files in the current directory. Other cases could be handled with additional code, but this is a start. Add explicit errors for absolute paths and links found in the middle of a path (directories). Other cases like '..' or '.' will result with the file not being found as when those path components are explicitly provided. Add a helper to decompress a null-terminated link name which is shared with cramfs_list_inode. Signed-off-by: Tyler Hall <tylerwhall@gmail.com>
-rw-r--r--fs/cramfs/cramfs.c62
1 files changed, 50 insertions, 12 deletions
diff --git a/fs/cramfs/cramfs.c b/fs/cramfs/cramfs.c
index ca8bc5e12b..228f599d44 100644
--- a/fs/cramfs/cramfs.c
+++ b/fs/cramfs/cramfs.c
@@ -49,6 +49,9 @@ extern flash_info_t flash_info[];
#define PART_OFFSET(x) ((ulong)x->offset)
#endif
+static int cramfs_uncompress (unsigned long begin, unsigned long offset,
+ unsigned long loadoffset);
+
static int cramfs_read_super (struct part_info *info)
{
unsigned long root_offset;
@@ -94,6 +97,22 @@ static int cramfs_read_super (struct part_info *info)
return 0;
}
+/* Unpack to an allocated buffer, trusting in the inode's size field. */
+static char *cramfs_uncompress_link (unsigned long begin, unsigned long offset)
+{
+ struct cramfs_inode *inode = (struct cramfs_inode *)(begin + offset);
+ unsigned long size = CRAMFS_24 (inode->size);
+ char *link = malloc (size + 1);
+
+ if (!link || cramfs_uncompress (begin, offset, (unsigned long)link) != size) {
+ free (link);
+ link = NULL;
+ } else {
+ link[size] = '\0';
+ }
+ return link;
+}
+
static unsigned long cramfs_resolve (unsigned long begin, unsigned long offset,
unsigned long size, int raw,
char *filename)
@@ -143,6 +162,33 @@ static unsigned long cramfs_resolve (unsigned long begin, unsigned long offset,
p);
} else if (S_ISREG (CRAMFS_16 (inode->mode))) {
return offset + inodeoffset;
+ } else if (S_ISLNK (CRAMFS_16 (inode->mode))) {
+ unsigned long ret;
+ char *link;
+ if (p && strlen(p)) {
+ printf ("unsupported symlink to \
+ non-terminal path\n");
+ return 0;
+ }
+ link = cramfs_uncompress_link (begin,
+ offset + inodeoffset);
+ if (!link) {
+ printf ("%*.*s: Error reading link\n",
+ namelen, namelen, name);
+ return 0;
+ } else if (link[0] == '/') {
+ printf ("unsupported symlink to \
+ absolute path\n");
+ free (link);
+ return 0;
+ }
+ ret = cramfs_resolve (begin,
+ offset,
+ size,
+ raw,
+ strtok(link, "/"));
+ free (link);
+ return ret;
} else {
printf ("%*.*s: unsupported file type (%x)\n",
namelen, namelen, name,
@@ -235,20 +281,12 @@ static int cramfs_list_inode (struct part_info *info, unsigned long offset)
CRAMFS_24 (inode->size), namelen, namelen, name);
if ((CRAMFS_16 (inode->mode) & S_IFMT) == S_IFLNK) {
- /* symbolic link.
- * Unpack the link target, trusting in the inode's size field.
- */
- unsigned long size = CRAMFS_24 (inode->size);
- char *link = malloc (size);
-
- if (link != NULL && cramfs_uncompress (PART_OFFSET(info), offset,
- (unsigned long) link)
- == size)
- printf (" -> %*.*s\n", (int) size, (int) size, link);
+ char *link = cramfs_uncompress_link (PART_OFFSET(info), offset);
+ if (link)
+ printf (" -> %s\n", link);
else
printf (" [Error reading link]\n");
- if (link)
- free (link);
+ free (link);
} else
printf ("\n");