]> git.ipfire.org Git - people/ms/u-boot.git/blame - fs/fs.c
Remove CONFIG_SYS_BOOTCOUNT_SINGLEWORD
[people/ms/u-boot.git] / fs / fs.c
CommitLineData
045fa1e1
SW
1/*
2 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
3 *
5b8031cc 4 * SPDX-License-Identifier: GPL-2.0
045fa1e1
SW
5 */
6
7#include <config.h>
59e890ef 8#include <errno.h>
045fa1e1 9#include <common.h>
0eb25b61 10#include <mapmem.h>
045fa1e1
SW
11#include <part.h>
12#include <ext4fs.h>
13#include <fat.h>
14#include <fs.h>
92ccc96b 15#include <sandboxfs.h>
251cee0d 16#include <ubifs_uboot.h>
0c936ee3 17#include <btrfs.h>
117e0507 18#include <asm/io.h>
9e374e7b
TR
19#include <div64.h>
20#include <linux/math64.h>
045fa1e1 21
a1b231ce
SW
22DECLARE_GLOBAL_DATA_PTR;
23
4101f687 24static struct blk_desc *fs_dev_desc;
4bbcc965 25static int fs_dev_part;
045fa1e1
SW
26static disk_partition_t fs_partition;
27static int fs_type = FS_TYPE_ANY;
28
4101f687 29static inline int fs_probe_unsupported(struct blk_desc *fs_dev_desc,
2ded0d47 30 disk_partition_t *fs_partition)
436e2b73
SG
31{
32 printf("** Unrecognized filesystem type **\n");
33 return -1;
34}
35
045fa1e1
SW
36static inline int fs_ls_unsupported(const char *dirname)
37{
045fa1e1
SW
38 return -1;
39}
40
89191d62
RC
41/* 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
6152916a
SW
70static inline int fs_exists_unsupported(const char *filename)
71{
72 return 0;
73}
74
d455d878 75static inline int fs_size_unsupported(const char *filename, loff_t *size)
cf659819
SW
76{
77 return -1;
78}
79
117e0507 80static inline int fs_read_unsupported(const char *filename, void *buf,
d455d878
SR
81 loff_t offset, loff_t len,
82 loff_t *actread)
045fa1e1 83{
045fa1e1
SW
84 return -1;
85}
86
a8f6ab52 87static inline int fs_write_unsupported(const char *filename, void *buf,
d455d878
SR
88 loff_t offset, loff_t len,
89 loff_t *actwrite)
a8f6ab52
SG
90{
91 return -1;
92}
93
436e2b73
SG
94static inline void fs_close_unsupported(void)
95{
96}
97
59e890ef
CG
98static inline int fs_uuid_unsupported(char *uuid_str)
99{
100 return -1;
101}
102
4bbcc965
RC
103static inline int fs_opendir_unsupported(const char *filename,
104 struct fs_dir_stream **dirs)
105{
106 return -EACCES;
107}
108
436e2b73 109struct fstype_info {
045fa1e1 110 int fstype;
1a1ad8e0 111 char *name;
377202b5
SW
112 /*
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;
4101f687 121 int (*probe)(struct blk_desc *fs_dev_desc,
2ded0d47 122 disk_partition_t *fs_partition);
436e2b73 123 int (*ls)(const char *dirname);
6152916a 124 int (*exists)(const char *filename);
d455d878
SR
125 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);
436e2b73 130 void (*close)(void);
59e890ef 131 int (*uuid)(char *uuid_str);
4bbcc965
RC
132 /*
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);
436e2b73
SG
146};
147
148static struct fstype_info fstypes[] = {
149#ifdef CONFIG_FS_FAT
045fa1e1
SW
150 {
151 .fstype = FS_TYPE_FAT,
1a1ad8e0 152 .name = "fat",
377202b5 153 .null_dev_desc_ok = false,
e6d52415
SG
154 .probe = fat_set_blk_dev,
155 .close = fat_close,
89191d62 156 .ls = fs_ls_generic,
b7b5f319 157 .exists = fat_exists,
cf659819 158 .size = fat_size,
e6d52415 159 .read = fat_read_file,
d455d878
SR
160#ifdef CONFIG_FAT_WRITE
161 .write = file_fat_write,
162#else
bd6fb31f 163 .write = fs_write_unsupported,
d455d878 164#endif
59e890ef 165 .uuid = fs_uuid_unsupported,
89191d62
RC
166 .opendir = fat_opendir,
167 .readdir = fat_readdir,
168 .closedir = fat_closedir,
045fa1e1 169 },
436e2b73
SG
170#endif
171#ifdef CONFIG_FS_EXT4
045fa1e1
SW
172 {
173 .fstype = FS_TYPE_EXT,
1a1ad8e0 174 .name = "ext4",
377202b5 175 .null_dev_desc_ok = false,
e6d52415
SG
176 .probe = ext4fs_probe,
177 .close = ext4fs_close,
436e2b73 178 .ls = ext4fs_ls,
55af5c93 179 .exists = ext4fs_exists,
cf659819 180 .size = ext4fs_size,
e6d52415 181 .read = ext4_read_file,
d455d878
SR
182#ifdef CONFIG_CMD_EXT4_WRITE
183 .write = ext4_write_file,
184#else
bd6fb31f 185 .write = fs_write_unsupported,
d455d878 186#endif
59e890ef 187 .uuid = ext4fs_uuid,
4bbcc965 188 .opendir = fs_opendir_unsupported,
436e2b73 189 },
92ccc96b
SG
190#endif
191#ifdef CONFIG_SANDBOX
192 {
193 .fstype = FS_TYPE_SANDBOX,
1a1ad8e0 194 .name = "sandbox",
377202b5 195 .null_dev_desc_ok = true,
92ccc96b
SG
196 .probe = sandbox_fs_set_blk_dev,
197 .close = sandbox_fs_close,
198 .ls = sandbox_fs_ls,
0a30aa1e 199 .exists = sandbox_fs_exists,
cf659819 200 .size = sandbox_fs_size,
92ccc96b 201 .read = fs_read_sandbox,
7eb2c8d5 202 .write = fs_write_sandbox,
59e890ef 203 .uuid = fs_uuid_unsupported,
4bbcc965 204 .opendir = fs_opendir_unsupported,
92ccc96b 205 },
251cee0d
HG
206#endif
207#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,
4bbcc965 220 .opendir = fs_opendir_unsupported,
251cee0d 221 },
0c936ee3
MB
222#endif
223#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,
38fc683d 236 .opendir = fs_opendir_unsupported,
0c936ee3 237 },
436e2b73
SG
238#endif
239 {
240 .fstype = FS_TYPE_ANY,
1a1ad8e0 241 .name = "unsupported",
377202b5 242 .null_dev_desc_ok = true,
436e2b73
SG
243 .probe = fs_probe_unsupported,
244 .close = fs_close_unsupported,
245 .ls = fs_ls_unsupported,
6152916a 246 .exists = fs_exists_unsupported,
cf659819 247 .size = fs_size_unsupported,
436e2b73 248 .read = fs_read_unsupported,
a8f6ab52 249 .write = fs_write_unsupported,
59e890ef 250 .uuid = fs_uuid_unsupported,
4bbcc965 251 .opendir = fs_opendir_unsupported,
045fa1e1
SW
252 },
253};
254
c6f548d2
SG
255static 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
045fa1e1
SW
269int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
270{
436e2b73 271 struct fstype_info *info;
045fa1e1 272 int part, i;
a1b231ce
SW
273#ifdef CONFIG_NEEDS_MANUAL_RELOC
274 static int relocated;
275
276 if (!relocated) {
436e2b73
SG
277 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes);
278 i++, info++) {
1a1ad8e0 279 info->name += gd->reloc_off;
436e2b73
SG
280 info->probe += gd->reloc_off;
281 info->close += gd->reloc_off;
282 info->ls += gd->reloc_off;
283 info->read += gd->reloc_off;
a8f6ab52 284 info->write += gd->reloc_off;
436e2b73 285 }
a1b231ce
SW
286 relocated = 1;
287 }
288#endif
045fa1e1 289
e35929e4 290 part = blk_get_device_part_str(ifname, dev_part_str, &fs_dev_desc,
045fa1e1
SW
291 &fs_partition, 1);
292 if (part < 0)
293 return -1;
294
436e2b73
SG
295 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)
045fa1e1
SW
298 continue;
299
377202b5
SW
300 if (!fs_dev_desc && !info->null_dev_desc_ok)
301 continue;
302
4bbcc965
RC
303 if (!info->probe(fs_dev_desc, &fs_partition)) {
304 fs_type = info->fstype;
305 fs_dev_part = part;
306 return 0;
307 }
308 }
309
310 return -1;
311}
312
313/* 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++) {
2ded0d47 328 if (!info->probe(fs_dev_desc, &fs_partition)) {
436e2b73 329 fs_type = info->fstype;
045fa1e1
SW
330 return 0;
331 }
332 }
333
045fa1e1
SW
334 return -1;
335}
336
337static void fs_close(void)
338{
c6f548d2 339 struct fstype_info *info = fs_get_info(fs_type);
045fa1e1 340
c6f548d2 341 info->close();
e6d52415 342
045fa1e1
SW
343 fs_type = FS_TYPE_ANY;
344}
345
59e890ef
CG
346int 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
045fa1e1
SW
353int fs_ls(const char *dirname)
354{
355 int ret;
356
c6f548d2
SG
357 struct fstype_info *info = fs_get_info(fs_type);
358
359 ret = info->ls(dirname);
045fa1e1 360
e6d52415 361 fs_type = FS_TYPE_ANY;
045fa1e1
SW
362 fs_close();
363
364 return ret;
365}
366
6152916a
SW
367int 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
d455d878 380int fs_size(const char *filename, loff_t *size)
cf659819
SW
381{
382 int ret;
383
384 struct fstype_info *info = fs_get_info(fs_type);
385
d455d878 386 ret = info->size(filename, size);
cf659819
SW
387
388 fs_close();
389
390 return ret;
391}
392
d455d878
SR
393int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len,
394 loff_t *actread)
045fa1e1 395{
c6f548d2 396 struct fstype_info *info = fs_get_info(fs_type);
117e0507 397 void *buf;
045fa1e1
SW
398 int ret;
399
117e0507
SG
400 /*
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);
d455d878 405 ret = info->read(filename, buf, offset, len, actread);
117e0507 406 unmap_sysmem(buf);
045fa1e1 407
c6f548d2 408 /* If we requested a specific number of bytes, check we got it */
7a3e70cf 409 if (ret == 0 && len && *actread != len)
a327bde7 410 debug("** %s shorter than offset + len **\n", filename);
045fa1e1
SW
411 fs_close();
412
413 return ret;
414}
415
d455d878
SR
416int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
417 loff_t *actwrite)
a8f6ab52
SG
418{
419 struct fstype_info *info = fs_get_info(fs_type);
420 void *buf;
421 int ret;
422
a8f6ab52 423 buf = map_sysmem(addr, len);
d455d878 424 ret = info->write(filename, buf, offset, len, actwrite);
a8f6ab52
SG
425 unmap_sysmem(buf);
426
d455d878 427 if (ret < 0 && len != *actwrite) {
a8f6ab52
SG
428 printf("** Unable to write file %s **\n", filename);
429 ret = -1;
430 }
431 fs_close();
432
433 return ret;
434}
435
4bbcc965
RC
436struct 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
cf659819
SW
489int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
490 int fstype)
491{
d455d878 492 loff_t size;
cf659819
SW
493
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
d455d878 500 if (fs_size(argv[3], &size) < 0)
cf659819
SW
501 return CMD_RET_FAILURE;
502
018f5303 503 env_set_hex("filesize", size);
cf659819
SW
504
505 return 0;
506}
507
f9b55e22 508int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
b770e88a 509 int fstype)
045fa1e1
SW
510{
511 unsigned long addr;
512 const char *addr_str;
513 const char *filename;
d455d878
SR
514 loff_t bytes;
515 loff_t pos;
516 loff_t len_read;
517 int ret;
da1fd96c 518 unsigned long time;
949bbd7c 519 char *ep;
045fa1e1 520
e9b0f99e
SW
521 if (argc < 2)
522 return CMD_RET_USAGE;
523 if (argc > 7)
045fa1e1
SW
524 return CMD_RET_USAGE;
525
e9b0f99e 526 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
045fa1e1
SW
527 return 1;
528
529 if (argc >= 4) {
949bbd7c
PM
530 addr = simple_strtoul(argv[3], &ep, 16);
531 if (ep == argv[3] || *ep != '\0')
532 return CMD_RET_USAGE;
045fa1e1 533 } else {
00caae6d 534 addr_str = env_get("loadaddr");
045fa1e1
SW
535 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 {
00caae6d 543 filename = env_get("bootfile");
045fa1e1
SW
544 if (!filename) {
545 puts("** No boot file defined **\n");
546 return 1;
547 }
548 }
549 if (argc >= 6)
b770e88a 550 bytes = simple_strtoul(argv[5], NULL, 16);
045fa1e1
SW
551 else
552 bytes = 0;
553 if (argc >= 7)
b770e88a 554 pos = simple_strtoul(argv[6], NULL, 16);
045fa1e1
SW
555 else
556 pos = 0;
557
da1fd96c 558 time = get_timer(0);
d455d878 559 ret = fs_read(filename, addr, pos, bytes, &len_read);
da1fd96c 560 time = get_timer(time);
d455d878 561 if (ret < 0)
045fa1e1
SW
562 return 1;
563
d455d878 564 printf("%llu bytes read in %lu ms", len_read, time);
da1fd96c
AB
565 if (time > 0) {
566 puts(" (");
9e374e7b 567 print_size(div_u64(len_read, time) * 1000, "/s");
da1fd96c
AB
568 puts(")");
569 }
570 puts("\n");
045fa1e1 571
018f5303
SG
572 env_set_hex("fileaddr", addr);
573 env_set_hex("filesize", len_read);
045fa1e1
SW
574
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;
e9b0f99e
SW
583 if (argc > 4)
584 return CMD_RET_USAGE;
045fa1e1
SW
585
586 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
587 return 1;
588
e9b0f99e 589 if (fs_ls(argc >= 4 ? argv[3] : "/"))
045fa1e1
SW
590 return 1;
591
592 return 0;
593}
a8f6ab52 594
6152916a
SW
595int 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
a8f6ab52 604int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
b770e88a 605 int fstype)
a8f6ab52
SG
606{
607 unsigned long addr;
608 const char *filename;
d455d878
SR
609 loff_t bytes;
610 loff_t pos;
611 loff_t len;
612 int ret;
a8f6ab52
SG
613 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
d455d878
SR
621 addr = simple_strtoul(argv[3], NULL, 16);
622 filename = argv[4];
b770e88a 623 bytes = simple_strtoul(argv[5], NULL, 16);
a8f6ab52 624 if (argc >= 7)
b770e88a 625 pos = simple_strtoul(argv[6], NULL, 16);
a8f6ab52
SG
626 else
627 pos = 0;
628
629 time = get_timer(0);
d455d878 630 ret = fs_write(filename, addr, pos, bytes, &len);
a8f6ab52 631 time = get_timer(time);
d455d878 632 if (ret < 0)
a8f6ab52
SG
633 return 1;
634
d455d878 635 printf("%llu bytes written in %lu ms", len, time);
a8f6ab52
SG
636 if (time > 0) {
637 puts(" (");
9e374e7b 638 print_size(div_u64(len, time) * 1000, "/s");
a8f6ab52
SG
639 puts(")");
640 }
641 puts("\n");
642
643 return 0;
644}
59e890ef
CG
645
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)
382bee57 664 env_set(argv[3], uuid);
59e890ef
CG
665 else
666 printf("%s\n", uuid);
667
668 return CMD_RET_SUCCESS;
669}
1a1ad8e0
SS
670
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)
382bee57 684 env_set(argv[3], info->name);
1a1ad8e0
SS
685 else
686 printf("%s\n", info->name);
687
688 return CMD_RET_SUCCESS;
689}
690