Merge tag 'u-boot-imx-20190628' of https://gitlab.denx.de/u-boot/custodians/u-boot-imx
[oweals/u-boot.git] / fs / fs.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
4  */
5
6 #include <config.h>
7 #include <errno.h>
8 #include <common.h>
9 #include <mapmem.h>
10 #include <part.h>
11 #include <ext4fs.h>
12 #include <fat.h>
13 #include <fs.h>
14 #include <sandboxfs.h>
15 #include <ubifs_uboot.h>
16 #include <btrfs.h>
17 #include <asm/io.h>
18 #include <div64.h>
19 #include <linux/math64.h>
20 #include <efi_loader.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 int fs_ln_unsupported(const char *filename, const char *target)
95 {
96         return -1;
97 }
98
99 static inline void fs_close_unsupported(void)
100 {
101 }
102
103 static inline int fs_uuid_unsupported(char *uuid_str)
104 {
105         return -1;
106 }
107
108 static inline int fs_opendir_unsupported(const char *filename,
109                                          struct fs_dir_stream **dirs)
110 {
111         return -EACCES;
112 }
113
114 static inline int fs_unlink_unsupported(const char *filename)
115 {
116         return -1;
117 }
118
119 static inline int fs_mkdir_unsupported(const char *dirname)
120 {
121         return -1;
122 }
123
124 struct fstype_info {
125         int fstype;
126         char *name;
127         /*
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
131          * set to true. This should also be true for the dummy entry at the end
132          * of fstypes[], since that is essentially a "virtual" (non-existent)
133          * filesystem.
134          */
135         bool null_dev_desc_ok;
136         int (*probe)(struct blk_desc *fs_dev_desc,
137                      disk_partition_t *fs_partition);
138         int (*ls)(const char *dirname);
139         int (*exists)(const char *filename);
140         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);
145         void (*close)(void);
146         int (*uuid)(char *uuid_str);
147         /*
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);
161         int (*unlink)(const char *filename);
162         int (*mkdir)(const char *dirname);
163         int (*ln)(const char *filename, const char *target);
164 };
165
166 static struct fstype_info fstypes[] = {
167 #ifdef CONFIG_FS_FAT
168         {
169                 .fstype = FS_TYPE_FAT,
170                 .name = "fat",
171                 .null_dev_desc_ok = false,
172                 .probe = fat_set_blk_dev,
173                 .close = fat_close,
174                 .ls = fs_ls_generic,
175                 .exists = fat_exists,
176                 .size = fat_size,
177                 .read = fat_read_file,
178 #if CONFIG_IS_ENABLED(FAT_WRITE)
179                 .write = file_fat_write,
180                 .unlink = fat_unlink,
181                 .mkdir = fat_mkdir,
182 #else
183                 .write = fs_write_unsupported,
184                 .unlink = fs_unlink_unsupported,
185                 .mkdir = fs_mkdir_unsupported,
186 #endif
187                 .uuid = fs_uuid_unsupported,
188                 .opendir = fat_opendir,
189                 .readdir = fat_readdir,
190                 .closedir = fat_closedir,
191                 .ln = fs_ln_unsupported,
192         },
193 #endif
194
195 #if CONFIG_IS_ENABLED(FS_EXT4)
196         {
197                 .fstype = FS_TYPE_EXT,
198                 .name = "ext4",
199                 .null_dev_desc_ok = false,
200                 .probe = ext4fs_probe,
201                 .close = ext4fs_close,
202                 .ls = ext4fs_ls,
203                 .exists = ext4fs_exists,
204                 .size = ext4fs_size,
205                 .read = ext4_read_file,
206 #ifdef CONFIG_CMD_EXT4_WRITE
207                 .write = ext4_write_file,
208                 .ln = ext4fs_create_link,
209 #else
210                 .write = fs_write_unsupported,
211                 .ln = fs_ln_unsupported,
212 #endif
213                 .uuid = ext4fs_uuid,
214                 .opendir = fs_opendir_unsupported,
215                 .unlink = fs_unlink_unsupported,
216                 .mkdir = fs_mkdir_unsupported,
217         },
218 #endif
219 #ifdef CONFIG_SANDBOX
220         {
221                 .fstype = FS_TYPE_SANDBOX,
222                 .name = "sandbox",
223                 .null_dev_desc_ok = true,
224                 .probe = sandbox_fs_set_blk_dev,
225                 .close = sandbox_fs_close,
226                 .ls = sandbox_fs_ls,
227                 .exists = sandbox_fs_exists,
228                 .size = sandbox_fs_size,
229                 .read = fs_read_sandbox,
230                 .write = fs_write_sandbox,
231                 .uuid = fs_uuid_unsupported,
232                 .opendir = fs_opendir_unsupported,
233                 .unlink = fs_unlink_unsupported,
234                 .mkdir = fs_mkdir_unsupported,
235                 .ln = fs_ln_unsupported,
236         },
237 #endif
238 #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,
251                 .opendir = fs_opendir_unsupported,
252                 .unlink = fs_unlink_unsupported,
253                 .mkdir = fs_mkdir_unsupported,
254                 .ln = fs_ln_unsupported,
255         },
256 #endif
257 #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,
270                 .opendir = fs_opendir_unsupported,
271                 .unlink = fs_unlink_unsupported,
272                 .mkdir = fs_mkdir_unsupported,
273                 .ln = fs_ln_unsupported,
274         },
275 #endif
276         {
277                 .fstype = FS_TYPE_ANY,
278                 .name = "unsupported",
279                 .null_dev_desc_ok = true,
280                 .probe = fs_probe_unsupported,
281                 .close = fs_close_unsupported,
282                 .ls = fs_ls_unsupported,
283                 .exists = fs_exists_unsupported,
284                 .size = fs_size_unsupported,
285                 .read = fs_read_unsupported,
286                 .write = fs_write_unsupported,
287                 .uuid = fs_uuid_unsupported,
288                 .opendir = fs_opendir_unsupported,
289                 .unlink = fs_unlink_unsupported,
290                 .mkdir = fs_mkdir_unsupported,
291                 .ln = fs_ln_unsupported,
292         },
293 };
294
295 static 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
309 /**
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  */
317 const char *fs_get_type_name(void)
318 {
319         return fs_get_info(fs_type)->name;
320 }
321
322 int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
323 {
324         struct fstype_info *info;
325         int part, i;
326 #ifdef CONFIG_NEEDS_MANUAL_RELOC
327         static int relocated;
328
329         if (!relocated) {
330                 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes);
331                                 i++, info++) {
332                         info->name += gd->reloc_off;
333                         info->probe += gd->reloc_off;
334                         info->close += gd->reloc_off;
335                         info->ls += gd->reloc_off;
336                         info->read += gd->reloc_off;
337                         info->write += gd->reloc_off;
338                 }
339                 relocated = 1;
340         }
341 #endif
342
343         part = blk_get_device_part_str(ifname, dev_part_str, &fs_dev_desc,
344                                         &fs_partition, 1);
345         if (part < 0)
346                 return -1;
347
348         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)
351                         continue;
352
353                 if (!fs_dev_desc && !info->null_dev_desc_ok)
354                         continue;
355
356                 if (!info->probe(fs_dev_desc, &fs_partition)) {
357                         fs_type = info->fstype;
358                         fs_dev_part = part;
359                         return 0;
360                 }
361         }
362
363         return -1;
364 }
365
366 /* set current blk device w/ blk_desc + partition # */
367 int 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;
383                         fs_dev_part = part;
384                         return 0;
385                 }
386         }
387
388         return -1;
389 }
390
391 static void fs_close(void)
392 {
393         struct fstype_info *info = fs_get_info(fs_type);
394
395         info->close();
396
397         fs_type = FS_TYPE_ANY;
398 }
399
400 int 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
407 int fs_ls(const char *dirname)
408 {
409         int ret;
410
411         struct fstype_info *info = fs_get_info(fs_type);
412
413         ret = info->ls(dirname);
414
415         fs_type = FS_TYPE_ANY;
416         fs_close();
417
418         return ret;
419 }
420
421 int 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
434 int fs_size(const char *filename, loff_t *size)
435 {
436         int ret;
437
438         struct fstype_info *info = fs_get_info(fs_type);
439
440         ret = info->size(filename, size);
441
442         fs_close();
443
444         return ret;
445 }
446
447 #ifdef CONFIG_LMB
448 /* Check if a file may be read to the given address */
449 static 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
471         lmb_init_and_reserve(&lmb, gd->bd, (void *)gd->fdt_blob);
472         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
482 static int _fs_read(const char *filename, ulong addr, loff_t offset, loff_t len,
483                     int do_lmb_check, loff_t *actread)
484 {
485         struct fstype_info *info = fs_get_info(fs_type);
486         void *buf;
487         int ret;
488
489 #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
497         /*
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);
502         ret = info->read(filename, buf, offset, len, actread);
503         unmap_sysmem(buf);
504
505         /* If we requested a specific number of bytes, check we got it */
506         if (ret == 0 && len && *actread != len)
507                 debug("** %s shorter than offset + len **\n", filename);
508         fs_close();
509
510         return ret;
511 }
512
513 int 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
519 int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
520              loff_t *actwrite)
521 {
522         struct fstype_info *info = fs_get_info(fs_type);
523         void *buf;
524         int ret;
525
526         buf = map_sysmem(addr, len);
527         ret = info->write(filename, buf, offset, len, actwrite);
528         unmap_sysmem(buf);
529
530         if (ret < 0 && len != *actwrite) {
531                 printf("** Unable to write file %s **\n", filename);
532                 ret = -1;
533         }
534         fs_close();
535
536         return ret;
537 }
538
539 struct 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
558 struct 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
577 void 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
591 int 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 }
604
605 int 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 }
618
619 int 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
635 int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
636                 int fstype)
637 {
638         loff_t size;
639
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
646         if (fs_size(argv[3], &size) < 0)
647                 return CMD_RET_FAILURE;
648
649         env_set_hex("filesize", size);
650
651         return 0;
652 }
653
654 int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
655                 int fstype)
656 {
657         unsigned long addr;
658         const char *addr_str;
659         const char *filename;
660         loff_t bytes;
661         loff_t pos;
662         loff_t len_read;
663         int ret;
664         unsigned long time;
665         char *ep;
666
667         if (argc < 2)
668                 return CMD_RET_USAGE;
669         if (argc > 7)
670                 return CMD_RET_USAGE;
671
672         if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
673                 return 1;
674
675         if (argc >= 4) {
676                 addr = simple_strtoul(argv[3], &ep, 16);
677                 if (ep == argv[3] || *ep != '\0')
678                         return CMD_RET_USAGE;
679         } else {
680                 addr_str = env_get("loadaddr");
681                 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 {
689                 filename = env_get("bootfile");
690                 if (!filename) {
691                         puts("** No boot file defined **\n");
692                         return 1;
693                 }
694         }
695         if (argc >= 6)
696                 bytes = simple_strtoul(argv[5], NULL, 16);
697         else
698                 bytes = 0;
699         if (argc >= 7)
700                 pos = simple_strtoul(argv[6], NULL, 16);
701         else
702                 pos = 0;
703
704 #ifdef CONFIG_CMD_BOOTEFI
705         efi_set_bootdev(argv[1], (argc > 2) ? argv[2] : "",
706                         (argc > 4) ? argv[4] : "");
707 #endif
708         time = get_timer(0);
709         ret = _fs_read(filename, addr, pos, bytes, 1, &len_read);
710         time = get_timer(time);
711         if (ret < 0)
712                 return 1;
713
714         printf("%llu bytes read in %lu ms", len_read, time);
715         if (time > 0) {
716                 puts(" (");
717                 print_size(div_u64(len_read, time) * 1000, "/s");
718                 puts(")");
719         }
720         puts("\n");
721
722         env_set_hex("fileaddr", addr);
723         env_set_hex("filesize", len_read);
724
725         return 0;
726 }
727
728 int 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;
733         if (argc > 4)
734                 return CMD_RET_USAGE;
735
736         if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
737                 return 1;
738
739         if (fs_ls(argc >= 4 ? argv[3] : "/"))
740                 return 1;
741
742         return 0;
743 }
744
745 int 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
754 int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
755                 int fstype)
756 {
757         unsigned long addr;
758         const char *filename;
759         loff_t bytes;
760         loff_t pos;
761         loff_t len;
762         int ret;
763         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
771         addr = simple_strtoul(argv[3], NULL, 16);
772         filename = argv[4];
773         bytes = simple_strtoul(argv[5], NULL, 16);
774         if (argc >= 7)
775                 pos = simple_strtoul(argv[6], NULL, 16);
776         else
777                 pos = 0;
778
779         time = get_timer(0);
780         ret = fs_write(filename, addr, pos, bytes, &len);
781         time = get_timer(time);
782         if (ret < 0)
783                 return 1;
784
785         printf("%llu bytes written in %lu ms", len, time);
786         if (time > 0) {
787                 puts(" (");
788                 print_size(div_u64(len, time) * 1000, "/s");
789                 puts(")");
790         }
791         puts("\n");
792
793         return 0;
794 }
795
796 int 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)
814                 env_set(argv[3], uuid);
815         else
816                 printf("%s\n", uuid);
817
818         return CMD_RET_SUCCESS;
819 }
820
821 int 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)
834                 env_set(argv[3], info->name);
835         else
836                 printf("%s\n", info->name);
837
838         fs_close();
839
840         return CMD_RET_SUCCESS;
841 }
842
843 int 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
858 int 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 }
877
878 int 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 }