Home | History | Annotate | Download | only in fs
      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 
     21 DECLARE_GLOBAL_DATA_PTR;
     22 
     23 static struct blk_desc *fs_dev_desc;
     24 static int fs_dev_part;
     25 static disk_partition_t fs_partition;
     26 static int fs_type = FS_TYPE_ANY;
     27 
     28 static inline int fs_probe_unsupported(struct blk_desc *fs_dev_desc,
     29 				      disk_partition_t *fs_partition)
     30 {
     31 	printf("** Unrecognized filesystem type **\n");
     32 	return -1;
     33 }
     34 
     35 static inline int fs_ls_unsupported(const char *dirname)
     36 {
     37 	return -1;
     38 }
     39 
     40 /* generic implementation of ls in terms of opendir/readdir/closedir */
     41 __maybe_unused
     42 static int fs_ls_generic(const char *dirname)
     43 {
     44 	struct fs_dir_stream *dirs;
     45 	struct fs_dirent *dent;
     46 	int nfiles = 0, ndirs = 0;
     47 
     48 	dirs = fs_opendir(dirname);
     49 	if (!dirs)
     50 		return -errno;
     51 
     52 	while ((dent = fs_readdir(dirs))) {
     53 		if (dent->type == FS_DT_DIR) {
     54 			printf("            %s/\n", dent->name);
     55 			ndirs++;
     56 		} else {
     57 			printf(" %8lld   %s\n", dent->size, dent->name);
     58 			nfiles++;
     59 		}
     60 	}
     61 
     62 	fs_closedir(dirs);
     63 
     64 	printf("\n%d file(s), %d dir(s)\n\n", nfiles, ndirs);
     65 
     66 	return 0;
     67 }
     68 
     69 static inline int fs_exists_unsupported(const char *filename)
     70 {
     71 	return 0;
     72 }
     73 
     74 static inline int fs_size_unsupported(const char *filename, loff_t *size)
     75 {
     76 	return -1;
     77 }
     78 
     79 static inline int fs_read_unsupported(const char *filename, void *buf,
     80 				      loff_t offset, loff_t len,
     81 				      loff_t *actread)
     82 {
     83 	return -1;
     84 }
     85 
     86 static inline int fs_write_unsupported(const char *filename, void *buf,
     87 				      loff_t offset, loff_t len,
     88 				      loff_t *actwrite)
     89 {
     90 	return -1;
     91 }
     92 
     93 static inline void fs_close_unsupported(void)
     94 {
     95 }
     96 
     97 static inline int fs_uuid_unsupported(char *uuid_str)
     98 {
     99 	return -1;
    100 }
    101 
    102 static inline int fs_opendir_unsupported(const char *filename,
    103 					 struct fs_dir_stream **dirs)
    104 {
    105 	return -EACCES;
    106 }
    107 
    108 struct fstype_info {
    109 	int fstype;
    110 	char *name;
    111 	/*
    112 	 * Is it legal to pass NULL as .probe()'s  fs_dev_desc parameter? This
    113 	 * should be false in most cases. For "virtual" filesystems which
    114 	 * aren't based on a U-Boot block device (e.g. sandbox), this can be
    115 	 * set to true. This should also be true for the dumm entry at the end
    116 	 * of fstypes[], since that is essentially a "virtual" (non-existent)
    117 	 * filesystem.
    118 	 */
    119 	bool null_dev_desc_ok;
    120 	int (*probe)(struct blk_desc *fs_dev_desc,
    121 		     disk_partition_t *fs_partition);
    122 	int (*ls)(const char *dirname);
    123 	int (*exists)(const char *filename);
    124 	int (*size)(const char *filename, loff_t *size);
    125 	int (*read)(const char *filename, void *buf, loff_t offset,
    126 		    loff_t len, loff_t *actread);
    127 	int (*write)(const char *filename, void *buf, loff_t offset,
    128 		     loff_t len, loff_t *actwrite);
    129 	void (*close)(void);
    130 	int (*uuid)(char *uuid_str);
    131 	/*
    132 	 * Open a directory stream.  On success return 0 and directory
    133 	 * stream pointer via 'dirsp'.  On error, return -errno.  See
    134 	 * fs_opendir().
    135 	 */
    136 	int (*opendir)(const char *filename, struct fs_dir_stream **dirsp);
    137 	/*
    138 	 * Read next entry from directory stream.  On success return 0
    139 	 * and directory entry pointer via 'dentp'.  On error return
    140 	 * -errno.  See fs_readdir().
    141 	 */
    142 	int (*readdir)(struct fs_dir_stream *dirs, struct fs_dirent **dentp);
    143 	/* see fs_closedir() */
    144 	void (*closedir)(struct fs_dir_stream *dirs);
    145 };
    146 
    147 static struct fstype_info fstypes[] = {
    148 #ifdef CONFIG_FS_FAT
    149 	{
    150 		.fstype = FS_TYPE_FAT,
    151 		.name = "fat",
    152 		.null_dev_desc_ok = false,
    153 		.probe = fat_set_blk_dev,
    154 		.close = fat_close,
    155 		.ls = fs_ls_generic,
    156 		.exists = fat_exists,
    157 		.size = fat_size,
    158 		.read = fat_read_file,
    159 #ifdef CONFIG_FAT_WRITE
    160 		.write = file_fat_write,
    161 #else
    162 		.write = fs_write_unsupported,
    163 #endif
    164 		.uuid = fs_uuid_unsupported,
    165 		.opendir = fat_opendir,
    166 		.readdir = fat_readdir,
    167 		.closedir = fat_closedir,
    168 	},
    169 #endif
    170 #ifdef CONFIG_FS_EXT4
    171 	{
    172 		.fstype = FS_TYPE_EXT,
    173 		.name = "ext4",
    174 		.null_dev_desc_ok = false,
    175 		.probe = ext4fs_probe,
    176 		.close = ext4fs_close,
    177 		.ls = ext4fs_ls,
    178 		.exists = ext4fs_exists,
    179 		.size = ext4fs_size,
    180 		.read = ext4_read_file,
    181 #ifdef CONFIG_CMD_EXT4_WRITE
    182 		.write = ext4_write_file,
    183 #else
    184 		.write = fs_write_unsupported,
    185 #endif
    186 		.uuid = ext4fs_uuid,
    187 		.opendir = fs_opendir_unsupported,
    188 	},
    189 #endif
    190 #ifdef CONFIG_SANDBOX
    191 	{
    192 		.fstype = FS_TYPE_SANDBOX,
    193 		.name = "sandbox",
    194 		.null_dev_desc_ok = true,
    195 		.probe = sandbox_fs_set_blk_dev,
    196 		.close = sandbox_fs_close,
    197 		.ls = sandbox_fs_ls,
    198 		.exists = sandbox_fs_exists,
    199 		.size = sandbox_fs_size,
    200 		.read = fs_read_sandbox,
    201 		.write = fs_write_sandbox,
    202 		.uuid = fs_uuid_unsupported,
    203 		.opendir = fs_opendir_unsupported,
    204 	},
    205 #endif
    206 #ifdef CONFIG_CMD_UBIFS
    207 	{
    208 		.fstype = FS_TYPE_UBIFS,
    209 		.name = "ubifs",
    210 		.null_dev_desc_ok = true,
    211 		.probe = ubifs_set_blk_dev,
    212 		.close = ubifs_close,
    213 		.ls = ubifs_ls,
    214 		.exists = ubifs_exists,
    215 		.size = ubifs_size,
    216 		.read = ubifs_read,
    217 		.write = fs_write_unsupported,
    218 		.uuid = fs_uuid_unsupported,
    219 		.opendir = fs_opendir_unsupported,
    220 	},
    221 #endif
    222 #ifdef CONFIG_FS_BTRFS
    223 	{
    224 		.fstype = FS_TYPE_BTRFS,
    225 		.name = "btrfs",
    226 		.null_dev_desc_ok = false,
    227 		.probe = btrfs_probe,
    228 		.close = btrfs_close,
    229 		.ls = btrfs_ls,
    230 		.exists = btrfs_exists,
    231 		.size = btrfs_size,
    232 		.read = btrfs_read,
    233 		.write = fs_write_unsupported,
    234 		.uuid = btrfs_uuid,
    235 		.opendir = fs_opendir_unsupported,
    236 	},
    237 #endif
    238 	{
    239 		.fstype = FS_TYPE_ANY,
    240 		.name = "unsupported",
    241 		.null_dev_desc_ok = true,
    242 		.probe = fs_probe_unsupported,
    243 		.close = fs_close_unsupported,
    244 		.ls = fs_ls_unsupported,
    245 		.exists = fs_exists_unsupported,
    246 		.size = fs_size_unsupported,
    247 		.read = fs_read_unsupported,
    248 		.write = fs_write_unsupported,
    249 		.uuid = fs_uuid_unsupported,
    250 		.opendir = fs_opendir_unsupported,
    251 	},
    252 };
    253 
    254 static struct fstype_info *fs_get_info(int fstype)
    255 {
    256 	struct fstype_info *info;
    257 	int i;
    258 
    259 	for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes) - 1; i++, info++) {
    260 		if (fstype == info->fstype)
    261 			return info;
    262 	}
    263 
    264 	/* Return the 'unsupported' sentinel */
    265 	return info;
    266 }
    267 
    268 /**
    269  * fs_get_type_name() - Get type of current filesystem
    270  *
    271  * Return: Pointer to filesystem name
    272  *
    273  * Returns a string describing the current filesystem, or the sentinel
    274  * "unsupported" for any unrecognised filesystem.
    275  */
    276 const char *fs_get_type_name(void)
    277 {
    278 	return fs_get_info(fs_type)->name;
    279 }
    280 
    281 int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
    282 {
    283 	struct fstype_info *info;
    284 	int part, i;
    285 #ifdef CONFIG_NEEDS_MANUAL_RELOC
    286 	static int relocated;
    287 
    288 	if (!relocated) {
    289 		for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes);
    290 				i++, info++) {
    291 			info->name += gd->reloc_off;
    292 			info->probe += gd->reloc_off;
    293 			info->close += gd->reloc_off;
    294 			info->ls += gd->reloc_off;
    295 			info->read += gd->reloc_off;
    296 			info->write += gd->reloc_off;
    297 		}
    298 		relocated = 1;
    299 	}
    300 #endif
    301 
    302 	part = blk_get_device_part_str(ifname, dev_part_str, &fs_dev_desc,
    303 					&fs_partition, 1);
    304 	if (part < 0)
    305 		return -1;
    306 
    307 	for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
    308 		if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY &&
    309 				fstype != info->fstype)
    310 			continue;
    311 
    312 		if (!fs_dev_desc && !info->null_dev_desc_ok)
    313 			continue;
    314 
    315 		if (!info->probe(fs_dev_desc, &fs_partition)) {
    316 			fs_type = info->fstype;
    317 			fs_dev_part = part;
    318 			return 0;
    319 		}
    320 	}
    321 
    322 	return -1;
    323 }
    324 
    325 /* set current blk device w/ blk_desc + partition # */
    326 int fs_set_blk_dev_with_part(struct blk_desc *desc, int part)
    327 {
    328 	struct fstype_info *info;
    329 	int ret, i;
    330 
    331 	if (part >= 1)
    332 		ret = part_get_info(desc, part, &fs_partition);
    333 	else
    334 		ret = part_get_info_whole_disk(desc, &fs_partition);
    335 	if (ret)
    336 		return ret;
    337 	fs_dev_desc = desc;
    338 
    339 	for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
    340 		if (!info->probe(fs_dev_desc, &fs_partition)) {
    341 			fs_type = info->fstype;
    342 			return 0;
    343 		}
    344 	}
    345 
    346 	return -1;
    347 }
    348 
    349 static void fs_close(void)
    350 {
    351 	struct fstype_info *info = fs_get_info(fs_type);
    352 
    353 	info->close();
    354 
    355 	fs_type = FS_TYPE_ANY;
    356 }
    357 
    358 int fs_uuid(char *uuid_str)
    359 {
    360 	struct fstype_info *info = fs_get_info(fs_type);
    361 
    362 	return info->uuid(uuid_str);
    363 }
    364 
    365 int fs_ls(const char *dirname)
    366 {
    367 	int ret;
    368 
    369 	struct fstype_info *info = fs_get_info(fs_type);
    370 
    371 	ret = info->ls(dirname);
    372 
    373 	fs_type = FS_TYPE_ANY;
    374 	fs_close();
    375 
    376 	return ret;
    377 }
    378 
    379 int fs_exists(const char *filename)
    380 {
    381 	int ret;
    382 
    383 	struct fstype_info *info = fs_get_info(fs_type);
    384 
    385 	ret = info->exists(filename);
    386 
    387 	fs_close();
    388 
    389 	return ret;
    390 }
    391 
    392 int fs_size(const char *filename, loff_t *size)
    393 {
    394 	int ret;
    395 
    396 	struct fstype_info *info = fs_get_info(fs_type);
    397 
    398 	ret = info->size(filename, size);
    399 
    400 	fs_close();
    401 
    402 	return ret;
    403 }
    404 
    405 int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len,
    406 	    loff_t *actread)
    407 {
    408 	struct fstype_info *info = fs_get_info(fs_type);
    409 	void *buf;
    410 	int ret;
    411 
    412 	/*
    413 	 * We don't actually know how many bytes are being read, since len==0
    414 	 * means read the whole file.
    415 	 */
    416 	buf = map_sysmem(addr, len);
    417 	ret = info->read(filename, buf, offset, len, actread);
    418 	unmap_sysmem(buf);
    419 
    420 	/* If we requested a specific number of bytes, check we got it */
    421 	if (ret == 0 && len && *actread != len)
    422 		debug("** %s shorter than offset + len **\n", filename);
    423 	fs_close();
    424 
    425 	return ret;
    426 }
    427 
    428 int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
    429 	     loff_t *actwrite)
    430 {
    431 	struct fstype_info *info = fs_get_info(fs_type);
    432 	void *buf;
    433 	int ret;
    434 
    435 	buf = map_sysmem(addr, len);
    436 	ret = info->write(filename, buf, offset, len, actwrite);
    437 	unmap_sysmem(buf);
    438 
    439 	if (ret < 0 && len != *actwrite) {
    440 		printf("** Unable to write file %s **\n", filename);
    441 		ret = -1;
    442 	}
    443 	fs_close();
    444 
    445 	return ret;
    446 }
    447 
    448 struct fs_dir_stream *fs_opendir(const char *filename)
    449 {
    450 	struct fstype_info *info = fs_get_info(fs_type);
    451 	struct fs_dir_stream *dirs = NULL;
    452 	int ret;
    453 
    454 	ret = info->opendir(filename, &dirs);
    455 	fs_close();
    456 	if (ret) {
    457 		errno = -ret;
    458 		return NULL;
    459 	}
    460 
    461 	dirs->desc = fs_dev_desc;
    462 	dirs->part = fs_dev_part;
    463 
    464 	return dirs;
    465 }
    466 
    467 struct fs_dirent *fs_readdir(struct fs_dir_stream *dirs)
    468 {
    469 	struct fstype_info *info;
    470 	struct fs_dirent *dirent;
    471 	int ret;
    472 
    473 	fs_set_blk_dev_with_part(dirs->desc, dirs->part);
    474 	info = fs_get_info(fs_type);
    475 
    476 	ret = info->readdir(dirs, &dirent);
    477 	fs_close();
    478 	if (ret) {
    479 		errno = -ret;
    480 		return NULL;
    481 	}
    482 
    483 	return dirent;
    484 }
    485 
    486 void fs_closedir(struct fs_dir_stream *dirs)
    487 {
    488 	struct fstype_info *info;
    489 
    490 	if (!dirs)
    491 		return;
    492 
    493 	fs_set_blk_dev_with_part(dirs->desc, dirs->part);
    494 	info = fs_get_info(fs_type);
    495 
    496 	info->closedir(dirs);
    497 	fs_close();
    498 }
    499 
    500 
    501 int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
    502 		int fstype)
    503 {
    504 	loff_t size;
    505 
    506 	if (argc != 4)
    507 		return CMD_RET_USAGE;
    508 
    509 	if (fs_set_blk_dev(argv[1], argv[2], fstype))
    510 		return 1;
    511 
    512 	if (fs_size(argv[3], &size) < 0)
    513 		return CMD_RET_FAILURE;
    514 
    515 	env_set_hex("filesize", size);
    516 
    517 	return 0;
    518 }
    519 
    520 int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
    521 		int fstype)
    522 {
    523 	unsigned long addr;
    524 	const char *addr_str;
    525 	const char *filename;
    526 	loff_t bytes;
    527 	loff_t pos;
    528 	loff_t len_read;
    529 	int ret;
    530 	unsigned long time;
    531 	char *ep;
    532 
    533 	if (argc < 2)
    534 		return CMD_RET_USAGE;
    535 	if (argc > 7)
    536 		return CMD_RET_USAGE;
    537 
    538 	if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
    539 		return 1;
    540 
    541 	if (argc >= 4) {
    542 		addr = simple_strtoul(argv[3], &ep, 16);
    543 		if (ep == argv[3] || *ep != '\0')
    544 			return CMD_RET_USAGE;
    545 	} else {
    546 		addr_str = env_get("loadaddr");
    547 		if (addr_str != NULL)
    548 			addr = simple_strtoul(addr_str, NULL, 16);
    549 		else
    550 			addr = CONFIG_SYS_LOAD_ADDR;
    551 	}
    552 	if (argc >= 5) {
    553 		filename = argv[4];
    554 	} else {
    555 		filename = env_get("bootfile");
    556 		if (!filename) {
    557 			puts("** No boot file defined **\n");
    558 			return 1;
    559 		}
    560 	}
    561 	if (argc >= 6)
    562 		bytes = simple_strtoul(argv[5], NULL, 16);
    563 	else
    564 		bytes = 0;
    565 	if (argc >= 7)
    566 		pos = simple_strtoul(argv[6], NULL, 16);
    567 	else
    568 		pos = 0;
    569 
    570 	time = get_timer(0);
    571 	ret = fs_read(filename, addr, pos, bytes, &len_read);
    572 	time = get_timer(time);
    573 	if (ret < 0)
    574 		return 1;
    575 
    576 	printf("%llu bytes read in %lu ms", len_read, time);
    577 	if (time > 0) {
    578 		puts(" (");
    579 		print_size(div_u64(len_read, time) * 1000, "/s");
    580 		puts(")");
    581 	}
    582 	puts("\n");
    583 
    584 	env_set_hex("fileaddr", addr);
    585 	env_set_hex("filesize", len_read);
    586 
    587 	return 0;
    588 }
    589 
    590 int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
    591 	int fstype)
    592 {
    593 	if (argc < 2)
    594 		return CMD_RET_USAGE;
    595 	if (argc > 4)
    596 		return CMD_RET_USAGE;
    597 
    598 	if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
    599 		return 1;
    600 
    601 	if (fs_ls(argc >= 4 ? argv[3] : "/"))
    602 		return 1;
    603 
    604 	return 0;
    605 }
    606 
    607 int file_exists(const char *dev_type, const char *dev_part, const char *file,
    608 		int fstype)
    609 {
    610 	if (fs_set_blk_dev(dev_type, dev_part, fstype))
    611 		return 0;
    612 
    613 	return fs_exists(file);
    614 }
    615 
    616 int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
    617 		int fstype)
    618 {
    619 	unsigned long addr;
    620 	const char *filename;
    621 	loff_t bytes;
    622 	loff_t pos;
    623 	loff_t len;
    624 	int ret;
    625 	unsigned long time;
    626 
    627 	if (argc < 6 || argc > 7)
    628 		return CMD_RET_USAGE;
    629 
    630 	if (fs_set_blk_dev(argv[1], argv[2], fstype))
    631 		return 1;
    632 
    633 	addr = simple_strtoul(argv[3], NULL, 16);
    634 	filename = argv[4];
    635 	bytes = simple_strtoul(argv[5], NULL, 16);
    636 	if (argc >= 7)
    637 		pos = simple_strtoul(argv[6], NULL, 16);
    638 	else
    639 		pos = 0;
    640 
    641 	time = get_timer(0);
    642 	ret = fs_write(filename, addr, pos, bytes, &len);
    643 	time = get_timer(time);
    644 	if (ret < 0)
    645 		return 1;
    646 
    647 	printf("%llu bytes written in %lu ms", len, time);
    648 	if (time > 0) {
    649 		puts(" (");
    650 		print_size(div_u64(len, time) * 1000, "/s");
    651 		puts(")");
    652 	}
    653 	puts("\n");
    654 
    655 	return 0;
    656 }
    657 
    658 int do_fs_uuid(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
    659 		int fstype)
    660 {
    661 	int ret;
    662 	char uuid[37];
    663 	memset(uuid, 0, sizeof(uuid));
    664 
    665 	if (argc < 3 || argc > 4)
    666 		return CMD_RET_USAGE;
    667 
    668 	if (fs_set_blk_dev(argv[1], argv[2], fstype))
    669 		return 1;
    670 
    671 	ret = fs_uuid(uuid);
    672 	if (ret)
    673 		return CMD_RET_FAILURE;
    674 
    675 	if (argc == 4)
    676 		env_set(argv[3], uuid);
    677 	else
    678 		printf("%s\n", uuid);
    679 
    680 	return CMD_RET_SUCCESS;
    681 }
    682 
    683 int do_fs_type(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
    684 {
    685 	struct fstype_info *info;
    686 
    687 	if (argc < 3 || argc > 4)
    688 		return CMD_RET_USAGE;
    689 
    690 	if (fs_set_blk_dev(argv[1], argv[2], FS_TYPE_ANY))
    691 		return 1;
    692 
    693 	info = fs_get_info(fs_type);
    694 
    695 	if (argc == 4)
    696 		env_set(argv[3], info->name);
    697 	else
    698 		printf("%s\n", info->name);
    699 
    700 	return CMD_RET_SUCCESS;
    701 }
    702 
    703