blob: 5591c65eaa9801f4e02214e62b9106d8d5c0d10e [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0
Stephen Warreneefbc3f2012-10-22 06:43:51 +00002/*
3 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
Stephen Warreneefbc3f2012-10-22 06:43:51 +00004 */
5
Simon Glassed38aef2020-05-10 11:40:03 -06006#include <command.h>
Stephen Warreneefbc3f2012-10-22 06:43:51 +00007#include <config.h>
Christian Gmeiner9f9eec32014-11-12 14:35:04 +01008#include <errno.h>
Stephen Warreneefbc3f2012-10-22 06:43:51 +00009#include <common.h>
Simon Glass313112a2019-08-01 09:46:46 -060010#include <env.h>
Simon Glass655306c2020-05-10 11:39:58 -060011#include <lmb.h>
Joe Hershberger65b905b2015-03-22 17:08:59 -050012#include <mapmem.h>
Stephen Warreneefbc3f2012-10-22 06:43:51 +000013#include <part.h>
14#include <ext4fs.h>
15#include <fat.h>
16#include <fs.h>
Simon Glass11842872012-12-26 09:53:35 +000017#include <sandboxfs.h>
Hans de Goede690c7962015-09-17 18:46:58 -040018#include <ubifs_uboot.h>
Marek BehĂșn98ec1d12017-09-03 17:00:29 +020019#include <btrfs.h>
Simon Glasscbe5d5d2012-12-26 09:53:32 +000020#include <asm/io.h>
Tom Rinia17b7bc2014-11-24 11:50:46 -050021#include <div64.h>
22#include <linux/math64.h>
Mian Yousaf Kaukab961ebe82019-06-18 15:03:44 +020023#include <efi_loader.h>
Stephen Warreneefbc3f2012-10-22 06:43:51 +000024
Stephen Warren44161af2012-10-30 07:50:47 +000025DECLARE_GLOBAL_DATA_PTR;
26
Simon Glasse3394752016-02-29 15:25:34 -070027static struct blk_desc *fs_dev_desc;
Rob Clark2b7bfd92017-09-09 13:15:55 -040028static int fs_dev_part;
Simon Glassc1c4a8f2020-05-10 11:39:57 -060029static struct disk_partition fs_partition;
Stephen Warreneefbc3f2012-10-22 06:43:51 +000030static int fs_type = FS_TYPE_ANY;
31
Simon Glasse3394752016-02-29 15:25:34 -070032static inline int fs_probe_unsupported(struct blk_desc *fs_dev_desc,
Simon Glassc1c4a8f2020-05-10 11:39:57 -060033 struct disk_partition *fs_partition)
Simon Glass1aede482012-12-26 09:53:29 +000034{
35 printf("** Unrecognized filesystem type **\n");
36 return -1;
37}
38
Stephen Warreneefbc3f2012-10-22 06:43:51 +000039static inline int fs_ls_unsupported(const char *dirname)
40{
Stephen Warreneefbc3f2012-10-22 06:43:51 +000041 return -1;
42}
43
Rob Clark60d74a92017-09-09 13:15:58 -040044/* generic implementation of ls in terms of opendir/readdir/closedir */
45__maybe_unused
46static int fs_ls_generic(const char *dirname)
47{
48 struct fs_dir_stream *dirs;
49 struct fs_dirent *dent;
50 int nfiles = 0, ndirs = 0;
51
52 dirs = fs_opendir(dirname);
53 if (!dirs)
54 return -errno;
55
56 while ((dent = fs_readdir(dirs))) {
57 if (dent->type == FS_DT_DIR) {
58 printf(" %s/\n", dent->name);
59 ndirs++;
60 } else {
61 printf(" %8lld %s\n", dent->size, dent->name);
62 nfiles++;
63 }
64 }
65
66 fs_closedir(dirs);
67
68 printf("\n%d file(s), %d dir(s)\n\n", nfiles, ndirs);
69
70 return 0;
71}
72
Stephen Warrend008fbb2014-02-03 13:21:00 -070073static inline int fs_exists_unsupported(const char *filename)
74{
75 return 0;
76}
77
Suriyan Ramasami96171fb2014-11-17 14:39:38 -080078static inline int fs_size_unsupported(const char *filename, loff_t *size)
Stephen Warren3eb58f52014-06-11 12:47:26 -060079{
80 return -1;
81}
82
Simon Glasscbe5d5d2012-12-26 09:53:32 +000083static inline int fs_read_unsupported(const char *filename, void *buf,
Suriyan Ramasami96171fb2014-11-17 14:39:38 -080084 loff_t offset, loff_t len,
85 loff_t *actread)
Stephen Warreneefbc3f2012-10-22 06:43:51 +000086{
Stephen Warreneefbc3f2012-10-22 06:43:51 +000087 return -1;
88}
89
Simon Glasseda14ea2013-04-20 08:42:50 +000090static inline int fs_write_unsupported(const char *filename, void *buf,
Suriyan Ramasami96171fb2014-11-17 14:39:38 -080091 loff_t offset, loff_t len,
92 loff_t *actwrite)
Simon Glasseda14ea2013-04-20 08:42:50 +000093{
94 return -1;
95}
96
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +010097static inline int fs_ln_unsupported(const char *filename, const char *target)
98{
99 return -1;
100}
101
Simon Glass1aede482012-12-26 09:53:29 +0000102static inline void fs_close_unsupported(void)
103{
104}
105
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100106static inline int fs_uuid_unsupported(char *uuid_str)
107{
108 return -1;
109}
110
Rob Clark2b7bfd92017-09-09 13:15:55 -0400111static inline int fs_opendir_unsupported(const char *filename,
112 struct fs_dir_stream **dirs)
113{
114 return -EACCES;
115}
116
AKASHI Takahiro1ba42532018-09-11 15:59:13 +0900117static inline int fs_unlink_unsupported(const char *filename)
118{
119 return -1;
120}
121
AKASHI Takahiroadc8c9f2018-09-11 15:59:08 +0900122static inline int fs_mkdir_unsupported(const char *dirname)
123{
124 return -1;
125}
126
Simon Glass1aede482012-12-26 09:53:29 +0000127struct fstype_info {
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000128 int fstype;
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100129 char *name;
Stephen Warrenec63d4a2014-02-03 13:21:01 -0700130 /*
131 * Is it legal to pass NULL as .probe()'s fs_dev_desc parameter? This
132 * should be false in most cases. For "virtual" filesystems which
133 * aren't based on a U-Boot block device (e.g. sandbox), this can be
Heinrich Schuchardt99dc17d2018-08-11 15:52:14 +0200134 * set to true. This should also be true for the dummy entry at the end
Stephen Warrenec63d4a2014-02-03 13:21:01 -0700135 * of fstypes[], since that is essentially a "virtual" (non-existent)
136 * filesystem.
137 */
138 bool null_dev_desc_ok;
Simon Glasse3394752016-02-29 15:25:34 -0700139 int (*probe)(struct blk_desc *fs_dev_desc,
Simon Glassc1c4a8f2020-05-10 11:39:57 -0600140 struct disk_partition *fs_partition);
Simon Glass1aede482012-12-26 09:53:29 +0000141 int (*ls)(const char *dirname);
Stephen Warrend008fbb2014-02-03 13:21:00 -0700142 int (*exists)(const char *filename);
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800143 int (*size)(const char *filename, loff_t *size);
144 int (*read)(const char *filename, void *buf, loff_t offset,
145 loff_t len, loff_t *actread);
146 int (*write)(const char *filename, void *buf, loff_t offset,
147 loff_t len, loff_t *actwrite);
Simon Glass1aede482012-12-26 09:53:29 +0000148 void (*close)(void);
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100149 int (*uuid)(char *uuid_str);
Rob Clark2b7bfd92017-09-09 13:15:55 -0400150 /*
151 * Open a directory stream. On success return 0 and directory
152 * stream pointer via 'dirsp'. On error, return -errno. See
153 * fs_opendir().
154 */
155 int (*opendir)(const char *filename, struct fs_dir_stream **dirsp);
156 /*
157 * Read next entry from directory stream. On success return 0
158 * and directory entry pointer via 'dentp'. On error return
159 * -errno. See fs_readdir().
160 */
161 int (*readdir)(struct fs_dir_stream *dirs, struct fs_dirent **dentp);
162 /* see fs_closedir() */
163 void (*closedir)(struct fs_dir_stream *dirs);
AKASHI Takahiro1ba42532018-09-11 15:59:13 +0900164 int (*unlink)(const char *filename);
AKASHI Takahiroadc8c9f2018-09-11 15:59:08 +0900165 int (*mkdir)(const char *dirname);
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +0100166 int (*ln)(const char *filename, const char *target);
Simon Glass1aede482012-12-26 09:53:29 +0000167};
168
169static struct fstype_info fstypes[] = {
170#ifdef CONFIG_FS_FAT
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000171 {
172 .fstype = FS_TYPE_FAT,
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100173 .name = "fat",
Stephen Warrenec63d4a2014-02-03 13:21:01 -0700174 .null_dev_desc_ok = false,
Simon Glass19e38582012-12-26 09:53:33 +0000175 .probe = fat_set_blk_dev,
176 .close = fat_close,
Rob Clark60d74a92017-09-09 13:15:58 -0400177 .ls = fs_ls_generic,
Stephen Warren1d2f9a02014-02-03 13:21:10 -0700178 .exists = fat_exists,
Stephen Warren3eb58f52014-06-11 12:47:26 -0600179 .size = fat_size,
Simon Glass19e38582012-12-26 09:53:33 +0000180 .read = fat_read_file,
Tien Fong Chee87fda0c2019-01-23 14:20:04 +0800181#if CONFIG_IS_ENABLED(FAT_WRITE)
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800182 .write = file_fat_write,
AKASHI Takahiro73b34972018-09-11 15:59:14 +0900183 .unlink = fat_unlink,
AKASHI Takahiro1c24b7b2018-09-11 15:59:10 +0900184 .mkdir = fat_mkdir,
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800185#else
Stephen Warren9df25802014-02-03 13:20:59 -0700186 .write = fs_write_unsupported,
AKASHI Takahiro73b34972018-09-11 15:59:14 +0900187 .unlink = fs_unlink_unsupported,
AKASHI Takahiro1c24b7b2018-09-11 15:59:10 +0900188 .mkdir = fs_mkdir_unsupported,
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800189#endif
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100190 .uuid = fs_uuid_unsupported,
Rob Clark60d74a92017-09-09 13:15:58 -0400191 .opendir = fat_opendir,
192 .readdir = fat_readdir,
193 .closedir = fat_closedir,
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +0100194 .ln = fs_ln_unsupported,
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000195 },
Simon Glass1aede482012-12-26 09:53:29 +0000196#endif
Tien Fong Chee64eab042019-01-23 14:20:06 +0800197
198#if CONFIG_IS_ENABLED(FS_EXT4)
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000199 {
200 .fstype = FS_TYPE_EXT,
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100201 .name = "ext4",
Stephen Warrenec63d4a2014-02-03 13:21:01 -0700202 .null_dev_desc_ok = false,
Simon Glass19e38582012-12-26 09:53:33 +0000203 .probe = ext4fs_probe,
204 .close = ext4fs_close,
Simon Glass1aede482012-12-26 09:53:29 +0000205 .ls = ext4fs_ls,
Stephen Warren12d6d0c2014-02-03 13:21:09 -0700206 .exists = ext4fs_exists,
Stephen Warren3eb58f52014-06-11 12:47:26 -0600207 .size = ext4fs_size,
Simon Glass19e38582012-12-26 09:53:33 +0000208 .read = ext4_read_file,
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800209#ifdef CONFIG_CMD_EXT4_WRITE
210 .write = ext4_write_file,
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +0100211 .ln = ext4fs_create_link,
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800212#else
Stephen Warren9df25802014-02-03 13:20:59 -0700213 .write = fs_write_unsupported,
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +0100214 .ln = fs_ln_unsupported,
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800215#endif
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100216 .uuid = ext4fs_uuid,
Rob Clark2b7bfd92017-09-09 13:15:55 -0400217 .opendir = fs_opendir_unsupported,
AKASHI Takahiro1ba42532018-09-11 15:59:13 +0900218 .unlink = fs_unlink_unsupported,
AKASHI Takahiroadc8c9f2018-09-11 15:59:08 +0900219 .mkdir = fs_mkdir_unsupported,
Simon Glass1aede482012-12-26 09:53:29 +0000220 },
221#endif
Simon Glass11842872012-12-26 09:53:35 +0000222#ifdef CONFIG_SANDBOX
223 {
224 .fstype = FS_TYPE_SANDBOX,
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100225 .name = "sandbox",
Stephen Warrenec63d4a2014-02-03 13:21:01 -0700226 .null_dev_desc_ok = true,
Simon Glass11842872012-12-26 09:53:35 +0000227 .probe = sandbox_fs_set_blk_dev,
228 .close = sandbox_fs_close,
229 .ls = sandbox_fs_ls,
Stephen Warren97d66f22014-02-03 13:21:07 -0700230 .exists = sandbox_fs_exists,
Stephen Warren3eb58f52014-06-11 12:47:26 -0600231 .size = sandbox_fs_size,
Simon Glass11842872012-12-26 09:53:35 +0000232 .read = fs_read_sandbox,
Simon Glassea307e82013-04-20 08:42:51 +0000233 .write = fs_write_sandbox,
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100234 .uuid = fs_uuid_unsupported,
Rob Clark2b7bfd92017-09-09 13:15:55 -0400235 .opendir = fs_opendir_unsupported,
AKASHI Takahiro1ba42532018-09-11 15:59:13 +0900236 .unlink = fs_unlink_unsupported,
AKASHI Takahiroadc8c9f2018-09-11 15:59:08 +0900237 .mkdir = fs_mkdir_unsupported,
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +0100238 .ln = fs_ln_unsupported,
Simon Glass11842872012-12-26 09:53:35 +0000239 },
240#endif
Hans de Goede690c7962015-09-17 18:46:58 -0400241#ifdef CONFIG_CMD_UBIFS
242 {
243 .fstype = FS_TYPE_UBIFS,
244 .name = "ubifs",
245 .null_dev_desc_ok = true,
246 .probe = ubifs_set_blk_dev,
247 .close = ubifs_close,
248 .ls = ubifs_ls,
249 .exists = ubifs_exists,
250 .size = ubifs_size,
251 .read = ubifs_read,
252 .write = fs_write_unsupported,
253 .uuid = fs_uuid_unsupported,
Rob Clark2b7bfd92017-09-09 13:15:55 -0400254 .opendir = fs_opendir_unsupported,
AKASHI Takahiro1ba42532018-09-11 15:59:13 +0900255 .unlink = fs_unlink_unsupported,
AKASHI Takahiroadc8c9f2018-09-11 15:59:08 +0900256 .mkdir = fs_mkdir_unsupported,
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +0100257 .ln = fs_ln_unsupported,
Hans de Goede690c7962015-09-17 18:46:58 -0400258 },
259#endif
Marek BehĂșn98ec1d12017-09-03 17:00:29 +0200260#ifdef CONFIG_FS_BTRFS
261 {
262 .fstype = FS_TYPE_BTRFS,
263 .name = "btrfs",
264 .null_dev_desc_ok = false,
265 .probe = btrfs_probe,
266 .close = btrfs_close,
267 .ls = btrfs_ls,
268 .exists = btrfs_exists,
269 .size = btrfs_size,
270 .read = btrfs_read,
271 .write = fs_write_unsupported,
272 .uuid = btrfs_uuid,
Marek BehĂșn90762d92017-10-06 16:56:07 +0200273 .opendir = fs_opendir_unsupported,
AKASHI Takahiro1ba42532018-09-11 15:59:13 +0900274 .unlink = fs_unlink_unsupported,
AKASHI Takahiroadc8c9f2018-09-11 15:59:08 +0900275 .mkdir = fs_mkdir_unsupported,
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +0100276 .ln = fs_ln_unsupported,
Marek BehĂșn98ec1d12017-09-03 17:00:29 +0200277 },
278#endif
Simon Glass1aede482012-12-26 09:53:29 +0000279 {
280 .fstype = FS_TYPE_ANY,
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100281 .name = "unsupported",
Stephen Warrenec63d4a2014-02-03 13:21:01 -0700282 .null_dev_desc_ok = true,
Simon Glass1aede482012-12-26 09:53:29 +0000283 .probe = fs_probe_unsupported,
284 .close = fs_close_unsupported,
285 .ls = fs_ls_unsupported,
Stephen Warrend008fbb2014-02-03 13:21:00 -0700286 .exists = fs_exists_unsupported,
Stephen Warren3eb58f52014-06-11 12:47:26 -0600287 .size = fs_size_unsupported,
Simon Glass1aede482012-12-26 09:53:29 +0000288 .read = fs_read_unsupported,
Simon Glasseda14ea2013-04-20 08:42:50 +0000289 .write = fs_write_unsupported,
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100290 .uuid = fs_uuid_unsupported,
Rob Clark2b7bfd92017-09-09 13:15:55 -0400291 .opendir = fs_opendir_unsupported,
AKASHI Takahiro1ba42532018-09-11 15:59:13 +0900292 .unlink = fs_unlink_unsupported,
AKASHI Takahiroadc8c9f2018-09-11 15:59:08 +0900293 .mkdir = fs_mkdir_unsupported,
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +0100294 .ln = fs_ln_unsupported,
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000295 },
296};
297
Simon Glasse6aad852012-12-26 09:53:30 +0000298static struct fstype_info *fs_get_info(int fstype)
299{
300 struct fstype_info *info;
301 int i;
302
303 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes) - 1; i++, info++) {
304 if (fstype == info->fstype)
305 return info;
306 }
307
308 /* Return the 'unsupported' sentinel */
309 return info;
310}
311
Alex Kiernan3a6163a2018-05-29 15:30:50 +0000312/**
AKASHI Takahiro80ac7342019-10-07 14:59:37 +0900313 * fs_get_type() - Get type of current filesystem
314 *
315 * Return: filesystem type
316 *
317 * Returns filesystem type representing the current filesystem, or
318 * FS_TYPE_ANY for any unrecognised filesystem.
319 */
320int fs_get_type(void)
321{
322 return fs_type;
323}
324
325/**
Alex Kiernan3a6163a2018-05-29 15:30:50 +0000326 * fs_get_type_name() - Get type of current filesystem
327 *
328 * Return: Pointer to filesystem name
329 *
330 * Returns a string describing the current filesystem, or the sentinel
331 * "unsupported" for any unrecognised filesystem.
332 */
333const char *fs_get_type_name(void)
334{
335 return fs_get_info(fs_type)->name;
336}
337
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000338int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
339{
Simon Glass1aede482012-12-26 09:53:29 +0000340 struct fstype_info *info;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000341 int part, i;
Stephen Warren44161af2012-10-30 07:50:47 +0000342#ifdef CONFIG_NEEDS_MANUAL_RELOC
343 static int relocated;
344
345 if (!relocated) {
Simon Glass1aede482012-12-26 09:53:29 +0000346 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes);
347 i++, info++) {
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100348 info->name += gd->reloc_off;
Simon Glass1aede482012-12-26 09:53:29 +0000349 info->probe += gd->reloc_off;
350 info->close += gd->reloc_off;
351 info->ls += gd->reloc_off;
352 info->read += gd->reloc_off;
Simon Glasseda14ea2013-04-20 08:42:50 +0000353 info->write += gd->reloc_off;
Simon Glass1aede482012-12-26 09:53:29 +0000354 }
Stephen Warren44161af2012-10-30 07:50:47 +0000355 relocated = 1;
356 }
357#endif
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000358
Simon Glasse76ee972016-02-29 15:25:44 -0700359 part = blk_get_device_part_str(ifname, dev_part_str, &fs_dev_desc,
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000360 &fs_partition, 1);
361 if (part < 0)
362 return -1;
363
Simon Glass1aede482012-12-26 09:53:29 +0000364 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
365 if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY &&
366 fstype != info->fstype)
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000367 continue;
368
Stephen Warrenec63d4a2014-02-03 13:21:01 -0700369 if (!fs_dev_desc && !info->null_dev_desc_ok)
370 continue;
371
Simon Glass6a46e2f2012-12-26 09:53:31 +0000372 if (!info->probe(fs_dev_desc, &fs_partition)) {
Simon Glass1aede482012-12-26 09:53:29 +0000373 fs_type = info->fstype;
Rob Clark2b7bfd92017-09-09 13:15:55 -0400374 fs_dev_part = part;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000375 return 0;
376 }
377 }
378
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000379 return -1;
380}
381
Rob Clark2b7bfd92017-09-09 13:15:55 -0400382/* set current blk device w/ blk_desc + partition # */
383int fs_set_blk_dev_with_part(struct blk_desc *desc, int part)
384{
385 struct fstype_info *info;
386 int ret, i;
387
388 if (part >= 1)
389 ret = part_get_info(desc, part, &fs_partition);
390 else
391 ret = part_get_info_whole_disk(desc, &fs_partition);
392 if (ret)
393 return ret;
394 fs_dev_desc = desc;
395
396 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
397 if (!info->probe(fs_dev_desc, &fs_partition)) {
398 fs_type = info->fstype;
AKASHI Takahiro43efaa02018-10-17 16:32:02 +0900399 fs_dev_part = part;
Rob Clark2b7bfd92017-09-09 13:15:55 -0400400 return 0;
401 }
402 }
403
404 return -1;
405}
406
AKASHI Takahiroca8e3772019-10-07 14:59:35 +0900407void fs_close(void)
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000408{
Simon Glasse6aad852012-12-26 09:53:30 +0000409 struct fstype_info *info = fs_get_info(fs_type);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000410
Simon Glasse6aad852012-12-26 09:53:30 +0000411 info->close();
Simon Glass19e38582012-12-26 09:53:33 +0000412
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000413 fs_type = FS_TYPE_ANY;
414}
415
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100416int fs_uuid(char *uuid_str)
417{
418 struct fstype_info *info = fs_get_info(fs_type);
419
420 return info->uuid(uuid_str);
421}
422
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000423int fs_ls(const char *dirname)
424{
425 int ret;
426
Simon Glasse6aad852012-12-26 09:53:30 +0000427 struct fstype_info *info = fs_get_info(fs_type);
428
429 ret = info->ls(dirname);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000430
431 fs_close();
432
433 return ret;
434}
435
Stephen Warrend008fbb2014-02-03 13:21:00 -0700436int fs_exists(const char *filename)
437{
438 int ret;
439
440 struct fstype_info *info = fs_get_info(fs_type);
441
442 ret = info->exists(filename);
443
444 fs_close();
445
446 return ret;
447}
448
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800449int fs_size(const char *filename, loff_t *size)
Stephen Warren3eb58f52014-06-11 12:47:26 -0600450{
451 int ret;
452
453 struct fstype_info *info = fs_get_info(fs_type);
454
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800455 ret = info->size(filename, size);
Stephen Warren3eb58f52014-06-11 12:47:26 -0600456
457 fs_close();
458
459 return ret;
460}
461
Simon Goldschmidt5b2c6872019-01-14 22:38:19 +0100462#ifdef CONFIG_LMB
463/* Check if a file may be read to the given address */
464static int fs_read_lmb_check(const char *filename, ulong addr, loff_t offset,
465 loff_t len, struct fstype_info *info)
466{
467 struct lmb lmb;
468 int ret;
469 loff_t size;
470 loff_t read_len;
471
472 /* get the actual size of the file */
473 ret = info->size(filename, &size);
474 if (ret)
475 return ret;
476 if (offset >= size) {
477 /* offset >= EOF, no bytes will be written */
478 return 0;
479 }
480 read_len = size - offset;
481
482 /* limit to 'len' if it is smaller */
483 if (len && len < read_len)
484 read_len = len;
485
Simon Goldschmidt8890e7d2019-01-26 22:13:04 +0100486 lmb_init_and_reserve(&lmb, gd->bd, (void *)gd->fdt_blob);
Simon Goldschmidt5b2c6872019-01-14 22:38:19 +0100487 lmb_dump_all(&lmb);
488
489 if (lmb_alloc_addr(&lmb, addr, read_len) == addr)
490 return 0;
491
492 printf("** Reading file would overwrite reserved memory **\n");
493 return -ENOSPC;
494}
495#endif
496
497static int _fs_read(const char *filename, ulong addr, loff_t offset, loff_t len,
498 int do_lmb_check, loff_t *actread)
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000499{
Simon Glasse6aad852012-12-26 09:53:30 +0000500 struct fstype_info *info = fs_get_info(fs_type);
Simon Glasscbe5d5d2012-12-26 09:53:32 +0000501 void *buf;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000502 int ret;
503
Simon Goldschmidt5b2c6872019-01-14 22:38:19 +0100504#ifdef CONFIG_LMB
505 if (do_lmb_check) {
506 ret = fs_read_lmb_check(filename, addr, offset, len, info);
507 if (ret)
508 return ret;
509 }
510#endif
511
Simon Glasscbe5d5d2012-12-26 09:53:32 +0000512 /*
513 * We don't actually know how many bytes are being read, since len==0
514 * means read the whole file.
515 */
516 buf = map_sysmem(addr, len);
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800517 ret = info->read(filename, buf, offset, len, actread);
Simon Glasscbe5d5d2012-12-26 09:53:32 +0000518 unmap_sysmem(buf);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000519
Simon Glasse6aad852012-12-26 09:53:30 +0000520 /* If we requested a specific number of bytes, check we got it */
Max Krummenacher56d9cdf2015-08-05 17:16:58 +0200521 if (ret == 0 && len && *actread != len)
Heinrich Schuchardtf02c5c52018-01-01 21:15:37 +0100522 debug("** %s shorter than offset + len **\n", filename);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000523 fs_close();
524
525 return ret;
526}
527
Simon Goldschmidt5b2c6872019-01-14 22:38:19 +0100528int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len,
529 loff_t *actread)
530{
531 return _fs_read(filename, addr, offset, len, 0, actread);
532}
533
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800534int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
535 loff_t *actwrite)
Simon Glasseda14ea2013-04-20 08:42:50 +0000536{
537 struct fstype_info *info = fs_get_info(fs_type);
538 void *buf;
539 int ret;
540
Simon Glasseda14ea2013-04-20 08:42:50 +0000541 buf = map_sysmem(addr, len);
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800542 ret = info->write(filename, buf, offset, len, actwrite);
Simon Glasseda14ea2013-04-20 08:42:50 +0000543 unmap_sysmem(buf);
544
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800545 if (ret < 0 && len != *actwrite) {
Simon Glasseda14ea2013-04-20 08:42:50 +0000546 printf("** Unable to write file %s **\n", filename);
547 ret = -1;
548 }
549 fs_close();
550
551 return ret;
552}
553
Rob Clark2b7bfd92017-09-09 13:15:55 -0400554struct fs_dir_stream *fs_opendir(const char *filename)
555{
556 struct fstype_info *info = fs_get_info(fs_type);
557 struct fs_dir_stream *dirs = NULL;
558 int ret;
559
560 ret = info->opendir(filename, &dirs);
561 fs_close();
562 if (ret) {
563 errno = -ret;
564 return NULL;
565 }
566
567 dirs->desc = fs_dev_desc;
568 dirs->part = fs_dev_part;
569
570 return dirs;
571}
572
573struct fs_dirent *fs_readdir(struct fs_dir_stream *dirs)
574{
575 struct fstype_info *info;
576 struct fs_dirent *dirent;
577 int ret;
578
579 fs_set_blk_dev_with_part(dirs->desc, dirs->part);
580 info = fs_get_info(fs_type);
581
582 ret = info->readdir(dirs, &dirent);
583 fs_close();
584 if (ret) {
585 errno = -ret;
586 return NULL;
587 }
588
589 return dirent;
590}
591
592void fs_closedir(struct fs_dir_stream *dirs)
593{
594 struct fstype_info *info;
595
596 if (!dirs)
597 return;
598
599 fs_set_blk_dev_with_part(dirs->desc, dirs->part);
600 info = fs_get_info(fs_type);
601
602 info->closedir(dirs);
603 fs_close();
604}
605
AKASHI Takahiro1ba42532018-09-11 15:59:13 +0900606int fs_unlink(const char *filename)
607{
608 int ret;
609
610 struct fstype_info *info = fs_get_info(fs_type);
611
612 ret = info->unlink(filename);
613
AKASHI Takahiro1ba42532018-09-11 15:59:13 +0900614 fs_close();
615
616 return ret;
617}
AKASHI Takahiroadc8c9f2018-09-11 15:59:08 +0900618
619int fs_mkdir(const char *dirname)
620{
621 int ret;
622
623 struct fstype_info *info = fs_get_info(fs_type);
624
625 ret = info->mkdir(dirname);
626
AKASHI Takahiroadc8c9f2018-09-11 15:59:08 +0900627 fs_close();
628
629 return ret;
630}
Rob Clark2b7bfd92017-09-09 13:15:55 -0400631
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +0100632int fs_ln(const char *fname, const char *target)
633{
634 struct fstype_info *info = fs_get_info(fs_type);
635 int ret;
636
637 ret = info->ln(fname, target);
638
639 if (ret < 0) {
640 printf("** Unable to create link %s -> %s **\n", fname, target);
641 ret = -1;
642 }
643 fs_close();
644
645 return ret;
646}
647
Simon Glassed38aef2020-05-10 11:40:03 -0600648int do_size(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[],
649 int fstype)
Stephen Warren3eb58f52014-06-11 12:47:26 -0600650{
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800651 loff_t size;
Stephen Warren3eb58f52014-06-11 12:47:26 -0600652
653 if (argc != 4)
654 return CMD_RET_USAGE;
655
656 if (fs_set_blk_dev(argv[1], argv[2], fstype))
657 return 1;
658
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800659 if (fs_size(argv[3], &size) < 0)
Stephen Warren3eb58f52014-06-11 12:47:26 -0600660 return CMD_RET_FAILURE;
661
Simon Glass4d949a22017-08-03 12:22:10 -0600662 env_set_hex("filesize", size);
Stephen Warren3eb58f52014-06-11 12:47:26 -0600663
664 return 0;
665}
666
Simon Glassed38aef2020-05-10 11:40:03 -0600667int do_load(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[],
668 int fstype)
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000669{
670 unsigned long addr;
671 const char *addr_str;
672 const char *filename;
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800673 loff_t bytes;
674 loff_t pos;
675 loff_t len_read;
676 int ret;
Andreas Bießmann1fd2d8a2012-11-14 13:32:37 +0100677 unsigned long time;
Pavel Machek4c1a9c52014-07-09 22:42:57 +0200678 char *ep;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000679
Stephen Warrenb2d5cd62012-10-30 12:04:17 +0000680 if (argc < 2)
681 return CMD_RET_USAGE;
682 if (argc > 7)
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000683 return CMD_RET_USAGE;
684
Stephen Warrenb2d5cd62012-10-30 12:04:17 +0000685 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000686 return 1;
687
688 if (argc >= 4) {
Pavel Machek4c1a9c52014-07-09 22:42:57 +0200689 addr = simple_strtoul(argv[3], &ep, 16);
690 if (ep == argv[3] || *ep != '\0')
691 return CMD_RET_USAGE;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000692 } else {
Simon Glass64b723f2017-08-03 12:22:12 -0600693 addr_str = env_get("loadaddr");
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000694 if (addr_str != NULL)
695 addr = simple_strtoul(addr_str, NULL, 16);
696 else
697 addr = CONFIG_SYS_LOAD_ADDR;
698 }
699 if (argc >= 5) {
700 filename = argv[4];
701 } else {
Simon Glass64b723f2017-08-03 12:22:12 -0600702 filename = env_get("bootfile");
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000703 if (!filename) {
704 puts("** No boot file defined **\n");
705 return 1;
706 }
707 }
708 if (argc >= 6)
Wolfgang Denka10c7a52013-10-05 21:07:25 +0200709 bytes = simple_strtoul(argv[5], NULL, 16);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000710 else
711 bytes = 0;
712 if (argc >= 7)
Wolfgang Denka10c7a52013-10-05 21:07:25 +0200713 pos = simple_strtoul(argv[6], NULL, 16);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000714 else
715 pos = 0;
716
Mian Yousaf Kaukab961ebe82019-06-18 15:03:44 +0200717#ifdef CONFIG_CMD_BOOTEFI
718 efi_set_bootdev(argv[1], (argc > 2) ? argv[2] : "",
719 (argc > 4) ? argv[4] : "");
720#endif
Andreas Bießmann1fd2d8a2012-11-14 13:32:37 +0100721 time = get_timer(0);
Simon Goldschmidt5b2c6872019-01-14 22:38:19 +0100722 ret = _fs_read(filename, addr, pos, bytes, 1, &len_read);
Andreas Bießmann1fd2d8a2012-11-14 13:32:37 +0100723 time = get_timer(time);
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800724 if (ret < 0)
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000725 return 1;
726
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800727 printf("%llu bytes read in %lu ms", len_read, time);
Andreas Bießmann1fd2d8a2012-11-14 13:32:37 +0100728 if (time > 0) {
729 puts(" (");
Tom Rinia17b7bc2014-11-24 11:50:46 -0500730 print_size(div_u64(len_read, time) * 1000, "/s");
Andreas Bießmann1fd2d8a2012-11-14 13:32:37 +0100731 puts(")");
732 }
733 puts("\n");
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000734
Simon Glass4d949a22017-08-03 12:22:10 -0600735 env_set_hex("fileaddr", addr);
736 env_set_hex("filesize", len_read);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000737
738 return 0;
739}
740
Simon Glassed38aef2020-05-10 11:40:03 -0600741int do_ls(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[],
742 int fstype)
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000743{
744 if (argc < 2)
745 return CMD_RET_USAGE;
Stephen Warrenb2d5cd62012-10-30 12:04:17 +0000746 if (argc > 4)
747 return CMD_RET_USAGE;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000748
749 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
750 return 1;
751
Stephen Warrenb2d5cd62012-10-30 12:04:17 +0000752 if (fs_ls(argc >= 4 ? argv[3] : "/"))
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000753 return 1;
754
755 return 0;
756}
Simon Glasseda14ea2013-04-20 08:42:50 +0000757
Stephen Warrend008fbb2014-02-03 13:21:00 -0700758int file_exists(const char *dev_type, const char *dev_part, const char *file,
759 int fstype)
760{
761 if (fs_set_blk_dev(dev_type, dev_part, fstype))
762 return 0;
763
764 return fs_exists(file);
765}
766
Simon Glassed38aef2020-05-10 11:40:03 -0600767int do_save(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[],
768 int fstype)
Simon Glasseda14ea2013-04-20 08:42:50 +0000769{
770 unsigned long addr;
771 const char *filename;
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800772 loff_t bytes;
773 loff_t pos;
774 loff_t len;
775 int ret;
Simon Glasseda14ea2013-04-20 08:42:50 +0000776 unsigned long time;
777
778 if (argc < 6 || argc > 7)
779 return CMD_RET_USAGE;
780
781 if (fs_set_blk_dev(argv[1], argv[2], fstype))
782 return 1;
783
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800784 addr = simple_strtoul(argv[3], NULL, 16);
785 filename = argv[4];
Wolfgang Denka10c7a52013-10-05 21:07:25 +0200786 bytes = simple_strtoul(argv[5], NULL, 16);
Simon Glasseda14ea2013-04-20 08:42:50 +0000787 if (argc >= 7)
Wolfgang Denka10c7a52013-10-05 21:07:25 +0200788 pos = simple_strtoul(argv[6], NULL, 16);
Simon Glasseda14ea2013-04-20 08:42:50 +0000789 else
790 pos = 0;
791
792 time = get_timer(0);
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800793 ret = fs_write(filename, addr, pos, bytes, &len);
Simon Glasseda14ea2013-04-20 08:42:50 +0000794 time = get_timer(time);
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800795 if (ret < 0)
Simon Glasseda14ea2013-04-20 08:42:50 +0000796 return 1;
797
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800798 printf("%llu bytes written in %lu ms", len, time);
Simon Glasseda14ea2013-04-20 08:42:50 +0000799 if (time > 0) {
800 puts(" (");
Tom Rinia17b7bc2014-11-24 11:50:46 -0500801 print_size(div_u64(len, time) * 1000, "/s");
Simon Glasseda14ea2013-04-20 08:42:50 +0000802 puts(")");
803 }
804 puts("\n");
805
806 return 0;
807}
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100808
Simon Glassed38aef2020-05-10 11:40:03 -0600809int do_fs_uuid(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[],
810 int fstype)
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100811{
812 int ret;
813 char uuid[37];
814 memset(uuid, 0, sizeof(uuid));
815
816 if (argc < 3 || argc > 4)
817 return CMD_RET_USAGE;
818
819 if (fs_set_blk_dev(argv[1], argv[2], fstype))
820 return 1;
821
822 ret = fs_uuid(uuid);
823 if (ret)
824 return CMD_RET_FAILURE;
825
826 if (argc == 4)
Simon Glass6a38e412017-08-03 12:22:09 -0600827 env_set(argv[3], uuid);
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100828 else
829 printf("%s\n", uuid);
830
831 return CMD_RET_SUCCESS;
832}
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100833
Simon Glassed38aef2020-05-10 11:40:03 -0600834int do_fs_type(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100835{
836 struct fstype_info *info;
837
838 if (argc < 3 || argc > 4)
839 return CMD_RET_USAGE;
840
841 if (fs_set_blk_dev(argv[1], argv[2], FS_TYPE_ANY))
842 return 1;
843
844 info = fs_get_info(fs_type);
845
846 if (argc == 4)
Simon Glass6a38e412017-08-03 12:22:09 -0600847 env_set(argv[3], info->name);
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100848 else
849 printf("%s\n", info->name);
850
Marek Vasut08d1c422019-02-06 13:19:29 +0100851 fs_close();
852
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100853 return CMD_RET_SUCCESS;
854}
855
Simon Glassed38aef2020-05-10 11:40:03 -0600856int do_rm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[],
AKASHI Takahiro1ba42532018-09-11 15:59:13 +0900857 int fstype)
858{
859 if (argc != 4)
860 return CMD_RET_USAGE;
861
862 if (fs_set_blk_dev(argv[1], argv[2], fstype))
863 return 1;
864
865 if (fs_unlink(argv[3]))
866 return 1;
867
868 return 0;
869}
870
Simon Glassed38aef2020-05-10 11:40:03 -0600871int do_mkdir(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[],
AKASHI Takahiroadc8c9f2018-09-11 15:59:08 +0900872 int fstype)
873{
874 int ret;
875
876 if (argc != 4)
877 return CMD_RET_USAGE;
878
879 if (fs_set_blk_dev(argv[1], argv[2], fstype))
880 return 1;
881
882 ret = fs_mkdir(argv[3]);
883 if (ret) {
884 printf("** Unable to create a directory \"%s\" **\n", argv[3]);
885 return 1;
886 }
887
888 return 0;
889}
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +0100890
Simon Glassed38aef2020-05-10 11:40:03 -0600891int do_ln(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[],
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +0100892 int fstype)
893{
894 if (argc != 5)
895 return CMD_RET_USAGE;
896
897 if (fs_set_blk_dev(argv[1], argv[2], fstype))
898 return 1;
899
900 if (fs_ln(argv[3], argv[4]))
901 return 1;
902
903 return 0;
904}