xref: /openbmc/u-boot/fs/fs.c (revision 9b643e312d528f291966c1f30b0d90bf3b1d43dc)
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  	},
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  int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
269  {
270  	struct fstype_info *info;
271  	int part, i;
272  #ifdef CONFIG_NEEDS_MANUAL_RELOC
273  	static int relocated;
274  
275  	if (!relocated) {
276  		for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes);
277  				i++, info++) {
278  			info->name += gd->reloc_off;
279  			info->probe += gd->reloc_off;
280  			info->close += gd->reloc_off;
281  			info->ls += gd->reloc_off;
282  			info->read += gd->reloc_off;
283  			info->write += gd->reloc_off;
284  		}
285  		relocated = 1;
286  	}
287  #endif
288  
289  	part = blk_get_device_part_str(ifname, dev_part_str, &fs_dev_desc,
290  					&fs_partition, 1);
291  	if (part < 0)
292  		return -1;
293  
294  	for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
295  		if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY &&
296  				fstype != info->fstype)
297  			continue;
298  
299  		if (!fs_dev_desc && !info->null_dev_desc_ok)
300  			continue;
301  
302  		if (!info->probe(fs_dev_desc, &fs_partition)) {
303  			fs_type = info->fstype;
304  			fs_dev_part = part;
305  			return 0;
306  		}
307  	}
308  
309  	return -1;
310  }
311  
312  /* set current blk device w/ blk_desc + partition # */
313  int fs_set_blk_dev_with_part(struct blk_desc *desc, int part)
314  {
315  	struct fstype_info *info;
316  	int ret, i;
317  
318  	if (part >= 1)
319  		ret = part_get_info(desc, part, &fs_partition);
320  	else
321  		ret = part_get_info_whole_disk(desc, &fs_partition);
322  	if (ret)
323  		return ret;
324  	fs_dev_desc = desc;
325  
326  	for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
327  		if (!info->probe(fs_dev_desc, &fs_partition)) {
328  			fs_type = info->fstype;
329  			return 0;
330  		}
331  	}
332  
333  	return -1;
334  }
335  
336  static void fs_close(void)
337  {
338  	struct fstype_info *info = fs_get_info(fs_type);
339  
340  	info->close();
341  
342  	fs_type = FS_TYPE_ANY;
343  }
344  
345  int fs_uuid(char *uuid_str)
346  {
347  	struct fstype_info *info = fs_get_info(fs_type);
348  
349  	return info->uuid(uuid_str);
350  }
351  
352  int fs_ls(const char *dirname)
353  {
354  	int ret;
355  
356  	struct fstype_info *info = fs_get_info(fs_type);
357  
358  	ret = info->ls(dirname);
359  
360  	fs_type = FS_TYPE_ANY;
361  	fs_close();
362  
363  	return ret;
364  }
365  
366  int fs_exists(const char *filename)
367  {
368  	int ret;
369  
370  	struct fstype_info *info = fs_get_info(fs_type);
371  
372  	ret = info->exists(filename);
373  
374  	fs_close();
375  
376  	return ret;
377  }
378  
379  int fs_size(const char *filename, loff_t *size)
380  {
381  	int ret;
382  
383  	struct fstype_info *info = fs_get_info(fs_type);
384  
385  	ret = info->size(filename, size);
386  
387  	fs_close();
388  
389  	return ret;
390  }
391  
392  int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len,
393  	    loff_t *actread)
394  {
395  	struct fstype_info *info = fs_get_info(fs_type);
396  	void *buf;
397  	int ret;
398  
399  	/*
400  	 * We don't actually know how many bytes are being read, since len==0
401  	 * means read the whole file.
402  	 */
403  	buf = map_sysmem(addr, len);
404  	ret = info->read(filename, buf, offset, len, actread);
405  	unmap_sysmem(buf);
406  
407  	/* If we requested a specific number of bytes, check we got it */
408  	if (ret == 0 && len && *actread != len)
409  		printf("** %s shorter than offset + len **\n", filename);
410  	fs_close();
411  
412  	return ret;
413  }
414  
415  int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
416  	     loff_t *actwrite)
417  {
418  	struct fstype_info *info = fs_get_info(fs_type);
419  	void *buf;
420  	int ret;
421  
422  	buf = map_sysmem(addr, len);
423  	ret = info->write(filename, buf, offset, len, actwrite);
424  	unmap_sysmem(buf);
425  
426  	if (ret < 0 && len != *actwrite) {
427  		printf("** Unable to write file %s **\n", filename);
428  		ret = -1;
429  	}
430  	fs_close();
431  
432  	return ret;
433  }
434  
435  struct fs_dir_stream *fs_opendir(const char *filename)
436  {
437  	struct fstype_info *info = fs_get_info(fs_type);
438  	struct fs_dir_stream *dirs = NULL;
439  	int ret;
440  
441  	ret = info->opendir(filename, &dirs);
442  	fs_close();
443  	if (ret) {
444  		errno = -ret;
445  		return NULL;
446  	}
447  
448  	dirs->desc = fs_dev_desc;
449  	dirs->part = fs_dev_part;
450  
451  	return dirs;
452  }
453  
454  struct fs_dirent *fs_readdir(struct fs_dir_stream *dirs)
455  {
456  	struct fstype_info *info;
457  	struct fs_dirent *dirent;
458  	int ret;
459  
460  	fs_set_blk_dev_with_part(dirs->desc, dirs->part);
461  	info = fs_get_info(fs_type);
462  
463  	ret = info->readdir(dirs, &dirent);
464  	fs_close();
465  	if (ret) {
466  		errno = -ret;
467  		return NULL;
468  	}
469  
470  	return dirent;
471  }
472  
473  void fs_closedir(struct fs_dir_stream *dirs)
474  {
475  	struct fstype_info *info;
476  
477  	if (!dirs)
478  		return;
479  
480  	fs_set_blk_dev_with_part(dirs->desc, dirs->part);
481  	info = fs_get_info(fs_type);
482  
483  	info->closedir(dirs);
484  	fs_close();
485  }
486  
487  
488  int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
489  		int fstype)
490  {
491  	loff_t size;
492  
493  	if (argc != 4)
494  		return CMD_RET_USAGE;
495  
496  	if (fs_set_blk_dev(argv[1], argv[2], fstype))
497  		return 1;
498  
499  	if (fs_size(argv[3], &size) < 0)
500  		return CMD_RET_FAILURE;
501  
502  	env_set_hex("filesize", size);
503  
504  	return 0;
505  }
506  
507  int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
508  		int fstype)
509  {
510  	unsigned long addr;
511  	const char *addr_str;
512  	const char *filename;
513  	loff_t bytes;
514  	loff_t pos;
515  	loff_t len_read;
516  	int ret;
517  	unsigned long time;
518  	char *ep;
519  
520  	if (argc < 2)
521  		return CMD_RET_USAGE;
522  	if (argc > 7)
523  		return CMD_RET_USAGE;
524  
525  	if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
526  		return 1;
527  
528  	if (argc >= 4) {
529  		addr = simple_strtoul(argv[3], &ep, 16);
530  		if (ep == argv[3] || *ep != '\0')
531  			return CMD_RET_USAGE;
532  	} else {
533  		addr_str = env_get("loadaddr");
534  		if (addr_str != NULL)
535  			addr = simple_strtoul(addr_str, NULL, 16);
536  		else
537  			addr = CONFIG_SYS_LOAD_ADDR;
538  	}
539  	if (argc >= 5) {
540  		filename = argv[4];
541  	} else {
542  		filename = env_get("bootfile");
543  		if (!filename) {
544  			puts("** No boot file defined **\n");
545  			return 1;
546  		}
547  	}
548  	if (argc >= 6)
549  		bytes = simple_strtoul(argv[5], NULL, 16);
550  	else
551  		bytes = 0;
552  	if (argc >= 7)
553  		pos = simple_strtoul(argv[6], NULL, 16);
554  	else
555  		pos = 0;
556  
557  	time = get_timer(0);
558  	ret = fs_read(filename, addr, pos, bytes, &len_read);
559  	time = get_timer(time);
560  	if (ret < 0)
561  		return 1;
562  
563  	printf("%llu bytes read in %lu ms", len_read, time);
564  	if (time > 0) {
565  		puts(" (");
566  		print_size(div_u64(len_read, time) * 1000, "/s");
567  		puts(")");
568  	}
569  	puts("\n");
570  
571  	env_set_hex("fileaddr", addr);
572  	env_set_hex("filesize", len_read);
573  
574  	return 0;
575  }
576  
577  int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
578  	int fstype)
579  {
580  	if (argc < 2)
581  		return CMD_RET_USAGE;
582  	if (argc > 4)
583  		return CMD_RET_USAGE;
584  
585  	if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
586  		return 1;
587  
588  	if (fs_ls(argc >= 4 ? argv[3] : "/"))
589  		return 1;
590  
591  	return 0;
592  }
593  
594  int file_exists(const char *dev_type, const char *dev_part, const char *file,
595  		int fstype)
596  {
597  	if (fs_set_blk_dev(dev_type, dev_part, fstype))
598  		return 0;
599  
600  	return fs_exists(file);
601  }
602  
603  int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
604  		int fstype)
605  {
606  	unsigned long addr;
607  	const char *filename;
608  	loff_t bytes;
609  	loff_t pos;
610  	loff_t len;
611  	int ret;
612  	unsigned long time;
613  
614  	if (argc < 6 || argc > 7)
615  		return CMD_RET_USAGE;
616  
617  	if (fs_set_blk_dev(argv[1], argv[2], fstype))
618  		return 1;
619  
620  	addr = simple_strtoul(argv[3], NULL, 16);
621  	filename = argv[4];
622  	bytes = simple_strtoul(argv[5], NULL, 16);
623  	if (argc >= 7)
624  		pos = simple_strtoul(argv[6], NULL, 16);
625  	else
626  		pos = 0;
627  
628  	time = get_timer(0);
629  	ret = fs_write(filename, addr, pos, bytes, &len);
630  	time = get_timer(time);
631  	if (ret < 0)
632  		return 1;
633  
634  	printf("%llu bytes written in %lu ms", len, time);
635  	if (time > 0) {
636  		puts(" (");
637  		print_size(div_u64(len, time) * 1000, "/s");
638  		puts(")");
639  	}
640  	puts("\n");
641  
642  	return 0;
643  }
644  
645  int do_fs_uuid(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
646  		int fstype)
647  {
648  	int ret;
649  	char uuid[37];
650  	memset(uuid, 0, sizeof(uuid));
651  
652  	if (argc < 3 || argc > 4)
653  		return CMD_RET_USAGE;
654  
655  	if (fs_set_blk_dev(argv[1], argv[2], fstype))
656  		return 1;
657  
658  	ret = fs_uuid(uuid);
659  	if (ret)
660  		return CMD_RET_FAILURE;
661  
662  	if (argc == 4)
663  		env_set(argv[3], uuid);
664  	else
665  		printf("%s\n", uuid);
666  
667  	return CMD_RET_SUCCESS;
668  }
669  
670  int do_fs_type(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
671  {
672  	struct fstype_info *info;
673  
674  	if (argc < 3 || argc > 4)
675  		return CMD_RET_USAGE;
676  
677  	if (fs_set_blk_dev(argv[1], argv[2], FS_TYPE_ANY))
678  		return 1;
679  
680  	info = fs_get_info(fs_type);
681  
682  	if (argc == 4)
683  		env_set(argv[3], info->name);
684  	else
685  		printf("%s\n", info->name);
686  
687  	return CMD_RET_SUCCESS;
688  }
689  
690