2 * (C) Copyright 2011 - 2012 Samsung Electronics
3 * EXT4 filesystem implementation in Uboot by
4 * Uma Shankar <uma.shankar@samsung.com>
5 * Manjunatha C Achar <a.manjunatha@samsung.com>
7 * ext4ls and ext4load : Based on ext2 ls load support in Uboot.
10 * esd gmbh <www.esd-electronics.com>
11 * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
13 * based on code from grub2 fs/ext2.c and fs/fshelp.c by
14 * GRUB -- GRand Unified Bootloader
15 * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33 #include <ext_common.h>
37 #include <linux/stat.h>
38 #include <linux/time.h>
39 #include <asm/byteorder.h>
40 #include "ext4_common.h"
42 struct ext2_data *ext4fs_root;
43 struct ext2fs_node *ext4fs_file;
44 uint32_t *ext4fs_indir1_block;
45 int ext4fs_indir1_size;
46 int ext4fs_indir1_blkno = -1;
47 uint32_t *ext4fs_indir2_block;
48 int ext4fs_indir2_size;
49 int ext4fs_indir2_blkno = -1;
51 uint32_t *ext4fs_indir3_block;
52 int ext4fs_indir3_size;
53 int ext4fs_indir3_blkno = -1;
54 struct ext2_inode *g_parent_inode;
55 static int symlinknest;
57 static struct ext4_extent_header *ext4fs_get_extent_block
58 (struct ext2_data *data, char *buf,
59 struct ext4_extent_header *ext_block,
60 uint32_t fileblock, int log2_blksz)
62 struct ext4_extent_idx *index;
63 unsigned long long block;
64 struct ext_filesystem *fs = get_fs();
68 index = (struct ext4_extent_idx *)(ext_block + 1);
70 if (le32_to_cpu(ext_block->eh_magic) != EXT4_EXT_MAGIC)
73 if (ext_block->eh_depth == 0)
78 if (i >= le32_to_cpu(ext_block->eh_entries))
80 } while (fileblock > le32_to_cpu(index[i].ei_block));
85 block = le32_to_cpu(index[i].ei_leaf_hi);
86 block = (block << 32) + le32_to_cpu(index[i].ei_leaf_lo);
88 if (ext4fs_devread(block << log2_blksz, 0, fs->blksz, buf))
89 ext_block = (struct ext4_extent_header *)buf;
95 static int ext4fs_blockgroup
96 (struct ext2_data *data, int group, struct ext2_block_group *blkgrp)
99 unsigned int blkoff, desc_per_blk;
101 desc_per_blk = EXT2_BLOCK_SIZE(data) / sizeof(struct ext2_block_group);
103 blkno = __le32_to_cpu(data->sblock.first_data_block) + 1 +
104 group / desc_per_blk;
105 blkoff = (group % desc_per_blk) * sizeof(struct ext2_block_group);
107 debug("ext4fs read %d group descriptor (blkno %ld blkoff %u)\n",
108 group, blkno, blkoff);
110 return ext4fs_devread(blkno << LOG2_EXT2_BLOCK_SIZE(data),
111 blkoff, sizeof(struct ext2_block_group),
115 int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode)
117 struct ext2_block_group blkgrp;
118 struct ext2_sblock *sblock = &data->sblock;
119 struct ext_filesystem *fs = get_fs();
120 int inodes_per_block, status;
124 /* It is easier to calculate if the first inode is 0. */
126 status = ext4fs_blockgroup(data, ino / __le32_to_cpu
127 (sblock->inodes_per_group), &blkgrp);
131 inodes_per_block = EXT2_BLOCK_SIZE(data) / fs->inodesz;
132 blkno = __le32_to_cpu(blkgrp.inode_table_id) +
133 (ino % __le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
134 blkoff = (ino % inodes_per_block) * fs->inodesz;
135 /* Read the inode. */
136 status = ext4fs_devread(blkno << LOG2_EXT2_BLOCK_SIZE(data), blkoff,
137 sizeof(struct ext2_inode), (char *)inode);
144 long int read_allocated_block(struct ext2_inode *inode, int fileblock)
151 long int perblock_parent;
152 long int perblock_child;
153 unsigned long long start;
154 /* get the blocksize of the filesystem */
155 blksz = EXT2_BLOCK_SIZE(ext4fs_root);
156 log2_blksz = LOG2_EXT2_BLOCK_SIZE(ext4fs_root);
157 if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) {
158 char *buf = zalloc(blksz);
161 struct ext4_extent_header *ext_block;
162 struct ext4_extent *extent;
164 ext_block = ext4fs_get_extent_block(ext4fs_root, buf,
165 (struct ext4_extent_header
168 fileblock, log2_blksz);
170 printf("invalid extent block\n");
175 extent = (struct ext4_extent *)(ext_block + 1);
179 if (i >= le32_to_cpu(ext_block->eh_entries))
181 } while (fileblock >= le32_to_cpu(extent[i].ee_block));
183 fileblock -= le32_to_cpu(extent[i].ee_block);
184 if (fileblock >= le32_to_cpu(extent[i].ee_len)) {
189 start = le32_to_cpu(extent[i].ee_start_hi);
190 start = (start << 32) +
191 le32_to_cpu(extent[i].ee_start_lo);
193 return fileblock + start;
196 printf("Extent Error\n");
202 if (fileblock < INDIRECT_BLOCKS)
203 blknr = __le32_to_cpu(inode->b.blocks.dir_blocks[fileblock]);
206 else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4))) {
207 if (ext4fs_indir1_block == NULL) {
208 ext4fs_indir1_block = zalloc(blksz);
209 if (ext4fs_indir1_block == NULL) {
210 printf("** SI ext2fs read block (indir 1)"
211 "malloc failed. **\n");
214 ext4fs_indir1_size = blksz;
215 ext4fs_indir1_blkno = -1;
217 if (blksz != ext4fs_indir1_size) {
218 free(ext4fs_indir1_block);
219 ext4fs_indir1_block = NULL;
220 ext4fs_indir1_size = 0;
221 ext4fs_indir1_blkno = -1;
222 ext4fs_indir1_block = zalloc(blksz);
223 if (ext4fs_indir1_block == NULL) {
224 printf("** SI ext2fs read block (indir 1):"
225 "malloc failed. **\n");
228 ext4fs_indir1_size = blksz;
230 if ((__le32_to_cpu(inode->b.blocks.indir_block) <<
231 log2_blksz) != ext4fs_indir1_blkno) {
233 ext4fs_devread(__le32_to_cpu
235 indir_block) << log2_blksz, 0,
236 blksz, (char *)ext4fs_indir1_block);
238 printf("** SI ext2fs read block (indir 1)"
242 ext4fs_indir1_blkno =
243 __le32_to_cpu(inode->b.blocks.
244 indir_block) << log2_blksz;
246 blknr = __le32_to_cpu(ext4fs_indir1_block
247 [fileblock - INDIRECT_BLOCKS]);
249 /* Double indirect. */
250 else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4 *
253 long int perblock = blksz / 4;
254 long int rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4);
256 if (ext4fs_indir1_block == NULL) {
257 ext4fs_indir1_block = zalloc(blksz);
258 if (ext4fs_indir1_block == NULL) {
259 printf("** DI ext2fs read block (indir 2 1)"
260 "malloc failed. **\n");
263 ext4fs_indir1_size = blksz;
264 ext4fs_indir1_blkno = -1;
266 if (blksz != ext4fs_indir1_size) {
267 free(ext4fs_indir1_block);
268 ext4fs_indir1_block = NULL;
269 ext4fs_indir1_size = 0;
270 ext4fs_indir1_blkno = -1;
271 ext4fs_indir1_block = zalloc(blksz);
272 if (ext4fs_indir1_block == NULL) {
273 printf("** DI ext2fs read block (indir 2 1)"
274 "malloc failed. **\n");
277 ext4fs_indir1_size = blksz;
279 if ((__le32_to_cpu(inode->b.blocks.double_indir_block) <<
280 log2_blksz) != ext4fs_indir1_blkno) {
282 ext4fs_devread(__le32_to_cpu
284 double_indir_block) << log2_blksz,
286 (char *)ext4fs_indir1_block);
288 printf("** DI ext2fs read block (indir 2 1)"
292 ext4fs_indir1_blkno =
293 __le32_to_cpu(inode->b.blocks.double_indir_block) <<
297 if (ext4fs_indir2_block == NULL) {
298 ext4fs_indir2_block = zalloc(blksz);
299 if (ext4fs_indir2_block == NULL) {
300 printf("** DI ext2fs read block (indir 2 2)"
301 "malloc failed. **\n");
304 ext4fs_indir2_size = blksz;
305 ext4fs_indir2_blkno = -1;
307 if (blksz != ext4fs_indir2_size) {
308 free(ext4fs_indir2_block);
309 ext4fs_indir2_block = NULL;
310 ext4fs_indir2_size = 0;
311 ext4fs_indir2_blkno = -1;
312 ext4fs_indir2_block = zalloc(blksz);
313 if (ext4fs_indir2_block == NULL) {
314 printf("** DI ext2fs read block (indir 2 2)"
315 "malloc failed. **\n");
318 ext4fs_indir2_size = blksz;
320 if ((__le32_to_cpu(ext4fs_indir1_block[rblock / perblock]) <<
321 log2_blksz) != ext4fs_indir2_blkno) {
322 status = ext4fs_devread(__le32_to_cpu
325 perblock]) << log2_blksz, 0,
327 (char *)ext4fs_indir2_block);
329 printf("** DI ext2fs read block (indir 2 2)"
333 ext4fs_indir2_blkno =
334 __le32_to_cpu(ext4fs_indir1_block[rblock
339 blknr = __le32_to_cpu(ext4fs_indir2_block[rblock % perblock]);
341 /* Tripple indirect. */
343 rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4 +
344 (blksz / 4 * blksz / 4));
345 perblock_child = blksz / 4;
346 perblock_parent = ((blksz / 4) * (blksz / 4));
348 if (ext4fs_indir1_block == NULL) {
349 ext4fs_indir1_block = zalloc(blksz);
350 if (ext4fs_indir1_block == NULL) {
351 printf("** TI ext2fs read block (indir 2 1)"
352 "malloc failed. **\n");
355 ext4fs_indir1_size = blksz;
356 ext4fs_indir1_blkno = -1;
358 if (blksz != ext4fs_indir1_size) {
359 free(ext4fs_indir1_block);
360 ext4fs_indir1_block = NULL;
361 ext4fs_indir1_size = 0;
362 ext4fs_indir1_blkno = -1;
363 ext4fs_indir1_block = zalloc(blksz);
364 if (ext4fs_indir1_block == NULL) {
365 printf("** TI ext2fs read block (indir 2 1)"
366 "malloc failed. **\n");
369 ext4fs_indir1_size = blksz;
371 if ((__le32_to_cpu(inode->b.blocks.triple_indir_block) <<
372 log2_blksz) != ext4fs_indir1_blkno) {
373 status = ext4fs_devread
374 (__le32_to_cpu(inode->b.blocks.triple_indir_block)
375 << log2_blksz, 0, blksz,
376 (char *)ext4fs_indir1_block);
378 printf("** TI ext2fs read block (indir 2 1)"
382 ext4fs_indir1_blkno =
383 __le32_to_cpu(inode->b.blocks.triple_indir_block) <<
387 if (ext4fs_indir2_block == NULL) {
388 ext4fs_indir2_block = zalloc(blksz);
389 if (ext4fs_indir2_block == NULL) {
390 printf("** TI ext2fs read block (indir 2 2)"
391 "malloc failed. **\n");
394 ext4fs_indir2_size = blksz;
395 ext4fs_indir2_blkno = -1;
397 if (blksz != ext4fs_indir2_size) {
398 free(ext4fs_indir2_block);
399 ext4fs_indir2_block = NULL;
400 ext4fs_indir2_size = 0;
401 ext4fs_indir2_blkno = -1;
402 ext4fs_indir2_block = zalloc(blksz);
403 if (ext4fs_indir2_block == NULL) {
404 printf("** TI ext2fs read block (indir 2 2)"
405 "malloc failed. **\n");
408 ext4fs_indir2_size = blksz;
410 if ((__le32_to_cpu(ext4fs_indir1_block[rblock /
413 != ext4fs_indir2_blkno) {
414 status = ext4fs_devread(__le32_to_cpu
418 log2_blksz, 0, blksz,
419 (char *)ext4fs_indir2_block);
421 printf("** TI ext2fs read block (indir 2 2)"
425 ext4fs_indir2_blkno =
426 __le32_to_cpu(ext4fs_indir1_block[rblock /
431 if (ext4fs_indir3_block == NULL) {
432 ext4fs_indir3_block = zalloc(blksz);
433 if (ext4fs_indir3_block == NULL) {
434 printf("** TI ext2fs read block (indir 2 2)"
435 "malloc failed. **\n");
438 ext4fs_indir3_size = blksz;
439 ext4fs_indir3_blkno = -1;
441 if (blksz != ext4fs_indir3_size) {
442 free(ext4fs_indir3_block);
443 ext4fs_indir3_block = NULL;
444 ext4fs_indir3_size = 0;
445 ext4fs_indir3_blkno = -1;
446 ext4fs_indir3_block = zalloc(blksz);
447 if (ext4fs_indir3_block == NULL) {
448 printf("** TI ext2fs read block (indir 2 2)"
449 "malloc failed. **\n");
452 ext4fs_indir3_size = blksz;
454 if ((__le32_to_cpu(ext4fs_indir2_block[rblock
457 log2_blksz) != ext4fs_indir3_blkno) {
459 ext4fs_devread(__le32_to_cpu
461 [(rblock / perblock_child)
462 % (blksz / 4)]) << log2_blksz, 0,
463 blksz, (char *)ext4fs_indir3_block);
465 printf("** TI ext2fs read block (indir 2 2)"
469 ext4fs_indir3_blkno =
470 __le32_to_cpu(ext4fs_indir2_block[(rblock /
477 blknr = __le32_to_cpu(ext4fs_indir3_block
478 [rblock % perblock_child]);
480 debug("ext4fs_read_block %ld\n", blknr);
485 void ext4fs_close(void)
487 if ((ext4fs_file != NULL) && (ext4fs_root != NULL)) {
488 ext4fs_free_node(ext4fs_file, &ext4fs_root->diropen);
491 if (ext4fs_root != NULL) {
495 if (ext4fs_indir1_block != NULL) {
496 free(ext4fs_indir1_block);
497 ext4fs_indir1_block = NULL;
498 ext4fs_indir1_size = 0;
499 ext4fs_indir1_blkno = -1;
501 if (ext4fs_indir2_block != NULL) {
502 free(ext4fs_indir2_block);
503 ext4fs_indir2_block = NULL;
504 ext4fs_indir2_size = 0;
505 ext4fs_indir2_blkno = -1;
507 if (ext4fs_indir3_block != NULL) {
508 free(ext4fs_indir3_block);
509 ext4fs_indir3_block = NULL;
510 ext4fs_indir3_size = 0;
511 ext4fs_indir3_blkno = -1;
515 int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name,
516 struct ext2fs_node **fnode, int *ftype)
518 unsigned int fpos = 0;
520 struct ext2fs_node *diro = (struct ext2fs_node *) dir;
524 printf("Iterate dir %s\n", name);
525 #endif /* of DEBUG */
526 if (!diro->inode_read) {
527 status = ext4fs_read_inode(diro->data, diro->ino, &diro->inode);
531 /* Search the file. */
532 while (fpos < __le32_to_cpu(diro->inode.size)) {
533 struct ext2_dirent dirent;
535 status = ext4fs_read_file(diro, fpos,
536 sizeof(struct ext2_dirent),
541 if (dirent.namelen != 0) {
542 char filename[dirent.namelen + 1];
543 struct ext2fs_node *fdiro;
544 int type = FILETYPE_UNKNOWN;
546 status = ext4fs_read_file(diro,
548 sizeof(struct ext2_dirent),
549 dirent.namelen, filename);
553 fdiro = zalloc(sizeof(struct ext2fs_node));
557 fdiro->data = diro->data;
558 fdiro->ino = __le32_to_cpu(dirent.inode);
560 filename[dirent.namelen] = '\0';
562 if (dirent.filetype != FILETYPE_UNKNOWN) {
563 fdiro->inode_read = 0;
565 if (dirent.filetype == FILETYPE_DIRECTORY)
566 type = FILETYPE_DIRECTORY;
567 else if (dirent.filetype == FILETYPE_SYMLINK)
568 type = FILETYPE_SYMLINK;
569 else if (dirent.filetype == FILETYPE_REG)
572 status = ext4fs_read_inode(diro->data,
580 fdiro->inode_read = 1;
582 if ((__le16_to_cpu(fdiro->inode.mode) &
583 FILETYPE_INO_MASK) ==
584 FILETYPE_INO_DIRECTORY) {
585 type = FILETYPE_DIRECTORY;
586 } else if ((__le16_to_cpu(fdiro->inode.mode)
587 & FILETYPE_INO_MASK) ==
588 FILETYPE_INO_SYMLINK) {
589 type = FILETYPE_SYMLINK;
590 } else if ((__le16_to_cpu(fdiro->inode.mode)
591 & FILETYPE_INO_MASK) ==
597 printf("iterate >%s<\n", filename);
598 #endif /* of DEBUG */
599 if ((name != NULL) && (fnode != NULL)
600 && (ftype != NULL)) {
601 if (strcmp(filename, name) == 0) {
607 if (fdiro->inode_read == 0) {
608 status = ext4fs_read_inode(diro->data,
616 fdiro->inode_read = 1;
619 case FILETYPE_DIRECTORY:
622 case FILETYPE_SYMLINK:
633 __le32_to_cpu(fdiro->inode.size),
638 fpos += __le16_to_cpu(dirent.direntlen);
643 static char *ext4fs_read_symlink(struct ext2fs_node *node)
646 struct ext2fs_node *diro = node;
649 if (!diro->inode_read) {
650 status = ext4fs_read_inode(diro->data, diro->ino, &diro->inode);
654 symlink = zalloc(__le32_to_cpu(diro->inode.size) + 1);
658 if (__le32_to_cpu(diro->inode.size) <= 60) {
659 strncpy(symlink, diro->inode.b.symlink,
660 __le32_to_cpu(diro->inode.size));
662 status = ext4fs_read_file(diro, 0,
663 __le32_to_cpu(diro->inode.size),
670 symlink[__le32_to_cpu(diro->inode.size)] = '\0';
674 static int ext4fs_find_file1(const char *currpath,
675 struct ext2fs_node *currroot,
676 struct ext2fs_node **currfound, int *foundtype)
678 char fpath[strlen(currpath) + 1];
682 int type = FILETYPE_DIRECTORY;
683 struct ext2fs_node *currnode = currroot;
684 struct ext2fs_node *oldnode = currroot;
686 strncpy(fpath, currpath, strlen(currpath) + 1);
688 /* Remove all leading slashes. */
693 *currfound = currnode;
700 /* Extract the actual part from the pathname. */
701 next = strchr(name, '/');
703 /* Remove all leading slashes. */
708 if (type != FILETYPE_DIRECTORY) {
709 ext4fs_free_node(currnode, currroot);
715 /* Iterate over the directory. */
716 found = ext4fs_iterate_dir(currnode, name, &currnode, &type);
723 /* Read in the symlink and follow it. */
724 if (type == FILETYPE_SYMLINK) {
727 /* Test if the symlink does not loop. */
728 if (++symlinknest == 8) {
729 ext4fs_free_node(currnode, currroot);
730 ext4fs_free_node(oldnode, currroot);
734 symlink = ext4fs_read_symlink(currnode);
735 ext4fs_free_node(currnode, currroot);
738 ext4fs_free_node(oldnode, currroot);
742 debug("Got symlink >%s<\n", symlink);
744 if (symlink[0] == '/') {
745 ext4fs_free_node(oldnode, currroot);
746 oldnode = &ext4fs_root->diropen;
749 /* Lookup the node the symlink points to. */
750 status = ext4fs_find_file1(symlink, oldnode,
756 ext4fs_free_node(oldnode, currroot);
761 ext4fs_free_node(oldnode, currroot);
763 /* Found the node! */
764 if (!next || *next == '\0') {
765 *currfound = currnode;
774 int ext4fs_find_file(const char *path, struct ext2fs_node *rootnode,
775 struct ext2fs_node **foundnode, int expecttype)
778 int foundtype = FILETYPE_DIRECTORY;
784 status = ext4fs_find_file1(path, rootnode, foundnode, &foundtype);
788 /* Check if the node that was found was of the expected type. */
789 if ((expecttype == FILETYPE_REG) && (foundtype != expecttype))
791 else if ((expecttype == FILETYPE_DIRECTORY)
792 && (foundtype != expecttype))
798 int ext4fs_open(const char *filename)
800 struct ext2fs_node *fdiro = NULL;
804 if (ext4fs_root == NULL)
808 status = ext4fs_find_file(filename, &ext4fs_root->diropen, &fdiro,
813 if (!fdiro->inode_read) {
814 status = ext4fs_read_inode(fdiro->data, fdiro->ino,
819 len = __le32_to_cpu(fdiro->inode.size);
824 ext4fs_free_node(fdiro, &ext4fs_root->diropen);
829 int ext4fs_mount(unsigned part_length)
831 struct ext2_data *data;
833 struct ext_filesystem *fs = get_fs();
834 data = zalloc(sizeof(struct ext2_data));
838 /* Read the superblock. */
839 status = ext4fs_devread(1 * 2, 0, sizeof(struct ext2_sblock),
840 (char *)&data->sblock);
845 /* Make sure this is an ext2 filesystem. */
846 if (__le16_to_cpu(data->sblock.magic) != EXT2_MAGIC)
849 if (__le32_to_cpu(data->sblock.revision_level == 0))
852 fs->inodesz = __le16_to_cpu(data->sblock.inode_size);
854 debug("EXT2 rev %d, inode_size %d\n",
855 __le32_to_cpu(data->sblock.revision_level), fs->inodesz);
857 data->diropen.data = data;
858 data->diropen.ino = 2;
859 data->diropen.inode_read = 1;
860 data->inode = &data->diropen.inode;
862 status = ext4fs_read_inode(data, 2, data->inode);
870 printf("Failed to mount ext2 filesystem...\n");