]> git.ipfire.org Git - people/ms/u-boot.git/blame - fs/fs.c
env: Rename common functions related to setenv()
[people/ms/u-boot.git] / fs / fs.c
CommitLineData
045fa1e1
SW
1/*
2 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
3 *
5b8031cc 4 * SPDX-License-Identifier: GPL-2.0
045fa1e1
SW
5 */
6
7#include <config.h>
59e890ef 8#include <errno.h>
045fa1e1 9#include <common.h>
0eb25b61 10#include <mapmem.h>
045fa1e1
SW
11#include <part.h>
12#include <ext4fs.h>
13#include <fat.h>
14#include <fs.h>
92ccc96b 15#include <sandboxfs.h>
251cee0d 16#include <ubifs_uboot.h>
117e0507 17#include <asm/io.h>
9e374e7b
TR
18#include <div64.h>
19#include <linux/math64.h>
045fa1e1 20
a1b231ce
SW
21DECLARE_GLOBAL_DATA_PTR;
22
4101f687 23static struct blk_desc *fs_dev_desc;
045fa1e1
SW
24static disk_partition_t fs_partition;
25static int fs_type = FS_TYPE_ANY;
26
4101f687 27static inline int fs_probe_unsupported(struct blk_desc *fs_dev_desc,
2ded0d47 28 disk_partition_t *fs_partition)
436e2b73
SG
29{
30 printf("** Unrecognized filesystem type **\n");
31 return -1;
32}
33
045fa1e1
SW
34static inline int fs_ls_unsupported(const char *dirname)
35{
045fa1e1
SW
36 return -1;
37}
38
6152916a
SW
39static inline int fs_exists_unsupported(const char *filename)
40{
41 return 0;
42}
43
d455d878 44static inline int fs_size_unsupported(const char *filename, loff_t *size)
cf659819
SW
45{
46 return -1;
47}
48
117e0507 49static inline int fs_read_unsupported(const char *filename, void *buf,
d455d878
SR
50 loff_t offset, loff_t len,
51 loff_t *actread)
045fa1e1 52{
045fa1e1
SW
53 return -1;
54}
55
a8f6ab52 56static inline int fs_write_unsupported(const char *filename, void *buf,
d455d878
SR
57 loff_t offset, loff_t len,
58 loff_t *actwrite)
a8f6ab52
SG
59{
60 return -1;
61}
62
436e2b73
SG
63static inline void fs_close_unsupported(void)
64{
65}
66
59e890ef
CG
67static inline int fs_uuid_unsupported(char *uuid_str)
68{
69 return -1;
70}
71
436e2b73 72struct fstype_info {
045fa1e1 73 int fstype;
1a1ad8e0 74 char *name;
377202b5
SW
75 /*
76 * Is it legal to pass NULL as .probe()'s fs_dev_desc parameter? This
77 * should be false in most cases. For "virtual" filesystems which
78 * aren't based on a U-Boot block device (e.g. sandbox), this can be
79 * set to true. This should also be true for the dumm entry at the end
80 * of fstypes[], since that is essentially a "virtual" (non-existent)
81 * filesystem.
82 */
83 bool null_dev_desc_ok;
4101f687 84 int (*probe)(struct blk_desc *fs_dev_desc,
2ded0d47 85 disk_partition_t *fs_partition);
436e2b73 86 int (*ls)(const char *dirname);
6152916a 87 int (*exists)(const char *filename);
d455d878
SR
88 int (*size)(const char *filename, loff_t *size);
89 int (*read)(const char *filename, void *buf, loff_t offset,
90 loff_t len, loff_t *actread);
91 int (*write)(const char *filename, void *buf, loff_t offset,
92 loff_t len, loff_t *actwrite);
436e2b73 93 void (*close)(void);
59e890ef 94 int (*uuid)(char *uuid_str);
436e2b73
SG
95};
96
97static struct fstype_info fstypes[] = {
98#ifdef CONFIG_FS_FAT
045fa1e1
SW
99 {
100 .fstype = FS_TYPE_FAT,
1a1ad8e0 101 .name = "fat",
377202b5 102 .null_dev_desc_ok = false,
e6d52415
SG
103 .probe = fat_set_blk_dev,
104 .close = fat_close,
436e2b73 105 .ls = file_fat_ls,
b7b5f319 106 .exists = fat_exists,
cf659819 107 .size = fat_size,
e6d52415 108 .read = fat_read_file,
d455d878
SR
109#ifdef CONFIG_FAT_WRITE
110 .write = file_fat_write,
111#else
bd6fb31f 112 .write = fs_write_unsupported,
d455d878 113#endif
59e890ef 114 .uuid = fs_uuid_unsupported,
045fa1e1 115 },
436e2b73
SG
116#endif
117#ifdef CONFIG_FS_EXT4
045fa1e1
SW
118 {
119 .fstype = FS_TYPE_EXT,
1a1ad8e0 120 .name = "ext4",
377202b5 121 .null_dev_desc_ok = false,
e6d52415
SG
122 .probe = ext4fs_probe,
123 .close = ext4fs_close,
436e2b73 124 .ls = ext4fs_ls,
55af5c93 125 .exists = ext4fs_exists,
cf659819 126 .size = ext4fs_size,
e6d52415 127 .read = ext4_read_file,
d455d878
SR
128#ifdef CONFIG_CMD_EXT4_WRITE
129 .write = ext4_write_file,
130#else
bd6fb31f 131 .write = fs_write_unsupported,
d455d878 132#endif
59e890ef 133 .uuid = ext4fs_uuid,
436e2b73 134 },
92ccc96b
SG
135#endif
136#ifdef CONFIG_SANDBOX
137 {
138 .fstype = FS_TYPE_SANDBOX,
1a1ad8e0 139 .name = "sandbox",
377202b5 140 .null_dev_desc_ok = true,
92ccc96b
SG
141 .probe = sandbox_fs_set_blk_dev,
142 .close = sandbox_fs_close,
143 .ls = sandbox_fs_ls,
0a30aa1e 144 .exists = sandbox_fs_exists,
cf659819 145 .size = sandbox_fs_size,
92ccc96b 146 .read = fs_read_sandbox,
7eb2c8d5 147 .write = fs_write_sandbox,
59e890ef 148 .uuid = fs_uuid_unsupported,
92ccc96b 149 },
251cee0d
HG
150#endif
151#ifdef CONFIG_CMD_UBIFS
152 {
153 .fstype = FS_TYPE_UBIFS,
154 .name = "ubifs",
155 .null_dev_desc_ok = true,
156 .probe = ubifs_set_blk_dev,
157 .close = ubifs_close,
158 .ls = ubifs_ls,
159 .exists = ubifs_exists,
160 .size = ubifs_size,
161 .read = ubifs_read,
162 .write = fs_write_unsupported,
163 .uuid = fs_uuid_unsupported,
164 },
436e2b73
SG
165#endif
166 {
167 .fstype = FS_TYPE_ANY,
1a1ad8e0 168 .name = "unsupported",
377202b5 169 .null_dev_desc_ok = true,
436e2b73
SG
170 .probe = fs_probe_unsupported,
171 .close = fs_close_unsupported,
172 .ls = fs_ls_unsupported,
6152916a 173 .exists = fs_exists_unsupported,
cf659819 174 .size = fs_size_unsupported,
436e2b73 175 .read = fs_read_unsupported,
a8f6ab52 176 .write = fs_write_unsupported,
59e890ef 177 .uuid = fs_uuid_unsupported,
045fa1e1
SW
178 },
179};
180
c6f548d2
SG
181static struct fstype_info *fs_get_info(int fstype)
182{
183 struct fstype_info *info;
184 int i;
185
186 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes) - 1; i++, info++) {
187 if (fstype == info->fstype)
188 return info;
189 }
190
191 /* Return the 'unsupported' sentinel */
192 return info;
193}
194
045fa1e1
SW
195int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
196{
436e2b73 197 struct fstype_info *info;
045fa1e1 198 int part, i;
a1b231ce
SW
199#ifdef CONFIG_NEEDS_MANUAL_RELOC
200 static int relocated;
201
202 if (!relocated) {
436e2b73
SG
203 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes);
204 i++, info++) {
1a1ad8e0 205 info->name += gd->reloc_off;
436e2b73
SG
206 info->probe += gd->reloc_off;
207 info->close += gd->reloc_off;
208 info->ls += gd->reloc_off;
209 info->read += gd->reloc_off;
a8f6ab52 210 info->write += gd->reloc_off;
436e2b73 211 }
a1b231ce
SW
212 relocated = 1;
213 }
214#endif
045fa1e1 215
e35929e4 216 part = blk_get_device_part_str(ifname, dev_part_str, &fs_dev_desc,
045fa1e1
SW
217 &fs_partition, 1);
218 if (part < 0)
219 return -1;
220
436e2b73
SG
221 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
222 if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY &&
223 fstype != info->fstype)
045fa1e1
SW
224 continue;
225
377202b5
SW
226 if (!fs_dev_desc && !info->null_dev_desc_ok)
227 continue;
228
2ded0d47 229 if (!info->probe(fs_dev_desc, &fs_partition)) {
436e2b73 230 fs_type = info->fstype;
045fa1e1
SW
231 return 0;
232 }
233 }
234
045fa1e1
SW
235 return -1;
236}
237
238static void fs_close(void)
239{
c6f548d2 240 struct fstype_info *info = fs_get_info(fs_type);
045fa1e1 241
c6f548d2 242 info->close();
e6d52415 243
045fa1e1
SW
244 fs_type = FS_TYPE_ANY;
245}
246
59e890ef
CG
247int fs_uuid(char *uuid_str)
248{
249 struct fstype_info *info = fs_get_info(fs_type);
250
251 return info->uuid(uuid_str);
252}
253
045fa1e1
SW
254int fs_ls(const char *dirname)
255{
256 int ret;
257
c6f548d2
SG
258 struct fstype_info *info = fs_get_info(fs_type);
259
260 ret = info->ls(dirname);
045fa1e1 261
e6d52415 262 fs_type = FS_TYPE_ANY;
045fa1e1
SW
263 fs_close();
264
265 return ret;
266}
267
6152916a
SW
268int fs_exists(const char *filename)
269{
270 int ret;
271
272 struct fstype_info *info = fs_get_info(fs_type);
273
274 ret = info->exists(filename);
275
276 fs_close();
277
278 return ret;
279}
280
d455d878 281int fs_size(const char *filename, loff_t *size)
cf659819
SW
282{
283 int ret;
284
285 struct fstype_info *info = fs_get_info(fs_type);
286
d455d878 287 ret = info->size(filename, size);
cf659819
SW
288
289 fs_close();
290
291 return ret;
292}
293
d455d878
SR
294int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len,
295 loff_t *actread)
045fa1e1 296{
c6f548d2 297 struct fstype_info *info = fs_get_info(fs_type);
117e0507 298 void *buf;
045fa1e1
SW
299 int ret;
300
117e0507
SG
301 /*
302 * We don't actually know how many bytes are being read, since len==0
303 * means read the whole file.
304 */
305 buf = map_sysmem(addr, len);
d455d878 306 ret = info->read(filename, buf, offset, len, actread);
117e0507 307 unmap_sysmem(buf);
045fa1e1 308
c6f548d2 309 /* If we requested a specific number of bytes, check we got it */
7a3e70cf
MK
310 if (ret == 0 && len && *actread != len)
311 printf("** %s shorter than offset + len **\n", filename);
045fa1e1
SW
312 fs_close();
313
314 return ret;
315}
316
d455d878
SR
317int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
318 loff_t *actwrite)
a8f6ab52
SG
319{
320 struct fstype_info *info = fs_get_info(fs_type);
321 void *buf;
322 int ret;
323
a8f6ab52 324 buf = map_sysmem(addr, len);
d455d878 325 ret = info->write(filename, buf, offset, len, actwrite);
a8f6ab52
SG
326 unmap_sysmem(buf);
327
d455d878 328 if (ret < 0 && len != *actwrite) {
a8f6ab52
SG
329 printf("** Unable to write file %s **\n", filename);
330 ret = -1;
331 }
332 fs_close();
333
334 return ret;
335}
336
cf659819
SW
337int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
338 int fstype)
339{
d455d878 340 loff_t size;
cf659819
SW
341
342 if (argc != 4)
343 return CMD_RET_USAGE;
344
345 if (fs_set_blk_dev(argv[1], argv[2], fstype))
346 return 1;
347
d455d878 348 if (fs_size(argv[3], &size) < 0)
cf659819
SW
349 return CMD_RET_FAILURE;
350
018f5303 351 env_set_hex("filesize", size);
cf659819
SW
352
353 return 0;
354}
355
f9b55e22 356int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
b770e88a 357 int fstype)
045fa1e1
SW
358{
359 unsigned long addr;
360 const char *addr_str;
361 const char *filename;
d455d878
SR
362 loff_t bytes;
363 loff_t pos;
364 loff_t len_read;
365 int ret;
da1fd96c 366 unsigned long time;
949bbd7c 367 char *ep;
045fa1e1 368
e9b0f99e
SW
369 if (argc < 2)
370 return CMD_RET_USAGE;
371 if (argc > 7)
045fa1e1
SW
372 return CMD_RET_USAGE;
373
e9b0f99e 374 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
045fa1e1
SW
375 return 1;
376
377 if (argc >= 4) {
949bbd7c
PM
378 addr = simple_strtoul(argv[3], &ep, 16);
379 if (ep == argv[3] || *ep != '\0')
380 return CMD_RET_USAGE;
045fa1e1
SW
381 } else {
382 addr_str = getenv("loadaddr");
383 if (addr_str != NULL)
384 addr = simple_strtoul(addr_str, NULL, 16);
385 else
386 addr = CONFIG_SYS_LOAD_ADDR;
387 }
388 if (argc >= 5) {
389 filename = argv[4];
390 } else {
391 filename = getenv("bootfile");
392 if (!filename) {
393 puts("** No boot file defined **\n");
394 return 1;
395 }
396 }
397 if (argc >= 6)
b770e88a 398 bytes = simple_strtoul(argv[5], NULL, 16);
045fa1e1
SW
399 else
400 bytes = 0;
401 if (argc >= 7)
b770e88a 402 pos = simple_strtoul(argv[6], NULL, 16);
045fa1e1
SW
403 else
404 pos = 0;
405
da1fd96c 406 time = get_timer(0);
d455d878 407 ret = fs_read(filename, addr, pos, bytes, &len_read);
da1fd96c 408 time = get_timer(time);
d455d878 409 if (ret < 0)
045fa1e1
SW
410 return 1;
411
d455d878 412 printf("%llu bytes read in %lu ms", len_read, time);
da1fd96c
AB
413 if (time > 0) {
414 puts(" (");
9e374e7b 415 print_size(div_u64(len_read, time) * 1000, "/s");
da1fd96c
AB
416 puts(")");
417 }
418 puts("\n");
045fa1e1 419
018f5303
SG
420 env_set_hex("fileaddr", addr);
421 env_set_hex("filesize", len_read);
045fa1e1
SW
422
423 return 0;
424}
425
426int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
427 int fstype)
428{
429 if (argc < 2)
430 return CMD_RET_USAGE;
e9b0f99e
SW
431 if (argc > 4)
432 return CMD_RET_USAGE;
045fa1e1
SW
433
434 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
435 return 1;
436
e9b0f99e 437 if (fs_ls(argc >= 4 ? argv[3] : "/"))
045fa1e1
SW
438 return 1;
439
440 return 0;
441}
a8f6ab52 442
6152916a
SW
443int file_exists(const char *dev_type, const char *dev_part, const char *file,
444 int fstype)
445{
446 if (fs_set_blk_dev(dev_type, dev_part, fstype))
447 return 0;
448
449 return fs_exists(file);
450}
451
a8f6ab52 452int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
b770e88a 453 int fstype)
a8f6ab52
SG
454{
455 unsigned long addr;
456 const char *filename;
d455d878
SR
457 loff_t bytes;
458 loff_t pos;
459 loff_t len;
460 int ret;
a8f6ab52
SG
461 unsigned long time;
462
463 if (argc < 6 || argc > 7)
464 return CMD_RET_USAGE;
465
466 if (fs_set_blk_dev(argv[1], argv[2], fstype))
467 return 1;
468
d455d878
SR
469 addr = simple_strtoul(argv[3], NULL, 16);
470 filename = argv[4];
b770e88a 471 bytes = simple_strtoul(argv[5], NULL, 16);
a8f6ab52 472 if (argc >= 7)
b770e88a 473 pos = simple_strtoul(argv[6], NULL, 16);
a8f6ab52
SG
474 else
475 pos = 0;
476
477 time = get_timer(0);
d455d878 478 ret = fs_write(filename, addr, pos, bytes, &len);
a8f6ab52 479 time = get_timer(time);
d455d878 480 if (ret < 0)
a8f6ab52
SG
481 return 1;
482
d455d878 483 printf("%llu bytes written in %lu ms", len, time);
a8f6ab52
SG
484 if (time > 0) {
485 puts(" (");
9e374e7b 486 print_size(div_u64(len, time) * 1000, "/s");
a8f6ab52
SG
487 puts(")");
488 }
489 puts("\n");
490
491 return 0;
492}
59e890ef
CG
493
494int do_fs_uuid(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
495 int fstype)
496{
497 int ret;
498 char uuid[37];
499 memset(uuid, 0, sizeof(uuid));
500
501 if (argc < 3 || argc > 4)
502 return CMD_RET_USAGE;
503
504 if (fs_set_blk_dev(argv[1], argv[2], fstype))
505 return 1;
506
507 ret = fs_uuid(uuid);
508 if (ret)
509 return CMD_RET_FAILURE;
510
511 if (argc == 4)
382bee57 512 env_set(argv[3], uuid);
59e890ef
CG
513 else
514 printf("%s\n", uuid);
515
516 return CMD_RET_SUCCESS;
517}
1a1ad8e0
SS
518
519int do_fs_type(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
520{
521 struct fstype_info *info;
522
523 if (argc < 3 || argc > 4)
524 return CMD_RET_USAGE;
525
526 if (fs_set_blk_dev(argv[1], argv[2], FS_TYPE_ANY))
527 return 1;
528
529 info = fs_get_info(fs_type);
530
531 if (argc == 4)
382bee57 532 env_set(argv[3], info->name);
1a1ad8e0
SS
533 else
534 printf("%s\n", info->name);
535
536 return CMD_RET_SUCCESS;
537}
538