cramfs: basic symlink support
authorTyler Hall <tylerwhall@gmail.com>
Wed, 12 Apr 2017 20:29:17 +0000 (16:29 -0400)
committerTom Rini <trini@konsulko.com>
Tue, 18 Apr 2017 14:27:58 +0000 (10:27 -0400)
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>
fs/cramfs/cramfs.c

index ca8bc5e12b8499796746dc133e15d1c49f0649a7..228f599d44bbca3e7c067ab5ae86ce9981e10a5e 100644 (file)
@@ -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");