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