[U-Boot] [PATCH v2 3/3] cramfs: basic symlink support

Tyler Hall tylerwhall at gmail.com
Wed Apr 12 20:29:17 UTC 2017


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 at gmail.com>
---
 fs/cramfs/cramfs.c | 62 +++++++++++++++++++++++++++++++++++++++++++-----------
 1 file 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");
 
-- 
2.12.2



More information about the U-Boot mailing list