blob: 6155cb1daf34352c95f3d5270e5cf7b8d7b0e32f [file] [log] [blame]
Stephen Warreneefbc3f2012-10-22 06:43:51 +00001/*
2 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
3 *
Tom Rinie2378802016-01-14 22:05:13 -05004 * SPDX-License-Identifier: GPL-2.0
Stephen Warreneefbc3f2012-10-22 06:43:51 +00005 */
6
7#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>
Joe Hershberger65b905b2015-03-22 17:08:59 -050010#include <mapmem.h>
Stephen Warreneefbc3f2012-10-22 06:43:51 +000011#include <part.h>
12#include <ext4fs.h>
13#include <fat.h>
14#include <fs.h>
Simon Glass11842872012-12-26 09:53:35 +000015#include <sandboxfs.h>
Hans de Goede690c7962015-09-17 18:46:58 -040016#include <ubifs_uboot.h>
Marek Behún98ec1d12017-09-03 17:00:29 +020017#include <btrfs.h>
Simon Glasscbe5d5d2012-12-26 09:53:32 +000018#include <asm/io.h>
Tom Rinia17b7bc2014-11-24 11:50:46 -050019#include <div64.h>
20#include <linux/math64.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
Simon Glass1aede482012-12-26 09:53:29 +000094static inline void fs_close_unsupported(void)
95{
96}
97
Christian Gmeiner9f9eec32014-11-12 14:35:04 +010098static inline int fs_uuid_unsupported(char *uuid_str)
99{
100 return -1;
101}
102
Rob Clark2b7bfd92017-09-09 13:15:55 -0400103static inline int fs_opendir_unsupported(const char *filename,
104 struct fs_dir_stream **dirs)
105{
106 return -EACCES;
107}
108
Simon Glass1aede482012-12-26 09:53:29 +0000109struct fstype_info {
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000110 int fstype;
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100111 char *name;
Stephen Warrenec63d4a2014-02-03 13:21:01 -0700112 /*
113 * Is it legal to pass NULL as .probe()'s fs_dev_desc parameter? This
114 * should be false in most cases. For "virtual" filesystems which
115 * aren't based on a U-Boot block device (e.g. sandbox), this can be
116 * set to true. This should also be true for the dumm entry at the end
117 * of fstypes[], since that is essentially a "virtual" (non-existent)
118 * filesystem.
119 */
120 bool null_dev_desc_ok;
Simon Glasse3394752016-02-29 15:25:34 -0700121 int (*probe)(struct blk_desc *fs_dev_desc,
Simon Glass6a46e2f2012-12-26 09:53:31 +0000122 disk_partition_t *fs_partition);
Simon Glass1aede482012-12-26 09:53:29 +0000123 int (*ls)(const char *dirname);
Stephen Warrend008fbb2014-02-03 13:21:00 -0700124 int (*exists)(const char *filename);
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800125 int (*size)(const char *filename, loff_t *size);
126 int (*read)(const char *filename, void *buf, loff_t offset,
127 loff_t len, loff_t *actread);
128 int (*write)(const char *filename, void *buf, loff_t offset,
129 loff_t len, loff_t *actwrite);
Simon Glass1aede482012-12-26 09:53:29 +0000130 void (*close)(void);
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100131 int (*uuid)(char *uuid_str);
Rob Clark2b7bfd92017-09-09 13:15:55 -0400132 /*
133 * Open a directory stream. On success return 0 and directory
134 * stream pointer via 'dirsp'. On error, return -errno. See
135 * fs_opendir().
136 */
137 int (*opendir)(const char *filename, struct fs_dir_stream **dirsp);
138 /*
139 * Read next entry from directory stream. On success return 0
140 * and directory entry pointer via 'dentp'. On error return
141 * -errno. See fs_readdir().
142 */
143 int (*readdir)(struct fs_dir_stream *dirs, struct fs_dirent **dentp);
144 /* see fs_closedir() */
145 void (*closedir)(struct fs_dir_stream *dirs);
Simon Glass1aede482012-12-26 09:53:29 +0000146};
147
148static struct fstype_info fstypes[] = {
149#ifdef CONFIG_FS_FAT
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000150 {
151 .fstype = FS_TYPE_FAT,
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100152 .name = "fat",
Stephen Warrenec63d4a2014-02-03 13:21:01 -0700153 .null_dev_desc_ok = false,
Simon Glass19e38582012-12-26 09:53:33 +0000154 .probe = fat_set_blk_dev,
155 .close = fat_close,
Rob Clark60d74a92017-09-09 13:15:58 -0400156 .ls = fs_ls_generic,
Stephen Warren1d2f9a02014-02-03 13:21:10 -0700157 .exists = fat_exists,
Stephen Warren3eb58f52014-06-11 12:47:26 -0600158 .size = fat_size,
Simon Glass19e38582012-12-26 09:53:33 +0000159 .read = fat_read_file,
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800160#ifdef CONFIG_FAT_WRITE
161 .write = file_fat_write,
162#else
Stephen Warren9df25802014-02-03 13:20:59 -0700163 .write = fs_write_unsupported,
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800164#endif
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100165 .uuid = fs_uuid_unsupported,
Rob Clark60d74a92017-09-09 13:15:58 -0400166 .opendir = fat_opendir,
167 .readdir = fat_readdir,
168 .closedir = fat_closedir,
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000169 },
Simon Glass1aede482012-12-26 09:53:29 +0000170#endif
171#ifdef CONFIG_FS_EXT4
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000172 {
173 .fstype = FS_TYPE_EXT,
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100174 .name = "ext4",
Stephen Warrenec63d4a2014-02-03 13:21:01 -0700175 .null_dev_desc_ok = false,
Simon Glass19e38582012-12-26 09:53:33 +0000176 .probe = ext4fs_probe,
177 .close = ext4fs_close,
Simon Glass1aede482012-12-26 09:53:29 +0000178 .ls = ext4fs_ls,
Stephen Warren12d6d0c2014-02-03 13:21:09 -0700179 .exists = ext4fs_exists,
Stephen Warren3eb58f52014-06-11 12:47:26 -0600180 .size = ext4fs_size,
Simon Glass19e38582012-12-26 09:53:33 +0000181 .read = ext4_read_file,
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800182#ifdef CONFIG_CMD_EXT4_WRITE
183 .write = ext4_write_file,
184#else
Stephen Warren9df25802014-02-03 13:20:59 -0700185 .write = fs_write_unsupported,
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800186#endif
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100187 .uuid = ext4fs_uuid,
Rob Clark2b7bfd92017-09-09 13:15:55 -0400188 .opendir = fs_opendir_unsupported,
Simon Glass1aede482012-12-26 09:53:29 +0000189 },
190#endif
Simon Glass11842872012-12-26 09:53:35 +0000191#ifdef CONFIG_SANDBOX
192 {
193 .fstype = FS_TYPE_SANDBOX,
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100194 .name = "sandbox",
Stephen Warrenec63d4a2014-02-03 13:21:01 -0700195 .null_dev_desc_ok = true,
Simon Glass11842872012-12-26 09:53:35 +0000196 .probe = sandbox_fs_set_blk_dev,
197 .close = sandbox_fs_close,
198 .ls = sandbox_fs_ls,
Stephen Warren97d66f22014-02-03 13:21:07 -0700199 .exists = sandbox_fs_exists,
Stephen Warren3eb58f52014-06-11 12:47:26 -0600200 .size = sandbox_fs_size,
Simon Glass11842872012-12-26 09:53:35 +0000201 .read = fs_read_sandbox,
Simon Glassea307e82013-04-20 08:42:51 +0000202 .write = fs_write_sandbox,
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100203 .uuid = fs_uuid_unsupported,
Rob Clark2b7bfd92017-09-09 13:15:55 -0400204 .opendir = fs_opendir_unsupported,
Simon Glass11842872012-12-26 09:53:35 +0000205 },
206#endif
Hans de Goede690c7962015-09-17 18:46:58 -0400207#ifdef CONFIG_CMD_UBIFS
208 {
209 .fstype = FS_TYPE_UBIFS,
210 .name = "ubifs",
211 .null_dev_desc_ok = true,
212 .probe = ubifs_set_blk_dev,
213 .close = ubifs_close,
214 .ls = ubifs_ls,
215 .exists = ubifs_exists,
216 .size = ubifs_size,
217 .read = ubifs_read,
218 .write = fs_write_unsupported,
219 .uuid = fs_uuid_unsupported,
Rob Clark2b7bfd92017-09-09 13:15:55 -0400220 .opendir = fs_opendir_unsupported,
Hans de Goede690c7962015-09-17 18:46:58 -0400221 },
222#endif
Marek Behún98ec1d12017-09-03 17:00:29 +0200223#ifdef CONFIG_FS_BTRFS
224 {
225 .fstype = FS_TYPE_BTRFS,
226 .name = "btrfs",
227 .null_dev_desc_ok = false,
228 .probe = btrfs_probe,
229 .close = btrfs_close,
230 .ls = btrfs_ls,
231 .exists = btrfs_exists,
232 .size = btrfs_size,
233 .read = btrfs_read,
234 .write = fs_write_unsupported,
235 .uuid = btrfs_uuid,
Marek Behún90762d92017-10-06 16:56:07 +0200236 .opendir = fs_opendir_unsupported,
Marek Behún98ec1d12017-09-03 17:00:29 +0200237 },
238#endif
Simon Glass1aede482012-12-26 09:53:29 +0000239 {
240 .fstype = FS_TYPE_ANY,
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100241 .name = "unsupported",
Stephen Warrenec63d4a2014-02-03 13:21:01 -0700242 .null_dev_desc_ok = true,
Simon Glass1aede482012-12-26 09:53:29 +0000243 .probe = fs_probe_unsupported,
244 .close = fs_close_unsupported,
245 .ls = fs_ls_unsupported,
Stephen Warrend008fbb2014-02-03 13:21:00 -0700246 .exists = fs_exists_unsupported,
Stephen Warren3eb58f52014-06-11 12:47:26 -0600247 .size = fs_size_unsupported,
Simon Glass1aede482012-12-26 09:53:29 +0000248 .read = fs_read_unsupported,
Simon Glasseda14ea2013-04-20 08:42:50 +0000249 .write = fs_write_unsupported,
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100250 .uuid = fs_uuid_unsupported,
Rob Clark2b7bfd92017-09-09 13:15:55 -0400251 .opendir = fs_opendir_unsupported,
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000252 },
253};
254
Simon Glasse6aad852012-12-26 09:53:30 +0000255static struct fstype_info *fs_get_info(int fstype)
256{
257 struct fstype_info *info;
258 int i;
259
260 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes) - 1; i++, info++) {
261 if (fstype == info->fstype)
262 return info;
263 }
264
265 /* Return the 'unsupported' sentinel */
266 return info;
267}
268
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000269int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
270{
Simon Glass1aede482012-12-26 09:53:29 +0000271 struct fstype_info *info;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000272 int part, i;
Stephen Warren44161af2012-10-30 07:50:47 +0000273#ifdef CONFIG_NEEDS_MANUAL_RELOC
274 static int relocated;
275
276 if (!relocated) {
Simon Glass1aede482012-12-26 09:53:29 +0000277 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes);
278 i++, info++) {
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100279 info->name += gd->reloc_off;
Simon Glass1aede482012-12-26 09:53:29 +0000280 info->probe += gd->reloc_off;
281 info->close += gd->reloc_off;
282 info->ls += gd->reloc_off;
283 info->read += gd->reloc_off;
Simon Glasseda14ea2013-04-20 08:42:50 +0000284 info->write += gd->reloc_off;
Simon Glass1aede482012-12-26 09:53:29 +0000285 }
Stephen Warren44161af2012-10-30 07:50:47 +0000286 relocated = 1;
287 }
288#endif
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000289
Simon Glasse76ee972016-02-29 15:25:44 -0700290 part = blk_get_device_part_str(ifname, dev_part_str, &fs_dev_desc,
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000291 &fs_partition, 1);
292 if (part < 0)
293 return -1;
294
Simon Glass1aede482012-12-26 09:53:29 +0000295 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
296 if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY &&
297 fstype != info->fstype)
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000298 continue;
299
Stephen Warrenec63d4a2014-02-03 13:21:01 -0700300 if (!fs_dev_desc && !info->null_dev_desc_ok)
301 continue;
302
Simon Glass6a46e2f2012-12-26 09:53:31 +0000303 if (!info->probe(fs_dev_desc, &fs_partition)) {
Simon Glass1aede482012-12-26 09:53:29 +0000304 fs_type = info->fstype;
Rob Clark2b7bfd92017-09-09 13:15:55 -0400305 fs_dev_part = part;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000306 return 0;
307 }
308 }
309
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000310 return -1;
311}
312
Rob Clark2b7bfd92017-09-09 13:15:55 -0400313/* set current blk device w/ blk_desc + partition # */
314int fs_set_blk_dev_with_part(struct blk_desc *desc, int part)
315{
316 struct fstype_info *info;
317 int ret, i;
318
319 if (part >= 1)
320 ret = part_get_info(desc, part, &fs_partition);
321 else
322 ret = part_get_info_whole_disk(desc, &fs_partition);
323 if (ret)
324 return ret;
325 fs_dev_desc = desc;
326
327 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
328 if (!info->probe(fs_dev_desc, &fs_partition)) {
329 fs_type = info->fstype;
330 return 0;
331 }
332 }
333
334 return -1;
335}
336
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000337static void fs_close(void)
338{
Simon Glasse6aad852012-12-26 09:53:30 +0000339 struct fstype_info *info = fs_get_info(fs_type);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000340
Simon Glasse6aad852012-12-26 09:53:30 +0000341 info->close();
Simon Glass19e38582012-12-26 09:53:33 +0000342
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000343 fs_type = FS_TYPE_ANY;
344}
345
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100346int fs_uuid(char *uuid_str)
347{
348 struct fstype_info *info = fs_get_info(fs_type);
349
350 return info->uuid(uuid_str);
351}
352
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000353int fs_ls(const char *dirname)
354{
355 int ret;
356
Simon Glasse6aad852012-12-26 09:53:30 +0000357 struct fstype_info *info = fs_get_info(fs_type);
358
359 ret = info->ls(dirname);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000360
Simon Glass19e38582012-12-26 09:53:33 +0000361 fs_type = FS_TYPE_ANY;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000362 fs_close();
363
364 return ret;
365}
366
Stephen Warrend008fbb2014-02-03 13:21:00 -0700367int fs_exists(const char *filename)
368{
369 int ret;
370
371 struct fstype_info *info = fs_get_info(fs_type);
372
373 ret = info->exists(filename);
374
375 fs_close();
376
377 return ret;
378}
379
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800380int fs_size(const char *filename, loff_t *size)
Stephen Warren3eb58f52014-06-11 12:47:26 -0600381{
382 int ret;
383
384 struct fstype_info *info = fs_get_info(fs_type);
385
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800386 ret = info->size(filename, size);
Stephen Warren3eb58f52014-06-11 12:47:26 -0600387
388 fs_close();
389
390 return ret;
391}
392
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800393int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len,
394 loff_t *actread)
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000395{
Simon Glasse6aad852012-12-26 09:53:30 +0000396 struct fstype_info *info = fs_get_info(fs_type);
Simon Glasscbe5d5d2012-12-26 09:53:32 +0000397 void *buf;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000398 int ret;
399
Simon Glasscbe5d5d2012-12-26 09:53:32 +0000400 /*
401 * We don't actually know how many bytes are being read, since len==0
402 * means read the whole file.
403 */
404 buf = map_sysmem(addr, len);
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800405 ret = info->read(filename, buf, offset, len, actread);
Simon Glasscbe5d5d2012-12-26 09:53:32 +0000406 unmap_sysmem(buf);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000407
Simon Glasse6aad852012-12-26 09:53:30 +0000408 /* If we requested a specific number of bytes, check we got it */
Max Krummenacher56d9cdf2015-08-05 17:16:58 +0200409 if (ret == 0 && len && *actread != len)
Heinrich Schuchardtf02c5c52018-01-01 21:15:37 +0100410 debug("** %s shorter than offset + len **\n", filename);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000411 fs_close();
412
413 return ret;
414}
415
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800416int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
417 loff_t *actwrite)
Simon Glasseda14ea2013-04-20 08:42:50 +0000418{
419 struct fstype_info *info = fs_get_info(fs_type);
420 void *buf;
421 int ret;
422
Simon Glasseda14ea2013-04-20 08:42:50 +0000423 buf = map_sysmem(addr, len);
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800424 ret = info->write(filename, buf, offset, len, actwrite);
Simon Glasseda14ea2013-04-20 08:42:50 +0000425 unmap_sysmem(buf);
426
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800427 if (ret < 0 && len != *actwrite) {
Simon Glasseda14ea2013-04-20 08:42:50 +0000428 printf("** Unable to write file %s **\n", filename);
429 ret = -1;
430 }
431 fs_close();
432
433 return ret;
434}
435
Rob Clark2b7bfd92017-09-09 13:15:55 -0400436struct fs_dir_stream *fs_opendir(const char *filename)
437{
438 struct fstype_info *info = fs_get_info(fs_type);
439 struct fs_dir_stream *dirs = NULL;
440 int ret;
441
442 ret = info->opendir(filename, &dirs);
443 fs_close();
444 if (ret) {
445 errno = -ret;
446 return NULL;
447 }
448
449 dirs->desc = fs_dev_desc;
450 dirs->part = fs_dev_part;
451
452 return dirs;
453}
454
455struct fs_dirent *fs_readdir(struct fs_dir_stream *dirs)
456{
457 struct fstype_info *info;
458 struct fs_dirent *dirent;
459 int ret;
460
461 fs_set_blk_dev_with_part(dirs->desc, dirs->part);
462 info = fs_get_info(fs_type);
463
464 ret = info->readdir(dirs, &dirent);
465 fs_close();
466 if (ret) {
467 errno = -ret;
468 return NULL;
469 }
470
471 return dirent;
472}
473
474void fs_closedir(struct fs_dir_stream *dirs)
475{
476 struct fstype_info *info;
477
478 if (!dirs)
479 return;
480
481 fs_set_blk_dev_with_part(dirs->desc, dirs->part);
482 info = fs_get_info(fs_type);
483
484 info->closedir(dirs);
485 fs_close();
486}
487
488
Stephen Warren3eb58f52014-06-11 12:47:26 -0600489int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
490 int fstype)
491{
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800492 loff_t size;
Stephen Warren3eb58f52014-06-11 12:47:26 -0600493
494 if (argc != 4)
495 return CMD_RET_USAGE;
496
497 if (fs_set_blk_dev(argv[1], argv[2], fstype))
498 return 1;
499
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800500 if (fs_size(argv[3], &size) < 0)
Stephen Warren3eb58f52014-06-11 12:47:26 -0600501 return CMD_RET_FAILURE;
502
Simon Glass4d949a22017-08-03 12:22:10 -0600503 env_set_hex("filesize", size);
Stephen Warren3eb58f52014-06-11 12:47:26 -0600504
505 return 0;
506}
507
Stephen Warren128d3d92012-10-31 11:05:07 +0000508int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
Wolfgang Denka10c7a52013-10-05 21:07:25 +0200509 int fstype)
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000510{
511 unsigned long addr;
512 const char *addr_str;
513 const char *filename;
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800514 loff_t bytes;
515 loff_t pos;
516 loff_t len_read;
517 int ret;
Andreas Bießmann1fd2d8a2012-11-14 13:32:37 +0100518 unsigned long time;
Pavel Machek4c1a9c52014-07-09 22:42:57 +0200519 char *ep;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000520
Stephen Warrenb2d5cd62012-10-30 12:04:17 +0000521 if (argc < 2)
522 return CMD_RET_USAGE;
523 if (argc > 7)
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000524 return CMD_RET_USAGE;
525
Stephen Warrenb2d5cd62012-10-30 12:04:17 +0000526 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000527 return 1;
528
529 if (argc >= 4) {
Pavel Machek4c1a9c52014-07-09 22:42:57 +0200530 addr = simple_strtoul(argv[3], &ep, 16);
531 if (ep == argv[3] || *ep != '\0')
532 return CMD_RET_USAGE;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000533 } else {
Simon Glass64b723f2017-08-03 12:22:12 -0600534 addr_str = env_get("loadaddr");
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000535 if (addr_str != NULL)
536 addr = simple_strtoul(addr_str, NULL, 16);
537 else
538 addr = CONFIG_SYS_LOAD_ADDR;
539 }
540 if (argc >= 5) {
541 filename = argv[4];
542 } else {
Simon Glass64b723f2017-08-03 12:22:12 -0600543 filename = env_get("bootfile");
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000544 if (!filename) {
545 puts("** No boot file defined **\n");
546 return 1;
547 }
548 }
549 if (argc >= 6)
Wolfgang Denka10c7a52013-10-05 21:07:25 +0200550 bytes = simple_strtoul(argv[5], NULL, 16);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000551 else
552 bytes = 0;
553 if (argc >= 7)
Wolfgang Denka10c7a52013-10-05 21:07:25 +0200554 pos = simple_strtoul(argv[6], NULL, 16);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000555 else
556 pos = 0;
557
Andreas Bießmann1fd2d8a2012-11-14 13:32:37 +0100558 time = get_timer(0);
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800559 ret = fs_read(filename, addr, pos, bytes, &len_read);
Andreas Bießmann1fd2d8a2012-11-14 13:32:37 +0100560 time = get_timer(time);
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800561 if (ret < 0)
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000562 return 1;
563
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800564 printf("%llu bytes read in %lu ms", len_read, time);
Andreas Bießmann1fd2d8a2012-11-14 13:32:37 +0100565 if (time > 0) {
566 puts(" (");
Tom Rinia17b7bc2014-11-24 11:50:46 -0500567 print_size(div_u64(len_read, time) * 1000, "/s");
Andreas Bießmann1fd2d8a2012-11-14 13:32:37 +0100568 puts(")");
569 }
570 puts("\n");
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000571
Simon Glass4d949a22017-08-03 12:22:10 -0600572 env_set_hex("fileaddr", addr);
573 env_set_hex("filesize", len_read);
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000574
575 return 0;
576}
577
578int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
579 int fstype)
580{
581 if (argc < 2)
582 return CMD_RET_USAGE;
Stephen Warrenb2d5cd62012-10-30 12:04:17 +0000583 if (argc > 4)
584 return CMD_RET_USAGE;
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000585
586 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
587 return 1;
588
Stephen Warrenb2d5cd62012-10-30 12:04:17 +0000589 if (fs_ls(argc >= 4 ? argv[3] : "/"))
Stephen Warreneefbc3f2012-10-22 06:43:51 +0000590 return 1;
591
592 return 0;
593}
Simon Glasseda14ea2013-04-20 08:42:50 +0000594
Stephen Warrend008fbb2014-02-03 13:21:00 -0700595int file_exists(const char *dev_type, const char *dev_part, const char *file,
596 int fstype)
597{
598 if (fs_set_blk_dev(dev_type, dev_part, fstype))
599 return 0;
600
601 return fs_exists(file);
602}
603
Simon Glasseda14ea2013-04-20 08:42:50 +0000604int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
Wolfgang Denka10c7a52013-10-05 21:07:25 +0200605 int fstype)
Simon Glasseda14ea2013-04-20 08:42:50 +0000606{
607 unsigned long addr;
608 const char *filename;
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800609 loff_t bytes;
610 loff_t pos;
611 loff_t len;
612 int ret;
Simon Glasseda14ea2013-04-20 08:42:50 +0000613 unsigned long time;
614
615 if (argc < 6 || argc > 7)
616 return CMD_RET_USAGE;
617
618 if (fs_set_blk_dev(argv[1], argv[2], fstype))
619 return 1;
620
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800621 addr = simple_strtoul(argv[3], NULL, 16);
622 filename = argv[4];
Wolfgang Denka10c7a52013-10-05 21:07:25 +0200623 bytes = simple_strtoul(argv[5], NULL, 16);
Simon Glasseda14ea2013-04-20 08:42:50 +0000624 if (argc >= 7)
Wolfgang Denka10c7a52013-10-05 21:07:25 +0200625 pos = simple_strtoul(argv[6], NULL, 16);
Simon Glasseda14ea2013-04-20 08:42:50 +0000626 else
627 pos = 0;
628
629 time = get_timer(0);
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800630 ret = fs_write(filename, addr, pos, bytes, &len);
Simon Glasseda14ea2013-04-20 08:42:50 +0000631 time = get_timer(time);
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800632 if (ret < 0)
Simon Glasseda14ea2013-04-20 08:42:50 +0000633 return 1;
634
Suriyan Ramasami96171fb2014-11-17 14:39:38 -0800635 printf("%llu bytes written in %lu ms", len, time);
Simon Glasseda14ea2013-04-20 08:42:50 +0000636 if (time > 0) {
637 puts(" (");
Tom Rinia17b7bc2014-11-24 11:50:46 -0500638 print_size(div_u64(len, time) * 1000, "/s");
Simon Glasseda14ea2013-04-20 08:42:50 +0000639 puts(")");
640 }
641 puts("\n");
642
643 return 0;
644}
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100645
646int do_fs_uuid(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
647 int fstype)
648{
649 int ret;
650 char uuid[37];
651 memset(uuid, 0, sizeof(uuid));
652
653 if (argc < 3 || argc > 4)
654 return CMD_RET_USAGE;
655
656 if (fs_set_blk_dev(argv[1], argv[2], fstype))
657 return 1;
658
659 ret = fs_uuid(uuid);
660 if (ret)
661 return CMD_RET_FAILURE;
662
663 if (argc == 4)
Simon Glass6a38e412017-08-03 12:22:09 -0600664 env_set(argv[3], uuid);
Christian Gmeiner9f9eec32014-11-12 14:35:04 +0100665 else
666 printf("%s\n", uuid);
667
668 return CMD_RET_SUCCESS;
669}
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100670
671int do_fs_type(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
672{
673 struct fstype_info *info;
674
675 if (argc < 3 || argc > 4)
676 return CMD_RET_USAGE;
677
678 if (fs_set_blk_dev(argv[1], argv[2], FS_TYPE_ANY))
679 return 1;
680
681 info = fs_get_info(fs_type);
682
683 if (argc == 4)
Simon Glass6a38e412017-08-03 12:22:09 -0600684 env_set(argv[3], info->name);
Sjoerd Simons7d9faf62015-01-05 18:13:36 +0100685 else
686 printf("%s\n", info->name);
687
688 return CMD_RET_SUCCESS;
689}
690