fs: implement size/fatsize/ext4size

These commands may be used to determine the size of a file without
actually reading the whole file content into memory. This may be used
to determine if the file will fit into the memory buffer that will
contain it. In particular, the DFU code will use it for this purpose
in the next commit.

Signed-off-by: Stephen Warren <swarren@nvidia.com>
diff --git a/fs/fs.c b/fs/fs.c
index ea15c5f..dd680f3 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -46,6 +46,11 @@
 	return 0;
 }
 
+static inline int fs_size_unsupported(const char *filename)
+{
+	return -1;
+}
+
 static inline int fs_read_unsupported(const char *filename, void *buf,
 				      int offset, int len)
 {
@@ -77,6 +82,7 @@
 		     disk_partition_t *fs_partition);
 	int (*ls)(const char *dirname);
 	int (*exists)(const char *filename);
+	int (*size)(const char *filename);
 	int (*read)(const char *filename, void *buf, int offset, int len);
 	int (*write)(const char *filename, void *buf, int offset, int len);
 	void (*close)(void);
@@ -91,6 +97,7 @@
 		.close = fat_close,
 		.ls = file_fat_ls,
 		.exists = fat_exists,
+		.size = fat_size,
 		.read = fat_read_file,
 		.write = fs_write_unsupported,
 	},
@@ -103,6 +110,7 @@
 		.close = ext4fs_close,
 		.ls = ext4fs_ls,
 		.exists = ext4fs_exists,
+		.size = ext4fs_size,
 		.read = ext4_read_file,
 		.write = fs_write_unsupported,
 	},
@@ -115,6 +123,7 @@
 		.close = sandbox_fs_close,
 		.ls = sandbox_fs_ls,
 		.exists = sandbox_fs_exists,
+		.size = sandbox_fs_size,
 		.read = fs_read_sandbox,
 		.write = fs_write_sandbox,
 	},
@@ -126,6 +135,7 @@
 		.close = fs_close_unsupported,
 		.ls = fs_ls_unsupported,
 		.exists = fs_exists_unsupported,
+		.size = fs_size_unsupported,
 		.read = fs_read_unsupported,
 		.write = fs_write_unsupported,
 	},
@@ -223,6 +233,19 @@
 	return ret;
 }
 
+int fs_size(const char *filename)
+{
+	int ret;
+
+	struct fstype_info *info = fs_get_info(fs_type);
+
+	ret = info->size(filename);
+
+	fs_close();
+
+	return ret;
+}
+
 int fs_read(const char *filename, ulong addr, int offset, int len)
 {
 	struct fstype_info *info = fs_get_info(fs_type);
@@ -266,6 +289,26 @@
 	return ret;
 }
 
+int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
+		int fstype)
+{
+	int size;
+
+	if (argc != 4)
+		return CMD_RET_USAGE;
+
+	if (fs_set_blk_dev(argv[1], argv[2], fstype))
+		return 1;
+
+	size = fs_size(argv[3]);
+	if (size < 0)
+		return CMD_RET_FAILURE;
+
+	setenv_hex("filesize", size);
+
+	return 0;
+}
+
 int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
 		int fstype)
 {