diff options
author | Uma Shankar <uma.shankar@samsung.com> | 2012-05-25 21:21:44 +0530 |
---|---|---|
committer | Wolfgang Denk <wd@denx.de> | 2012-08-09 23:47:43 +0200 |
commit | a1596438a68921d2c9b1fdec70a720d38c85ca7d (patch) | |
tree | 41abe5c16734aae38d1ebd130103bc83d8d5180c /fs/ext4/ext4fs.c | |
parent | 4d3c95f5ea7c737a21cd6b9c59435ee693b3f127 (diff) |
ext4fs ls load support
Signed-off-by: Uma Shankar <uma.shankar@samsung.com>
Signed-off-by: Manjunatha C Achar <a.manjunatha@samsung.com>
Signed-off-by: Iqbal Shareef <iqbal.ams@samsung.com>
Signed-off-by: Hakgoo Lee <goodguy.lee@samsung.com>
Diffstat (limited to 'fs/ext4/ext4fs.c')
-rw-r--r-- | fs/ext4/ext4fs.c | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c new file mode 100644 index 00000000000..1287bf0e182 --- /dev/null +++ b/fs/ext4/ext4fs.c @@ -0,0 +1,228 @@ +/* + * (C) Copyright 2011 - 2012 Samsung Electronics + * EXT4 filesystem implementation in Uboot by + * Uma Shankar <uma.shankar@samsung.com> + * Manjunatha C Achar <a.manjunatha@samsung.com> + * + * ext4ls and ext4load : Based on ext2 ls and load support in Uboot. + * Ext4 read optimization taken from Open-Moko + * Qi bootloader + * + * (C) Copyright 2004 + * esd gmbh <www.esd-electronics.com> + * Reinhard Arlt <reinhard.arlt@esd-electronics.com> + * + * based on code from grub2 fs/ext2.c and fs/fshelp.c by + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003, 2004 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <common.h> +#include <malloc.h> +#include <ext_common.h> +#include <ext4fs.h> +#include <linux/stat.h> +#include <linux/time.h> +#include <asm/byteorder.h> +#include "ext4_common.h" + +int ext4fs_symlinknest; +block_dev_desc_t *ext4_dev_desc; + +struct ext_filesystem *get_fs(void) +{ + if (ext4_dev_desc == NULL || ext4_dev_desc->priv == NULL) + printf("Invalid Input Arguments %s\n", __func__); + + return ext4_dev_desc->priv; +} + +int init_fs(block_dev_desc_t *dev_desc) +{ + struct ext_filesystem *fs; + if (dev_desc == NULL) { + printf("Invalid Input Arguments %s\n", __func__); + return -EINVAL; + } + + fs = zalloc(sizeof(struct ext_filesystem)); + if (fs == NULL) { + printf("malloc failed: %s\n", __func__); + return -ENOMEM; + } + + fs->dev_desc = dev_desc; + dev_desc->priv = fs; + + return 0; +} + +void deinit_fs(block_dev_desc_t *dev_desc) +{ + if (dev_desc == NULL) { + printf("Invalid Input Arguments %s\n", __func__); + return; + } + free(dev_desc->priv); + dev_desc->priv = NULL; +} + +void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot) +{ + if ((node != &ext4fs_root->diropen) && (node != currroot)) + free(node); +} + +/* + * Taken from openmoko-kernel mailing list: By Andy green + * Optimized read file API : collects and defers contiguous sector + * reads into one potentially more efficient larger sequential read action + */ +int ext4fs_read_file(struct ext2fs_node *node, int pos, + unsigned int len, char *buf) +{ + int i; + int blockcnt; + int log2blocksize = LOG2_EXT2_BLOCK_SIZE(node->data); + int blocksize = 1 << (log2blocksize + DISK_SECTOR_BITS); + unsigned int filesize = __le32_to_cpu(node->inode.size); + int previous_block_number = -1; + int delayed_start = 0; + int delayed_extent = 0; + int delayed_skipfirst = 0; + int delayed_next = 0; + char *delayed_buf = NULL; + short status; + + /* Adjust len so it we can't read past the end of the file. */ + if (len > filesize) + len = filesize; + + blockcnt = ((len + pos) + blocksize - 1) / blocksize; + + for (i = pos / blocksize; i < blockcnt; i++) { + int blknr; + int blockoff = pos % blocksize; + int blockend = blocksize; + int skipfirst = 0; + blknr = read_allocated_block(&(node->inode), i); + if (blknr < 0) + return -1; + + blknr = blknr << log2blocksize; + + /* Last block. */ + if (i == blockcnt - 1) { + blockend = (len + pos) % blocksize; + + /* The last portion is exactly blocksize. */ + if (!blockend) + blockend = blocksize; + } + + /* First block. */ + if (i == pos / blocksize) { + skipfirst = blockoff; + blockend -= skipfirst; + } + if (blknr) { + int status; + + if (previous_block_number != -1) { + if (delayed_next == blknr) { + delayed_extent += blockend; + delayed_next += blockend >> SECTOR_BITS; + } else { /* spill */ + status = ext4fs_devread(delayed_start, + delayed_skipfirst, + delayed_extent, + delayed_buf); + if (status == 0) + return -1; + previous_block_number = blknr; + delayed_start = blknr; + delayed_extent = blockend; + delayed_skipfirst = skipfirst; + delayed_buf = buf; + delayed_next = blknr + + (blockend >> SECTOR_BITS); + } + } else { + previous_block_number = blknr; + delayed_start = blknr; + delayed_extent = blockend; + delayed_skipfirst = skipfirst; + delayed_buf = buf; + delayed_next = blknr + + (blockend >> SECTOR_BITS); + } + } else { + if (previous_block_number != -1) { + /* spill */ + status = ext4fs_devread(delayed_start, + delayed_skipfirst, + delayed_extent, + delayed_buf); + if (status == 0) + return -1; + previous_block_number = -1; + } + memset(buf, 0, blocksize - skipfirst); + } + buf += blocksize - skipfirst; + } + if (previous_block_number != -1) { + /* spill */ + status = ext4fs_devread(delayed_start, + delayed_skipfirst, delayed_extent, + delayed_buf); + if (status == 0) + return -1; + previous_block_number = -1; + } + + return len; +} + +int ext4fs_ls(const char *dirname) +{ + struct ext2fs_node *dirnode; + int status; + + if (dirname == NULL) + return 0; + + status = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode, + FILETYPE_DIRECTORY); + if (status != 1) { + printf("** Can not find directory. **\n"); + return 1; + } + + ext4fs_iterate_dir(dirnode, NULL, NULL, NULL); + ext4fs_free_node(dirnode, &ext4fs_root->diropen); + + return 0; +} + +int ext4fs_read(char *buf, unsigned len) +{ + if (ext4fs_root == NULL || ext4fs_file == NULL) + return 0; + + return ext4fs_read_file(ext4fs_file, 0, len, buf); +} |