uboot/fs/fs.c
<<
>>
Prefs
   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 <env.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#include <efi_loader.h>
  22
  23DECLARE_GLOBAL_DATA_PTR;
  24
  25static struct blk_desc *fs_dev_desc;
  26static int fs_dev_part;
  27static disk_partition_t fs_partition;
  28static int fs_type = FS_TYPE_ANY;
  29
  30static inline int fs_probe_unsupported(struct blk_desc *fs_dev_desc,
  31                                      disk_partition_t *fs_partition)
  32{
  33        printf("** Unrecognized filesystem type **\n");
  34        return -1;
  35}
  36
  37static inline int fs_ls_unsupported(const char *dirname)
  38{
  39        return -1;
  40}
  41
  42/* generic implementation of ls in terms of opendir/readdir/closedir */
  43__maybe_unused
  44static int fs_ls_generic(const char *dirname)
  45{
  46        struct fs_dir_stream *dirs;
  47        struct fs_dirent *dent;
  48        int nfiles = 0, ndirs = 0;
  49
  50        dirs = fs_opendir(dirname);
  51        if (!dirs)
  52                return -errno;
  53
  54        while ((dent = fs_readdir(dirs))) {
  55                if (dent->type == FS_DT_DIR) {
  56                        printf("            %s/\n", dent->name);
  57                        ndirs++;
  58                } else {
  59                        printf(" %8lld   %s\n", dent->size, dent->name);
  60                        nfiles++;
  61                }
  62        }
  63
  64        fs_closedir(dirs);
  65
  66        printf("\n%d file(s), %d dir(s)\n\n", nfiles, ndirs);
  67
  68        return 0;
  69}
  70
  71static inline int fs_exists_unsupported(const char *filename)
  72{
  73        return 0;
  74}
  75
  76static inline int fs_size_unsupported(const char *filename, loff_t *size)
  77{
  78        return -1;
  79}
  80
  81static inline int fs_read_unsupported(const char *filename, void *buf,
  82                                      loff_t offset, loff_t len,
  83                                      loff_t *actread)
  84{
  85        return -1;
  86}
  87
  88static inline int fs_write_unsupported(const char *filename, void *buf,
  89                                      loff_t offset, loff_t len,
  90                                      loff_t *actwrite)
  91{
  92        return -1;
  93}
  94
  95static inline int fs_ln_unsupported(const char *filename, const char *target)
  96{
  97        return -1;
  98}
  99
 100static inline void fs_close_unsupported(void)
 101{
 102}
 103
 104static inline int fs_uuid_unsupported(char *uuid_str)
 105{
 106        return -1;
 107}
 108
 109static inline int fs_opendir_unsupported(const char *filename,
 110                                         struct fs_dir_stream **dirs)
 111{
 112        return -EACCES;
 113}
 114
 115static inline int fs_unlink_unsupported(const char *filename)
 116{
 117        return -1;
 118}
 119
 120static inline int fs_mkdir_unsupported(const char *dirname)
 121{
 122        return -1;
 123}
 124
 125struct fstype_info {
 126        int fstype;
 127        char *name;
 128        /*
 129         * Is it legal to pass NULL as .probe()'s  fs_dev_desc parameter? This
 130         * should be false in most cases. For "virtual" filesystems which
 131         * aren't based on a U-Boot block device (e.g. sandbox), this can be
 132         * set to true. This should also be true for the dummy entry at the end
 133         * of fstypes[], since that is essentially a "virtual" (non-existent)
 134         * filesystem.
 135         */
 136        bool null_dev_desc_ok;
 137        int (*probe)(struct blk_desc *fs_dev_desc,
 138                     disk_partition_t *fs_partition);
 139        int (*ls)(const char *dirname);
 140        int (*exists)(const char *filename);
 141        int (*size)(const char *filename, loff_t *size);
 142        int (*read)(const char *filename, void *buf, loff_t offset,
 143                    loff_t len, loff_t *actread);
 144        int (*write)(const char *filename, void *buf, loff_t offset,
 145                     loff_t len, loff_t *actwrite);
 146        void (*close)(void);
 147        int (*uuid)(char *uuid_str);
 148        /*
 149         * Open a directory stream.  On success return 0 and directory
 150         * stream pointer via 'dirsp'.  On error, return -errno.  See
 151         * fs_opendir().
 152         */
 153        int (*opendir)(const char *filename, struct fs_dir_stream **dirsp);
 154        /*
 155         * Read next entry from directory stream.  On success return 0
 156         * and directory entry pointer via 'dentp'.  On error return
 157         * -errno.  See fs_readdir().
 158         */
 159        int (*readdir)(struct fs_dir_stream *dirs, struct fs_dirent **dentp);
 160        /* see fs_closedir() */
 161        void (*closedir)(struct fs_dir_stream *dirs);
 162        int (*unlink)(const char *filename);
 163        int (*mkdir)(const char *dirname);
 164        int (*ln)(const char *filename, const char *target);
 165};
 166
 167static struct fstype_info fstypes[] = {
 168#ifdef CONFIG_FS_FAT
 169        {
 170                .fstype = FS_TYPE_FAT,
 171                .name = "fat",
 172                .null_dev_desc_ok = false,
 173                .probe = fat_set_blk_dev,
 174                .close = fat_close,
 175                .ls = fs_ls_generic,
 176                .exists = fat_exists,
 177                .size = fat_size,
 178                .read = fat_read_file,
 179#if CONFIG_IS_ENABLED(FAT_WRITE)
 180                .write = file_fat_write,
 181                .unlink = fat_unlink,
 182                .mkdir = fat_mkdir,
 183#else
 184                .write = fs_write_unsupported,
 185                .unlink = fs_unlink_unsupported,
 186                .mkdir = fs_mkdir_unsupported,
 187#endif
 188                .uuid = fs_uuid_unsupported,
 189                .opendir = fat_opendir,
 190                .readdir = fat_readdir,
 191                .closedir = fat_closedir,
 192                .ln = fs_ln_unsupported,
 193        },
 194#endif
 195
 196#if CONFIG_IS_ENABLED(FS_EXT4)
 197        {
 198                .fstype = FS_TYPE_EXT,
 199                .name = "ext4",
 200                .null_dev_desc_ok = false,
 201                .probe = ext4fs_probe,
 202                .close = ext4fs_close,
 203                .ls = ext4fs_ls,
 204                .exists = ext4fs_exists,
 205                .size = ext4fs_size,
 206                .read = ext4_read_file,
 207#ifdef CONFIG_CMD_EXT4_WRITE
 208                .write = ext4_write_file,
 209                .ln = ext4fs_create_link,
 210#else
 211                .write = fs_write_unsupported,
 212                .ln = fs_ln_unsupported,
 213#endif
 214                .uuid = ext4fs_uuid,
 215                .opendir = fs_opendir_unsupported,
 216                .unlink = fs_unlink_unsupported,
 217                .mkdir = fs_mkdir_unsupported,
 218        },
 219#endif
 220#ifdef CONFIG_SANDBOX
 221        {
 222                .fstype = FS_TYPE_SANDBOX,
 223                .name = "sandbox",
 224                .null_dev_desc_ok = true,
 225                .probe = sandbox_fs_set_blk_dev,
 226                .close = sandbox_fs_close,
 227                .ls = sandbox_fs_ls,
 228                .exists = sandbox_fs_exists,
 229                .size = sandbox_fs_size,
 230                .read = fs_read_sandbox,
 231                .write = fs_write_sandbox,
 232                .uuid = fs_uuid_unsupported,
 233                .opendir = fs_opendir_unsupported,
 234                .unlink = fs_unlink_unsupported,
 235                .mkdir = fs_mkdir_unsupported,
 236                .ln = fs_ln_unsupported,
 237        },
 238#endif
 239#ifdef CONFIG_CMD_UBIFS
 240        {
 241                .fstype = FS_TYPE_UBIFS,
 242                .name = "ubifs",
 243                .null_dev_desc_ok = true,
 244                .probe = ubifs_set_blk_dev,
 245                .close = ubifs_close,
 246                .ls = ubifs_ls,
 247                .exists = ubifs_exists,
 248                .size = ubifs_size,
 249                .read = ubifs_read,
 250                .write = fs_write_unsupported,
 251                .uuid = fs_uuid_unsupported,
 252                .opendir = fs_opendir_unsupported,
 253                .unlink = fs_unlink_unsupported,
 254                .mkdir = fs_mkdir_unsupported,
 255                .ln = fs_ln_unsupported,
 256        },
 257#endif
 258#ifdef CONFIG_FS_BTRFS
 259        {
 260                .fstype = FS_TYPE_BTRFS,
 261                .name = "btrfs",
 262                .null_dev_desc_ok = false,
 263                .probe = btrfs_probe,
 264                .close = btrfs_close,
 265                .ls = btrfs_ls,
 266                .exists = btrfs_exists,
 267                .size = btrfs_size,
 268                .read = btrfs_read,
 269                .write = fs_write_unsupported,
 270                .uuid = btrfs_uuid,
 271                .opendir = fs_opendir_unsupported,
 272                .unlink = fs_unlink_unsupported,
 273                .mkdir = fs_mkdir_unsupported,
 274                .ln = fs_ln_unsupported,
 275        },
 276#endif
 277        {
 278                .fstype = FS_TYPE_ANY,
 279                .name = "unsupported",
 280                .null_dev_desc_ok = true,
 281                .probe = fs_probe_unsupported,
 282                .close = fs_close_unsupported,
 283                .ls = fs_ls_unsupported,
 284                .exists = fs_exists_unsupported,
 285                .size = fs_size_unsupported,
 286                .read = fs_read_unsupported,
 287                .write = fs_write_unsupported,
 288                .uuid = fs_uuid_unsupported,
 289                .opendir = fs_opendir_unsupported,
 290                .unlink = fs_unlink_unsupported,
 291                .mkdir = fs_mkdir_unsupported,
 292                .ln = fs_ln_unsupported,
 293        },
 294};
 295
 296static struct fstype_info *fs_get_info(int fstype)
 297{
 298        struct fstype_info *info;
 299        int i;
 300
 301        for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes) - 1; i++, info++) {
 302                if (fstype == info->fstype)
 303                        return info;
 304        }
 305
 306        /* Return the 'unsupported' sentinel */
 307        return info;
 308}
 309
 310/**
 311 * fs_get_type() - Get type of current filesystem
 312 *
 313 * Return: filesystem type
 314 *
 315 * Returns filesystem type representing the current filesystem, or
 316 * FS_TYPE_ANY for any unrecognised filesystem.
 317 */
 318int fs_get_type(void)
 319{
 320        return fs_type;
 321}
 322
 323/**
 324 * fs_get_type_name() - Get type of current filesystem
 325 *
 326 * Return: Pointer to filesystem name
 327 *
 328 * Returns a string describing the current filesystem, or the sentinel
 329 * "unsupported" for any unrecognised filesystem.
 330 */
 331const char *fs_get_type_name(void)
 332{
 333        return fs_get_info(fs_type)->name;
 334}
 335
 336int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
 337{
 338        struct fstype_info *info;
 339        int part, i;
 340#ifdef CONFIG_NEEDS_MANUAL_RELOC
 341        static int relocated;
 342
 343        if (!relocated) {
 344                for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes);
 345                                i++, info++) {
 346                        info->name += gd->reloc_off;
 347                        info->probe += gd->reloc_off;
 348                        info->close += gd->reloc_off;
 349                        info->ls += gd->reloc_off;
 350                        info->read += gd->reloc_off;
 351                        info->write += gd->reloc_off;
 352                }
 353                relocated = 1;
 354        }
 355#endif
 356
 357        part = blk_get_device_part_str(ifname, dev_part_str, &fs_dev_desc,
 358                                        &fs_partition, 1);
 359        if (part < 0)
 360                return -1;
 361
 362        for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
 363                if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY &&
 364                                fstype != info->fstype)
 365                        continue;
 366
 367                if (!fs_dev_desc && !info->null_dev_desc_ok)
 368                        continue;
 369
 370                if (!info->probe(fs_dev_desc, &fs_partition)) {
 371                        fs_type = info->fstype;
 372                        fs_dev_part = part;
 373                        return 0;
 374                }
 375        }
 376
 377        return -1;
 378}
 379
 380/* set current blk device w/ blk_desc + partition # */
 381int fs_set_blk_dev_with_part(struct blk_desc *desc, int part)
 382{
 383        struct fstype_info *info;
 384        int ret, i;
 385
 386        if (part >= 1)
 387                ret = part_get_info(desc, part, &fs_partition);
 388        else
 389                ret = part_get_info_whole_disk(desc, &fs_partition);
 390        if (ret)
 391                return ret;
 392        fs_dev_desc = desc;
 393
 394        for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
 395                if (!info->probe(fs_dev_desc, &fs_partition)) {
 396                        fs_type = info->fstype;
 397                        fs_dev_part = part;
 398                        return 0;
 399                }
 400        }
 401
 402        return -1;
 403}
 404
 405void fs_close(void)
 406{
 407        struct fstype_info *info = fs_get_info(fs_type);
 408
 409        info->close();
 410
 411        fs_type = FS_TYPE_ANY;
 412}
 413
 414int fs_uuid(char *uuid_str)
 415{
 416        struct fstype_info *info = fs_get_info(fs_type);
 417
 418        return info->uuid(uuid_str);
 419}
 420
 421int fs_ls(const char *dirname)
 422{
 423        int ret;
 424
 425        struct fstype_info *info = fs_get_info(fs_type);
 426
 427        ret = info->ls(dirname);
 428
 429        fs_close();
 430
 431        return ret;
 432}
 433
 434int fs_exists(const char *filename)
 435{
 436        int ret;
 437
 438        struct fstype_info *info = fs_get_info(fs_type);
 439
 440        ret = info->exists(filename);
 441
 442        fs_close();
 443
 444        return ret;
 445}
 446
 447int fs_size(const char *filename, loff_t *size)
 448{
 449        int ret;
 450
 451        struct fstype_info *info = fs_get_info(fs_type);
 452
 453        ret = info->size(filename, size);
 454
 455        fs_close();
 456
 457        return ret;
 458}
 459
 460#ifdef CONFIG_LMB
 461/* Check if a file may be read to the given address */
 462static int fs_read_lmb_check(const char *filename, ulong addr, loff_t offset,
 463                             loff_t len, struct fstype_info *info)
 464{
 465        struct lmb lmb;
 466        int ret;
 467        loff_t size;
 468        loff_t read_len;
 469
 470        /* get the actual size of the file */
 471        ret = info->size(filename, &size);
 472        if (ret)
 473                return ret;
 474        if (offset >= size) {
 475                /* offset >= EOF, no bytes will be written */
 476                return 0;
 477        }
 478        read_len = size - offset;
 479
 480        /* limit to 'len' if it is smaller */
 481        if (len && len < read_len)
 482                read_len = len;
 483
 484        lmb_init_and_reserve(&lmb, gd->bd, (void *)gd->fdt_blob);
 485        lmb_dump_all(&lmb);
 486
 487        if (lmb_alloc_addr(&lmb, addr, read_len) == addr)
 488                return 0;
 489
 490        printf("** Reading file would overwrite reserved memory **\n");
 491        return -ENOSPC;
 492}
 493#endif
 494
 495static int _fs_read(const char *filename, ulong addr, loff_t offset, loff_t len,
 496                    int do_lmb_check, loff_t *actread)
 497{
 498        struct fstype_info *info = fs_get_info(fs_type);
 499        void *buf;
 500        int ret;
 501
 502#ifdef CONFIG_LMB
 503        if (do_lmb_check) {
 504                ret = fs_read_lmb_check(filename, addr, offset, len, info);
 505                if (ret)
 506                        return ret;
 507        }
 508#endif
 509
 510        /*
 511         * We don't actually know how many bytes are being read, since len==0
 512         * means read the whole file.
 513         */
 514        buf = map_sysmem(addr, len);
 515        ret = info->read(filename, buf, offset, len, actread);
 516        unmap_sysmem(buf);
 517
 518        /* If we requested a specific number of bytes, check we got it */
 519        if (ret == 0 && len && *actread != len)
 520                debug("** %s shorter than offset + len **\n", filename);
 521        fs_close();
 522
 523        return ret;
 524}
 525
 526int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len,
 527            loff_t *actread)
 528{
 529        return _fs_read(filename, addr, offset, len, 0, actread);
 530}
 531
 532int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
 533             loff_t *actwrite)
 534{
 535        struct fstype_info *info = fs_get_info(fs_type);
 536        void *buf;
 537        int ret;
 538
 539        buf = map_sysmem(addr, len);
 540        ret = info->write(filename, buf, offset, len, actwrite);
 541        unmap_sysmem(buf);
 542
 543        if (ret < 0 && len != *actwrite) {
 544                printf("** Unable to write file %s **\n", filename);
 545                ret = -1;
 546        }
 547        fs_close();
 548
 549        return ret;
 550}
 551
 552struct fs_dir_stream *fs_opendir(const char *filename)
 553{
 554        struct fstype_info *info = fs_get_info(fs_type);
 555        struct fs_dir_stream *dirs = NULL;
 556        int ret;
 557
 558        ret = info->opendir(filename, &dirs);
 559        fs_close();
 560        if (ret) {
 561                errno = -ret;
 562                return NULL;
 563        }
 564
 565        dirs->desc = fs_dev_desc;
 566        dirs->part = fs_dev_part;
 567
 568        return dirs;
 569}
 570
 571struct fs_dirent *fs_readdir(struct fs_dir_stream *dirs)
 572{
 573        struct fstype_info *info;
 574        struct fs_dirent *dirent;
 575        int ret;
 576
 577        fs_set_blk_dev_with_part(dirs->desc, dirs->part);
 578        info = fs_get_info(fs_type);
 579
 580        ret = info->readdir(dirs, &dirent);
 581        fs_close();
 582        if (ret) {
 583                errno = -ret;
 584                return NULL;
 585        }
 586
 587        return dirent;
 588}
 589
 590void fs_closedir(struct fs_dir_stream *dirs)
 591{
 592        struct fstype_info *info;
 593
 594        if (!dirs)
 595                return;
 596
 597        fs_set_blk_dev_with_part(dirs->desc, dirs->part);
 598        info = fs_get_info(fs_type);
 599
 600        info->closedir(dirs);
 601        fs_close();
 602}
 603
 604int fs_unlink(const char *filename)
 605{
 606        int ret;
 607
 608        struct fstype_info *info = fs_get_info(fs_type);
 609
 610        ret = info->unlink(filename);
 611
 612        fs_close();
 613
 614        return ret;
 615}
 616
 617int fs_mkdir(const char *dirname)
 618{
 619        int ret;
 620
 621        struct fstype_info *info = fs_get_info(fs_type);
 622
 623        ret = info->mkdir(dirname);
 624
 625        fs_close();
 626
 627        return ret;
 628}
 629
 630int fs_ln(const char *fname, const char *target)
 631{
 632        struct fstype_info *info = fs_get_info(fs_type);
 633        int ret;
 634
 635        ret = info->ln(fname, target);
 636
 637        if (ret < 0) {
 638                printf("** Unable to create link %s -> %s **\n", fname, target);
 639                ret = -1;
 640        }
 641        fs_close();
 642
 643        return ret;
 644}
 645
 646int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
 647                int fstype)
 648{
 649        loff_t size;
 650
 651        if (argc != 4)
 652                return CMD_RET_USAGE;
 653
 654        if (fs_set_blk_dev(argv[1], argv[2], fstype))
 655                return 1;
 656
 657        if (fs_size(argv[3], &size) < 0)
 658                return CMD_RET_FAILURE;
 659
 660        env_set_hex("filesize", size);
 661
 662        return 0;
 663}
 664
 665int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
 666                int fstype)
 667{
 668        unsigned long addr;
 669        const char *addr_str;
 670        const char *filename;
 671        loff_t bytes;
 672        loff_t pos;
 673        loff_t len_read;
 674        int ret;
 675        unsigned long time;
 676        char *ep;
 677
 678        if (argc < 2)
 679                return CMD_RET_USAGE;
 680        if (argc > 7)
 681                return CMD_RET_USAGE;
 682
 683        if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
 684                return 1;
 685
 686        if (argc >= 4) {
 687                addr = simple_strtoul(argv[3], &ep, 16);
 688                if (ep == argv[3] || *ep != '\0')
 689                        return CMD_RET_USAGE;
 690        } else {
 691                addr_str = env_get("loadaddr");
 692                if (addr_str != NULL)
 693                        addr = simple_strtoul(addr_str, NULL, 16);
 694                else
 695                        addr = CONFIG_SYS_LOAD_ADDR;
 696        }
 697        if (argc >= 5) {
 698                filename = argv[4];
 699        } else {
 700                filename = env_get("bootfile");
 701                if (!filename) {
 702                        puts("** No boot file defined **\n");
 703                        return 1;
 704                }
 705        }
 706        if (argc >= 6)
 707                bytes = simple_strtoul(argv[5], NULL, 16);
 708        else
 709                bytes = 0;
 710        if (argc >= 7)
 711                pos = simple_strtoul(argv[6], NULL, 16);
 712        else
 713                pos = 0;
 714
 715#ifdef CONFIG_CMD_BOOTEFI
 716        efi_set_bootdev(argv[1], (argc > 2) ? argv[2] : "",
 717                        (argc > 4) ? argv[4] : "");
 718#endif
 719        time = get_timer(0);
 720        ret = _fs_read(filename, addr, pos, bytes, 1, &len_read);
 721        time = get_timer(time);
 722        if (ret < 0)
 723                return 1;
 724
 725        printf("%llu bytes read in %lu ms", len_read, time);
 726        if (time > 0) {
 727                puts(" (");
 728                print_size(div_u64(len_read, time) * 1000, "/s");
 729                puts(")");
 730        }
 731        puts("\n");
 732
 733        env_set_hex("fileaddr", addr);
 734        env_set_hex("filesize", len_read);
 735
 736        return 0;
 737}
 738
 739int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
 740        int fstype)
 741{
 742        if (argc < 2)
 743                return CMD_RET_USAGE;
 744        if (argc > 4)
 745                return CMD_RET_USAGE;
 746
 747        if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
 748                return 1;
 749
 750        if (fs_ls(argc >= 4 ? argv[3] : "/"))
 751                return 1;
 752
 753        return 0;
 754}
 755
 756int file_exists(const char *dev_type, const char *dev_part, const char *file,
 757                int fstype)
 758{
 759        if (fs_set_blk_dev(dev_type, dev_part, fstype))
 760                return 0;
 761
 762        return fs_exists(file);
 763}
 764
 765int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
 766                int fstype)
 767{
 768        unsigned long addr;
 769        const char *filename;
 770        loff_t bytes;
 771        loff_t pos;
 772        loff_t len;
 773        int ret;
 774        unsigned long time;
 775
 776        if (argc < 6 || argc > 7)
 777                return CMD_RET_USAGE;
 778
 779        if (fs_set_blk_dev(argv[1], argv[2], fstype))
 780                return 1;
 781
 782        addr = simple_strtoul(argv[3], NULL, 16);
 783        filename = argv[4];
 784        bytes = simple_strtoul(argv[5], NULL, 16);
 785        if (argc >= 7)
 786                pos = simple_strtoul(argv[6], NULL, 16);
 787        else
 788                pos = 0;
 789
 790        time = get_timer(0);
 791        ret = fs_write(filename, addr, pos, bytes, &len);
 792        time = get_timer(time);
 793        if (ret < 0)
 794                return 1;
 795
 796        printf("%llu bytes written in %lu ms", len, time);
 797        if (time > 0) {
 798                puts(" (");
 799                print_size(div_u64(len, time) * 1000, "/s");
 800                puts(")");
 801        }
 802        puts("\n");
 803
 804        return 0;
 805}
 806
 807int do_fs_uuid(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
 808                int fstype)
 809{
 810        int ret;
 811        char uuid[37];
 812        memset(uuid, 0, sizeof(uuid));
 813
 814        if (argc < 3 || argc > 4)
 815                return CMD_RET_USAGE;
 816
 817        if (fs_set_blk_dev(argv[1], argv[2], fstype))
 818                return 1;
 819
 820        ret = fs_uuid(uuid);
 821        if (ret)
 822                return CMD_RET_FAILURE;
 823
 824        if (argc == 4)
 825                env_set(argv[3], uuid);
 826        else
 827                printf("%s\n", uuid);
 828
 829        return CMD_RET_SUCCESS;
 830}
 831
 832int do_fs_type(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 833{
 834        struct fstype_info *info;
 835
 836        if (argc < 3 || argc > 4)
 837                return CMD_RET_USAGE;
 838
 839        if (fs_set_blk_dev(argv[1], argv[2], FS_TYPE_ANY))
 840                return 1;
 841
 842        info = fs_get_info(fs_type);
 843
 844        if (argc == 4)
 845                env_set(argv[3], info->name);
 846        else
 847                printf("%s\n", info->name);
 848
 849        fs_close();
 850
 851        return CMD_RET_SUCCESS;
 852}
 853
 854int do_rm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
 855          int fstype)
 856{
 857        if (argc != 4)
 858                return CMD_RET_USAGE;
 859
 860        if (fs_set_blk_dev(argv[1], argv[2], fstype))
 861                return 1;
 862
 863        if (fs_unlink(argv[3]))
 864                return 1;
 865
 866        return 0;
 867}
 868
 869int do_mkdir(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
 870             int fstype)
 871{
 872        int ret;
 873
 874        if (argc != 4)
 875                return CMD_RET_USAGE;
 876
 877        if (fs_set_blk_dev(argv[1], argv[2], fstype))
 878                return 1;
 879
 880        ret = fs_mkdir(argv[3]);
 881        if (ret) {
 882                printf("** Unable to create a directory \"%s\" **\n", argv[3]);
 883                return 1;
 884        }
 885
 886        return 0;
 887}
 888
 889int do_ln(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
 890          int fstype)
 891{
 892        if (argc != 5)
 893                return CMD_RET_USAGE;
 894
 895        if (fs_set_blk_dev(argv[1], argv[2], fstype))
 896                return 1;
 897
 898        if (fs_ln(argv[3], argv[4]))
 899                return 1;
 900
 901        return 0;
 902}
 903