blob: 48d8f1f6dab88ada6d4debf1cd51d299300c783d [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
6#include <config.h>
Christian Gmeiner9f9eec32014-11-12 14:35:04 +01007#include <errno.h>
Stephen Warreneefbc3f2012-10-22 06:43:51 +00008#include <common.h>
Joe Hershberger65b905b2015-03-22 17:08:59 -05009#include <mapmem.h>
Stephen Warreneefbc3f2012-10-22 06:43:51 +000010#include <part.h>
11#include <ext4fs.h>
12#include <fat.h>
13#include <fs.h>
Simon Glass11842872012-12-26 09:53:35 +000014#include <sandboxfs.h>
Hans de Goede690c7962015-09-17 18:46:58 -040015#include <ubifs_uboot.h>
Marek BehĂșn98ec1d12017-09-03 17:00:29 +020016#include <btrfs.h>
Simon Glasscbe5d5d2012-12-26 09:53:32 +000017#include <asm/io.h>
Tom Rinia17b7bc2014-11-24 11:50:46 -050018#include <div64.h>
19#include <linux/math64.h>
Mian Yousaf Kaukab961ebe82019-06-18 15:03:44 +020020#include <efi_loader.h>
Stephen Warreneefbc3f2012-10-22 06:43:51 +000021
Stephen Warren44161af2012-10-30 07:50:47 +000022DECLARE_GLOBAL_DATA_PTR;
23
Simon Glasse3394752016-02-29 15:25:34 -070024static struct blk_desc *fs_dev_desc;
Rob Clark2b7bfd92017-09-09 13:15:55 -040025static int fs_dev_part;
Stephen Warreneefbc3f2012-10-22 06:43:51 +000026static disk_partition_t fs_partition;
27static int fs_type = FS_TYPE_ANY;
28
Simon Glasse3394752016-02-29 15:25:34 -070029static inline int fs_probe_unsupported(struct blk_desc *fs_dev_desc,
Simon Glass6a46e2f2012-12-26 09:53:31 +000030 disk_partition_t *fs_partition)
Simon Glass1aede482012-12-26 09:53:29 +000031{
32 printf("** Unrecognized filesystem type **\n");
33 return -1;
34}
35
Stephen Warreneefbc3f2012-10-22 06:43:51 +000036static inline int fs_ls_unsupported(const char *dirname)
37{
Stephen Warreneefbc3f2012-10-22 06:43:51 +000038 return -1;
39}
40
Rob Clark60d74a92017-09-09 13:15:58 -040041/* generic implementation of ls in terms of opendir/readdir/closedir */
42__maybe_unused
43static int fs_ls_generic(const char *dirname)
44{
45 struct fs_dir_stream *dirs;
46 struct fs_dirent *dent;
47 int nfiles = 0, ndirs = 0;
48
49 dirs = fs_opendir(dirname);
50 if (!dirs)
51 return -errno;
52
53 while ((dent = fs_readdir(dirs))) {
54 if (dent->type == FS_DT_DIR) {
55 printf(" %s/\n", dent->name);
56 ndirs++;
57 } else {
58 printf(" %8lld %s\n", dent->size, dent->name);
59 nfiles++;
60 }
61 }
62
63 fs_closedir(dirs);
64
65 printf("\n%d file(s), %d dir(s)\n\n", nfiles, ndirs);
66
67 return 0;
68}
69
Stephen Warrend008fbb2014-02-03 13:21:00 -070070static inline int fs_exists_unsupported(const char *filename)
71{
72 return 0;
73}
74
Suriyan Ramasami96171fb2014-11-17 14:39:38 -080075static inline int fs_size_unsupported(const char *filename, loff_t *size)
Stephen Warren3eb58f52014-06-11 12:47:26 -060076{
77 return -1;
78}
79
Simon Glasscbe5d5d2012-12-26 09:53:32 +000080static inline int fs_read_unsupported(const char *filename, void *buf,
Suriyan Ramasami96171fb2014-11-17 14:39:38 -080081 loff_t offset, loff_t len,
82 loff_t *actread)
Stephen Warreneefbc3f2012-10-22 06:43:51 +000083{
Stephen Warreneefbc3f2012-10-22 06:43:51 +000084 return -1;
85}
86
Simon Glasseda14ea2013-04-20 08:42:50 +000087static inline int fs_write_unsupported(const char *filename, void *buf,
Suriyan Ramasami96171fb2014-11-17 14:39:38 -080088 loff_t offset, loff_t len,
89 loff_t *actwrite)
Simon Glasseda14ea2013-04-20 08:42:50 +000090{
91 return -1;
92}
93
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +010094static inline int fs_ln_unsupported(const char *filename, const char *target)
95{
96 return -1;
97}
98
Simon Glass1aede482012-12-26 09:53:29 +000099static inline void fs_close_unsupported(void)
100{
101}
102
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100103static inline int fs_uuid_unsupported(char *uuid_str)
104{
105 return -1;
106}
107
Rob Clark2b7bfd92017-09-09 13:15:55 -0400108static inline int fs_opendir_unsupported(const char *filename,
109 struct fs_dir_stream **dirs)
110{
111 return -EACCES;
112}
113
AKASHI Takahiro1ba42532018-09-11 15:59:13 +0900114static inline int fs_unlink_unsupported(const char *filename)
115{
116 return -1;
117}
118
AKASHI Takahiroadc8c9f2018-09-11 15:59:08 +0900119static inline int fs_mkdir_unsupported(const char *dirname)
120{
121 return -1;
122}
123
Simon Glass1aede482012-12-26 09:53:29 +0000124struct fstype_info {
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000125 int fstype;
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100126 char *name;
Stephen Warrenec63d4a2014-02-03 13:21:01 -0700127 /*
128 * Is it legal to pass NULL as .probe()'s fs_dev_desc parameter? This
129 * should be false in most cases. For "virtual" filesystems which
130 * aren't based on a U-Boot block device (e.g. sandbox), this can be
Heinrich Schuchardt99dc17d2018-08-11 15:52:14 +0200131 * set to true. This should also be true for the dummy entry at the end
Stephen Warrenec63d4a2014-02-03 13:21:01 -0700132 * of fstypes[], since that is essentially a "virtual" (non-existent)
133 * filesystem.
134 */
135 bool null_dev_desc_ok;
Simon Glasse3394752016-02-29 15:25:34 -0700136 int (*probe)(struct blk_desc *fs_dev_desc,
Simon Glass6a46e2f2012-12-26 09:53:31 +0000137 disk_partition_t *fs_partition);
Simon Glass1aede482012-12-26 09:53:29 +0000138 int (*ls)(const char *dirname);
Stephen Warrend008fbb2014-02-03 13:21:00 -0700139 int (*exists)(const char *filename);
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800140 int (*size)(const char *filename, loff_t *size);
141 int (*read)(const char *filename, void *buf, loff_t offset,
142 loff_t len, loff_t *actread);
143 int (*write)(const char *filename, void *buf, loff_t offset,
144 loff_t len, loff_t *actwrite);
Simon Glass1aede482012-12-26 09:53:29 +0000145 void (*close)(void);
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100146 int (*uuid)(char *uuid_str);
Rob Clark2b7bfd92017-09-09 13:15:55 -0400147 /*
148 * Open a directory stream. On success return 0 and directory
149 * stream pointer via 'dirsp'. On error, return -errno. See
150 * fs_opendir().
151 */
152 int (*opendir)(const char *filename, struct fs_dir_stream **dirsp);
153 /*
154 * Read next entry from directory stream. On success return 0
155 * and directory entry pointer via 'dentp'. On error return
156 * -errno. See fs_readdir().
157 */
158 int (*readdir)(struct fs_dir_stream *dirs, struct fs_dirent **dentp);
159 /* see fs_closedir() */
160 void (*closedir)(struct fs_dir_stream *dirs);
AKASHI Takahiro1ba42532018-09-11 15:59:13 +0900161 int (*unlink)(const char *filename);
AKASHI Takahiroadc8c9f2018-09-11 15:59:08 +0900162 int (*mkdir)(const char *dirname);
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +0100163 int (*ln)(const char *filename, const char *target);
Simon Glass1aede482012-12-26 09:53:29 +0000164};
165
166static struct fstype_info fstypes[] = {
167#ifdef CONFIG_FS_FAT
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000168 {
169 .fstype = FS_TYPE_FAT,
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100170 .name = "fat",
Stephen Warrenec63d4a2014-02-03 13:21:01 -0700171 .null_dev_desc_ok = false,
Simon Glass19e38582012-12-26 09:53:33 +0000172 .probe = fat_set_blk_dev,
173 .close = fat_close,
Rob Clark60d74a92017-09-09 13:15:58 -0400174 .ls = fs_ls_generic,
Stephen Warren1d2f9a02014-02-03 13:21:10 -0700175 .exists = fat_exists,
Stephen Warren3eb58f52014-06-11 12:47:26 -0600176 .size = fat_size,
Simon Glass19e38582012-12-26 09:53:33 +0000177 .read = fat_read_file,
Tien Fong Chee87fda0c2019-01-23 14:20:04 +0800178#if CONFIG_IS_ENABLED(FAT_WRITE)
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800179 .write = file_fat_write,
AKASHI Takahiro73b34972018-09-11 15:59:14 +0900180 .unlink = fat_unlink,
AKASHI Takahiro1c24b7b2018-09-11 15:59:10 +0900181 .mkdir = fat_mkdir,
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800182#else
Stephen Warren9df25802014-02-03 13:20:59 -0700183 .write = fs_write_unsupported,
AKASHI Takahiro73b34972018-09-11 15:59:14 +0900184 .unlink = fs_unlink_unsupported,
AKASHI Takahiro1c24b7b2018-09-11 15:59:10 +0900185 .mkdir = fs_mkdir_unsupported,
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800186#endif
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100187 .uuid = fs_uuid_unsupported,
Rob Clark60d74a92017-09-09 13:15:58 -0400188 .opendir = fat_opendir,
189 .readdir = fat_readdir,
190 .closedir = fat_closedir,
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +0100191 .ln = fs_ln_unsupported,
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000192 },
Simon Glass1aede482012-12-26 09:53:29 +0000193#endif
Tien Fong Chee64eab042019-01-23 14:20:06 +0800194
195#if CONFIG_IS_ENABLED(FS_EXT4)
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000196 {
197 .fstype = FS_TYPE_EXT,
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100198 .name = "ext4",
Stephen Warrenec63d4a2014-02-03 13:21:01 -0700199 .null_dev_desc_ok = false,
Simon Glass19e38582012-12-26 09:53:33 +0000200 .probe = ext4fs_probe,
201 .close = ext4fs_close,
Simon Glass1aede482012-12-26 09:53:29 +0000202 .ls = ext4fs_ls,
Stephen Warren12d6d0c2014-02-03 13:21:09 -0700203 .exists = ext4fs_exists,
Stephen Warren3eb58f52014-06-11 12:47:26 -0600204 .size = ext4fs_size,
Simon Glass19e38582012-12-26 09:53:33 +0000205 .read = ext4_read_file,
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800206#ifdef CONFIG_CMD_EXT4_WRITE
207 .write = ext4_write_file,
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +0100208 .ln = ext4fs_create_link,
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800209#else
Stephen Warren9df25802014-02-03 13:20:59 -0700210 .write = fs_write_unsupported,
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +0100211 .ln = fs_ln_unsupported,
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800212#endif
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100213 .uuid = ext4fs_uuid,
Rob Clark2b7bfd92017-09-09 13:15:55 -0400214 .opendir = fs_opendir_unsupported,
AKASHI Takahiro1ba42532018-09-11 15:59:13 +0900215 .unlink = fs_unlink_unsupported,
AKASHI Takahiroadc8c9f2018-09-11 15:59:08 +0900216 .mkdir = fs_mkdir_unsupported,
Simon Glass1aede482012-12-26 09:53:29 +0000217 },
218#endif
Simon Glass11842872012-12-26 09:53:35 +0000219#ifdef CONFIG_SANDBOX
220 {
221 .fstype = FS_TYPE_SANDBOX,
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100222 .name = "sandbox",
Stephen Warrenec63d4a2014-02-03 13:21:01 -0700223 .null_dev_desc_ok = true,
Simon Glass11842872012-12-26 09:53:35 +0000224 .probe = sandbox_fs_set_blk_dev,
225 .close = sandbox_fs_close,
226 .ls = sandbox_fs_ls,
Stephen Warren97d66f22014-02-03 13:21:07 -0700227 .exists = sandbox_fs_exists,
Stephen Warren3eb58f52014-06-11 12:47:26 -0600228 .size = sandbox_fs_size,
Simon Glass11842872012-12-26 09:53:35 +0000229 .read = fs_read_sandbox,
Simon Glassea307e82013-04-20 08:42:51 +0000230 .write = fs_write_sandbox,
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100231 .uuid = fs_uuid_unsupported,
Rob Clark2b7bfd92017-09-09 13:15:55 -0400232 .opendir = fs_opendir_unsupported,
AKASHI Takahiro1ba42532018-09-11 15:59:13 +0900233 .unlink = fs_unlink_unsupported,
AKASHI Takahiroadc8c9f2018-09-11 15:59:08 +0900234 .mkdir = fs_mkdir_unsupported,
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +0100235 .ln = fs_ln_unsupported,
Simon Glass11842872012-12-26 09:53:35 +0000236 },
237#endif
Hans de Goede690c7962015-09-17 18:46:58 -0400238#ifdef CONFIG_CMD_UBIFS
239 {
240 .fstype = FS_TYPE_UBIFS,
241 .name = "ubifs",
242 .null_dev_desc_ok = true,
243 .probe = ubifs_set_blk_dev,
244 .close = ubifs_close,
245 .ls = ubifs_ls,
246 .exists = ubifs_exists,
247 .size = ubifs_size,
248 .read = ubifs_read,
249 .write = fs_write_unsupported,
250 .uuid = fs_uuid_unsupported,
Rob Clark2b7bfd92017-09-09 13:15:55 -0400251 .opendir = fs_opendir_unsupported,
AKASHI Takahiro1ba42532018-09-11 15:59:13 +0900252 .unlink = fs_unlink_unsupported,
AKASHI Takahiroadc8c9f2018-09-11 15:59:08 +0900253 .mkdir = fs_mkdir_unsupported,
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +0100254 .ln = fs_ln_unsupported,
Hans de Goede690c7962015-09-17 18:46:58 -0400255 },
256#endif
Marek BehĂșn98ec1d12017-09-03 17:00:29 +0200257#ifdef CONFIG_FS_BTRFS
258 {
259 .fstype = FS_TYPE_BTRFS,
260 .name = "btrfs",
261 .null_dev_desc_ok = false,
262 .probe = btrfs_probe,
263 .close = btrfs_close,
264 .ls = btrfs_ls,
265 .exists = btrfs_exists,
266 .size = btrfs_size,
267 .read = btrfs_read,
268 .write = fs_write_unsupported,
269 .uuid = btrfs_uuid,
Marek BehĂșn90762d92017-10-06 16:56:07 +0200270 .opendir = fs_opendir_unsupported,
AKASHI Takahiro1ba42532018-09-11 15:59:13 +0900271 .unlink = fs_unlink_unsupported,
AKASHI Takahiroadc8c9f2018-09-11 15:59:08 +0900272 .mkdir = fs_mkdir_unsupported,
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +0100273 .ln = fs_ln_unsupported,
Marek BehĂșn98ec1d12017-09-03 17:00:29 +0200274 },
275#endif
Simon Glass1aede482012-12-26 09:53:29 +0000276 {
277 .fstype = FS_TYPE_ANY,
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100278 .name = "unsupported",
Stephen Warrenec63d4a2014-02-03 13:21:01 -0700279 .null_dev_desc_ok = true,
Simon Glass1aede482012-12-26 09:53:29 +0000280 .probe = fs_probe_unsupported,
281 .close = fs_close_unsupported,
282 .ls = fs_ls_unsupported,
Stephen Warrend008fbb2014-02-03 13:21:00 -0700283 .exists = fs_exists_unsupported,
Stephen Warren3eb58f52014-06-11 12:47:26 -0600284 .size = fs_size_unsupported,
Simon Glass1aede482012-12-26 09:53:29 +0000285 .read = fs_read_unsupported,
Simon Glasseda14ea2013-04-20 08:42:50 +0000286 .write = fs_write_unsupported,
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100287 .uuid = fs_uuid_unsupported,
Rob Clark2b7bfd92017-09-09 13:15:55 -0400288 .opendir = fs_opendir_unsupported,
AKASHI Takahiro1ba42532018-09-11 15:59:13 +0900289 .unlink = fs_unlink_unsupported,
AKASHI Takahiroadc8c9f2018-09-11 15:59:08 +0900290 .mkdir = fs_mkdir_unsupported,
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +0100291 .ln = fs_ln_unsupported,
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000292 },
293};
294
Simon Glasse6aad852012-12-26 09:53:30 +0000295static struct fstype_info *fs_get_info(int fstype)
296{
297 struct fstype_info *info;
298 int i;
299
300 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes) - 1; i++, info++) {
301 if (fstype == info->fstype)
302 return info;
303 }
304
305 /* Return the 'unsupported' sentinel */
306 return info;
307}
308
Alex Kiernan3a6163a2018-05-29 15:30:50 +0000309/**
310 * fs_get_type_name() - Get type of current filesystem
311 *
312 * Return: Pointer to filesystem name
313 *
314 * Returns a string describing the current filesystem, or the sentinel
315 * "unsupported" for any unrecognised filesystem.
316 */
317const char *fs_get_type_name(void)
318{
319 return fs_get_info(fs_type)->name;
320}
321
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000322int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
323{
Simon Glass1aede482012-12-26 09:53:29 +0000324 struct fstype_info *info;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000325 int part, i;
Stephen Warren44161af2012-10-30 07:50:47 +0000326#ifdef CONFIG_NEEDS_MANUAL_RELOC
327 static int relocated;
328
329 if (!relocated) {
Simon Glass1aede482012-12-26 09:53:29 +0000330 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes);
331 i++, info++) {
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100332 info->name += gd->reloc_off;
Simon Glass1aede482012-12-26 09:53:29 +0000333 info->probe += gd->reloc_off;
334 info->close += gd->reloc_off;
335 info->ls += gd->reloc_off;
336 info->read += gd->reloc_off;
Simon Glasseda14ea2013-04-20 08:42:50 +0000337 info->write += gd->reloc_off;
Simon Glass1aede482012-12-26 09:53:29 +0000338 }
Stephen Warren44161af2012-10-30 07:50:47 +0000339 relocated = 1;
340 }
341#endif
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000342
Simon Glasse76ee972016-02-29 15:25:44 -0700343 part = blk_get_device_part_str(ifname, dev_part_str, &fs_dev_desc,
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000344 &fs_partition, 1);
345 if (part < 0)
346 return -1;
347
Simon Glass1aede482012-12-26 09:53:29 +0000348 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
349 if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY &&
350 fstype != info->fstype)
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000351 continue;
352
Stephen Warrenec63d4a2014-02-03 13:21:01 -0700353 if (!fs_dev_desc && !info->null_dev_desc_ok)
354 continue;
355
Simon Glass6a46e2f2012-12-26 09:53:31 +0000356 if (!info->probe(fs_dev_desc, &fs_partition)) {
Simon Glass1aede482012-12-26 09:53:29 +0000357 fs_type = info->fstype;
Rob Clark2b7bfd92017-09-09 13:15:55 -0400358 fs_dev_part = part;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000359 return 0;
360 }
361 }
362
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000363 return -1;
364}
365
Rob Clark2b7bfd92017-09-09 13:15:55 -0400366/* set current blk device w/ blk_desc + partition # */
367int fs_set_blk_dev_with_part(struct blk_desc *desc, int part)
368{
369 struct fstype_info *info;
370 int ret, i;
371
372 if (part >= 1)
373 ret = part_get_info(desc, part, &fs_partition);
374 else
375 ret = part_get_info_whole_disk(desc, &fs_partition);
376 if (ret)
377 return ret;
378 fs_dev_desc = desc;
379
380 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
381 if (!info->probe(fs_dev_desc, &fs_partition)) {
382 fs_type = info->fstype;
AKASHI Takahiro43efaa02018-10-17 16:32:02 +0900383 fs_dev_part = part;
Rob Clark2b7bfd92017-09-09 13:15:55 -0400384 return 0;
385 }
386 }
387
388 return -1;
389}
390
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000391static void fs_close(void)
392{
Simon Glasse6aad852012-12-26 09:53:30 +0000393 struct fstype_info *info = fs_get_info(fs_type);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000394
Simon Glasse6aad852012-12-26 09:53:30 +0000395 info->close();
Simon Glass19e38582012-12-26 09:53:33 +0000396
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000397 fs_type = FS_TYPE_ANY;
398}
399
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100400int fs_uuid(char *uuid_str)
401{
402 struct fstype_info *info = fs_get_info(fs_type);
403
404 return info->uuid(uuid_str);
405}
406
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000407int fs_ls(const char *dirname)
408{
409 int ret;
410
Simon Glasse6aad852012-12-26 09:53:30 +0000411 struct fstype_info *info = fs_get_info(fs_type);
412
413 ret = info->ls(dirname);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000414
Simon Glass19e38582012-12-26 09:53:33 +0000415 fs_type = FS_TYPE_ANY;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000416 fs_close();
417
418 return ret;
419}
420
Stephen Warrend008fbb2014-02-03 13:21:00 -0700421int fs_exists(const char *filename)
422{
423 int ret;
424
425 struct fstype_info *info = fs_get_info(fs_type);
426
427 ret = info->exists(filename);
428
429 fs_close();
430
431 return ret;
432}
433
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800434int fs_size(const char *filename, loff_t *size)
Stephen Warren3eb58f52014-06-11 12:47:26 -0600435{
436 int ret;
437
438 struct fstype_info *info = fs_get_info(fs_type);
439
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800440 ret = info->size(filename, size);
Stephen Warren3eb58f52014-06-11 12:47:26 -0600441
442 fs_close();
443
444 return ret;
445}
446
Simon Goldschmidt5b2c6872019-01-14 22:38:19 +0100447#ifdef CONFIG_LMB
448/* Check if a file may be read to the given address */
449static int fs_read_lmb_check(const char *filename, ulong addr, loff_t offset,
450 loff_t len, struct fstype_info *info)
451{
452 struct lmb lmb;
453 int ret;
454 loff_t size;
455 loff_t read_len;
456
457 /* get the actual size of the file */
458 ret = info->size(filename, &size);
459 if (ret)
460 return ret;
461 if (offset >= size) {
462 /* offset >= EOF, no bytes will be written */
463 return 0;
464 }
465 read_len = size - offset;
466
467 /* limit to 'len' if it is smaller */
468 if (len && len < read_len)
469 read_len = len;
470
Simon Goldschmidt8890e7d2019-01-26 22:13:04 +0100471 lmb_init_and_reserve(&lmb, gd->bd, (void *)gd->fdt_blob);
Simon Goldschmidt5b2c6872019-01-14 22:38:19 +0100472 lmb_dump_all(&lmb);
473
474 if (lmb_alloc_addr(&lmb, addr, read_len) == addr)
475 return 0;
476
477 printf("** Reading file would overwrite reserved memory **\n");
478 return -ENOSPC;
479}
480#endif
481
482static int _fs_read(const char *filename, ulong addr, loff_t offset, loff_t len,
483 int do_lmb_check, loff_t *actread)
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000484{
Simon Glasse6aad852012-12-26 09:53:30 +0000485 struct fstype_info *info = fs_get_info(fs_type);
Simon Glasscbe5d5d2012-12-26 09:53:32 +0000486 void *buf;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000487 int ret;
488
Simon Goldschmidt5b2c6872019-01-14 22:38:19 +0100489#ifdef CONFIG_LMB
490 if (do_lmb_check) {
491 ret = fs_read_lmb_check(filename, addr, offset, len, info);
492 if (ret)
493 return ret;
494 }
495#endif
496
Simon Glasscbe5d5d2012-12-26 09:53:32 +0000497 /*
498 * We don't actually know how many bytes are being read, since len==0
499 * means read the whole file.
500 */
501 buf = map_sysmem(addr, len);
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800502 ret = info->read(filename, buf, offset, len, actread);
Simon Glasscbe5d5d2012-12-26 09:53:32 +0000503 unmap_sysmem(buf);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000504
Simon Glasse6aad852012-12-26 09:53:30 +0000505 /* If we requested a specific number of bytes, check we got it */
Max Krummenacher56d9cdf2015-08-05 17:16:58 +0200506 if (ret == 0 && len && *actread != len)
Heinrich Schuchardtf02c5c52018-01-01 21:15:37 +0100507 debug("** %s shorter than offset + len **\n", filename);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000508 fs_close();
509
510 return ret;
511}
512
Simon Goldschmidt5b2c6872019-01-14 22:38:19 +0100513int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len,
514 loff_t *actread)
515{
516 return _fs_read(filename, addr, offset, len, 0, actread);
517}
518
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800519int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
520 loff_t *actwrite)
Simon Glasseda14ea2013-04-20 08:42:50 +0000521{
522 struct fstype_info *info = fs_get_info(fs_type);
523 void *buf;
524 int ret;
525
Simon Glasseda14ea2013-04-20 08:42:50 +0000526 buf = map_sysmem(addr, len);
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800527 ret = info->write(filename, buf, offset, len, actwrite);
Simon Glasseda14ea2013-04-20 08:42:50 +0000528 unmap_sysmem(buf);
529
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800530 if (ret < 0 && len != *actwrite) {
Simon Glasseda14ea2013-04-20 08:42:50 +0000531 printf("** Unable to write file %s **\n", filename);
532 ret = -1;
533 }
534 fs_close();
535
536 return ret;
537}
538
Rob Clark2b7bfd92017-09-09 13:15:55 -0400539struct fs_dir_stream *fs_opendir(const char *filename)
540{
541 struct fstype_info *info = fs_get_info(fs_type);
542 struct fs_dir_stream *dirs = NULL;
543 int ret;
544
545 ret = info->opendir(filename, &dirs);
546 fs_close();
547 if (ret) {
548 errno = -ret;
549 return NULL;
550 }
551
552 dirs->desc = fs_dev_desc;
553 dirs->part = fs_dev_part;
554
555 return dirs;
556}
557
558struct fs_dirent *fs_readdir(struct fs_dir_stream *dirs)
559{
560 struct fstype_info *info;
561 struct fs_dirent *dirent;
562 int ret;
563
564 fs_set_blk_dev_with_part(dirs->desc, dirs->part);
565 info = fs_get_info(fs_type);
566
567 ret = info->readdir(dirs, &dirent);
568 fs_close();
569 if (ret) {
570 errno = -ret;
571 return NULL;
572 }
573
574 return dirent;
575}
576
577void fs_closedir(struct fs_dir_stream *dirs)
578{
579 struct fstype_info *info;
580
581 if (!dirs)
582 return;
583
584 fs_set_blk_dev_with_part(dirs->desc, dirs->part);
585 info = fs_get_info(fs_type);
586
587 info->closedir(dirs);
588 fs_close();
589}
590
AKASHI Takahiro1ba42532018-09-11 15:59:13 +0900591int fs_unlink(const char *filename)
592{
593 int ret;
594
595 struct fstype_info *info = fs_get_info(fs_type);
596
597 ret = info->unlink(filename);
598
599 fs_type = FS_TYPE_ANY;
600 fs_close();
601
602 return ret;
603}
AKASHI Takahiroadc8c9f2018-09-11 15:59:08 +0900604
605int fs_mkdir(const char *dirname)
606{
607 int ret;
608
609 struct fstype_info *info = fs_get_info(fs_type);
610
611 ret = info->mkdir(dirname);
612
613 fs_type = FS_TYPE_ANY;
614 fs_close();
615
616 return ret;
617}
Rob Clark2b7bfd92017-09-09 13:15:55 -0400618
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +0100619int fs_ln(const char *fname, const char *target)
620{
621 struct fstype_info *info = fs_get_info(fs_type);
622 int ret;
623
624 ret = info->ln(fname, target);
625
626 if (ret < 0) {
627 printf("** Unable to create link %s -> %s **\n", fname, target);
628 ret = -1;
629 }
630 fs_close();
631
632 return ret;
633}
634
Stephen Warren3eb58f52014-06-11 12:47:26 -0600635int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
636 int fstype)
637{
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800638 loff_t size;
Stephen Warren3eb58f52014-06-11 12:47:26 -0600639
640 if (argc != 4)
641 return CMD_RET_USAGE;
642
643 if (fs_set_blk_dev(argv[1], argv[2], fstype))
644 return 1;
645
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800646 if (fs_size(argv[3], &size) < 0)
Stephen Warren3eb58f52014-06-11 12:47:26 -0600647 return CMD_RET_FAILURE;
648
Simon Glass4d949a22017-08-03 12:22:10 -0600649 env_set_hex("filesize", size);
Stephen Warren3eb58f52014-06-11 12:47:26 -0600650
651 return 0;
652}
653
Stephen Warren128d3d92012-10-31 11:05:07 +0000654int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
Wolfgang Denka10c7a52013-10-05 21:07:25 +0200655 int fstype)
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000656{
657 unsigned long addr;
658 const char *addr_str;
659 const char *filename;
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800660 loff_t bytes;
661 loff_t pos;
662 loff_t len_read;
663 int ret;
Andreas Bießmann1fd2d8a2012-11-14 13:32:37 +0100664 unsigned long time;
Pavel Machek4c1a9c52014-07-09 22:42:57 +0200665 char *ep;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000666
Stephen Warrenb2d5cd62012-10-30 12:04:17 +0000667 if (argc < 2)
668 return CMD_RET_USAGE;
669 if (argc > 7)
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000670 return CMD_RET_USAGE;
671
Stephen Warrenb2d5cd62012-10-30 12:04:17 +0000672 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000673 return 1;
674
675 if (argc >= 4) {
Pavel Machek4c1a9c52014-07-09 22:42:57 +0200676 addr = simple_strtoul(argv[3], &ep, 16);
677 if (ep == argv[3] || *ep != '\0')
678 return CMD_RET_USAGE;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000679 } else {
Simon Glass64b723f2017-08-03 12:22:12 -0600680 addr_str = env_get("loadaddr");
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000681 if (addr_str != NULL)
682 addr = simple_strtoul(addr_str, NULL, 16);
683 else
684 addr = CONFIG_SYS_LOAD_ADDR;
685 }
686 if (argc >= 5) {
687 filename = argv[4];
688 } else {
Simon Glass64b723f2017-08-03 12:22:12 -0600689 filename = env_get("bootfile");
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000690 if (!filename) {
691 puts("** No boot file defined **\n");
692 return 1;
693 }
694 }
695 if (argc >= 6)
Wolfgang Denka10c7a52013-10-05 21:07:25 +0200696 bytes = simple_strtoul(argv[5], NULL, 16);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000697 else
698 bytes = 0;
699 if (argc >= 7)
Wolfgang Denka10c7a52013-10-05 21:07:25 +0200700 pos = simple_strtoul(argv[6], NULL, 16);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000701 else
702 pos = 0;
703
Mian Yousaf Kaukab961ebe82019-06-18 15:03:44 +0200704#ifdef CONFIG_CMD_BOOTEFI
705 efi_set_bootdev(argv[1], (argc > 2) ? argv[2] : "",
706 (argc > 4) ? argv[4] : "");
707#endif
Andreas Bießmann1fd2d8a2012-11-14 13:32:37 +0100708 time = get_timer(0);
Simon Goldschmidt5b2c6872019-01-14 22:38:19 +0100709 ret = _fs_read(filename, addr, pos, bytes, 1, &len_read);
Andreas Bießmann1fd2d8a2012-11-14 13:32:37 +0100710 time = get_timer(time);
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800711 if (ret < 0)
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000712 return 1;
713
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800714 printf("%llu bytes read in %lu ms", len_read, time);
Andreas Bießmann1fd2d8a2012-11-14 13:32:37 +0100715 if (time > 0) {
716 puts(" (");
Tom Rinia17b7bc2014-11-24 11:50:46 -0500717 print_size(div_u64(len_read, time) * 1000, "/s");
Andreas Bießmann1fd2d8a2012-11-14 13:32:37 +0100718 puts(")");
719 }
720 puts("\n");
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000721
Simon Glass4d949a22017-08-03 12:22:10 -0600722 env_set_hex("fileaddr", addr);
723 env_set_hex("filesize", len_read);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000724
725 return 0;
726}
727
728int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
729 int fstype)
730{
731 if (argc < 2)
732 return CMD_RET_USAGE;
Stephen Warrenb2d5cd62012-10-30 12:04:17 +0000733 if (argc > 4)
734 return CMD_RET_USAGE;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000735
736 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
737 return 1;
738
Stephen Warrenb2d5cd62012-10-30 12:04:17 +0000739 if (fs_ls(argc >= 4 ? argv[3] : "/"))
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000740 return 1;
741
742 return 0;
743}
Simon Glasseda14ea2013-04-20 08:42:50 +0000744
Stephen Warrend008fbb2014-02-03 13:21:00 -0700745int file_exists(const char *dev_type, const char *dev_part, const char *file,
746 int fstype)
747{
748 if (fs_set_blk_dev(dev_type, dev_part, fstype))
749 return 0;
750
751 return fs_exists(file);
752}
753
Simon Glasseda14ea2013-04-20 08:42:50 +0000754int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
Wolfgang Denka10c7a52013-10-05 21:07:25 +0200755 int fstype)
Simon Glasseda14ea2013-04-20 08:42:50 +0000756{
757 unsigned long addr;
758 const char *filename;
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800759 loff_t bytes;
760 loff_t pos;
761 loff_t len;
762 int ret;
Simon Glasseda14ea2013-04-20 08:42:50 +0000763 unsigned long time;
764
765 if (argc < 6 || argc > 7)
766 return CMD_RET_USAGE;
767
768 if (fs_set_blk_dev(argv[1], argv[2], fstype))
769 return 1;
770
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800771 addr = simple_strtoul(argv[3], NULL, 16);
772 filename = argv[4];
Wolfgang Denka10c7a52013-10-05 21:07:25 +0200773 bytes = simple_strtoul(argv[5], NULL, 16);
Simon Glasseda14ea2013-04-20 08:42:50 +0000774 if (argc >= 7)
Wolfgang Denka10c7a52013-10-05 21:07:25 +0200775 pos = simple_strtoul(argv[6], NULL, 16);
Simon Glasseda14ea2013-04-20 08:42:50 +0000776 else
777 pos = 0;
778
779 time = get_timer(0);
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800780 ret = fs_write(filename, addr, pos, bytes, &len);
Simon Glasseda14ea2013-04-20 08:42:50 +0000781 time = get_timer(time);
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800782 if (ret < 0)
Simon Glasseda14ea2013-04-20 08:42:50 +0000783 return 1;
784
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800785 printf("%llu bytes written in %lu ms", len, time);
Simon Glasseda14ea2013-04-20 08:42:50 +0000786 if (time > 0) {
787 puts(" (");
Tom Rinia17b7bc2014-11-24 11:50:46 -0500788 print_size(div_u64(len, time) * 1000, "/s");
Simon Glasseda14ea2013-04-20 08:42:50 +0000789 puts(")");
790 }
791 puts("\n");
792
793 return 0;
794}
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100795
796int do_fs_uuid(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
797 int fstype)
798{
799 int ret;
800 char uuid[37];
801 memset(uuid, 0, sizeof(uuid));
802
803 if (argc < 3 || argc > 4)
804 return CMD_RET_USAGE;
805
806 if (fs_set_blk_dev(argv[1], argv[2], fstype))
807 return 1;
808
809 ret = fs_uuid(uuid);
810 if (ret)
811 return CMD_RET_FAILURE;
812
813 if (argc == 4)
Simon Glass6a38e412017-08-03 12:22:09 -0600814 env_set(argv[3], uuid);
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100815 else
816 printf("%s\n", uuid);
817
818 return CMD_RET_SUCCESS;
819}
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100820
821int do_fs_type(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
822{
823 struct fstype_info *info;
824
825 if (argc < 3 || argc > 4)
826 return CMD_RET_USAGE;
827
828 if (fs_set_blk_dev(argv[1], argv[2], FS_TYPE_ANY))
829 return 1;
830
831 info = fs_get_info(fs_type);
832
833 if (argc == 4)
Simon Glass6a38e412017-08-03 12:22:09 -0600834 env_set(argv[3], info->name);
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100835 else
836 printf("%s\n", info->name);
837
Marek Vasut08d1c422019-02-06 13:19:29 +0100838 fs_close();
839
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100840 return CMD_RET_SUCCESS;
841}
842
AKASHI Takahiro1ba42532018-09-11 15:59:13 +0900843int do_rm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
844 int fstype)
845{
846 if (argc != 4)
847 return CMD_RET_USAGE;
848
849 if (fs_set_blk_dev(argv[1], argv[2], fstype))
850 return 1;
851
852 if (fs_unlink(argv[3]))
853 return 1;
854
855 return 0;
856}
857
AKASHI Takahiroadc8c9f2018-09-11 15:59:08 +0900858int do_mkdir(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
859 int fstype)
860{
861 int ret;
862
863 if (argc != 4)
864 return CMD_RET_USAGE;
865
866 if (fs_set_blk_dev(argv[1], argv[2], fstype))
867 return 1;
868
869 ret = fs_mkdir(argv[3]);
870 if (ret) {
871 printf("** Unable to create a directory \"%s\" **\n", argv[3]);
872 return 1;
873 }
874
875 return 0;
876}
Jean-Jacques Hiblotbc237482019-02-13 12:15:26 +0100877
878int do_ln(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
879 int fstype)
880{
881 if (argc != 5)
882 return CMD_RET_USAGE;
883
884 if (fs_set_blk_dev(argv[1], argv[2], fstype))
885 return 1;
886
887 if (fs_ln(argv[3], argv[4]))
888 return 1;
889
890 return 0;
891}