summaryrefslogtreecommitdiff
path: root/fs/ext4/ext4fs.c
diff options
context:
space:
mode:
authorUma Shankar <uma.shankar@samsung.com>2012-05-25 21:21:44 +0530
committerWolfgang Denk <wd@denx.de>2012-08-09 23:47:43 +0200
commita1596438a68921d2c9b1fdec70a720d38c85ca7d (patch)
tree41abe5c16734aae38d1ebd130103bc83d8d5180c /fs/ext4/ext4fs.c
parent4d3c95f5ea7c737a21cd6b9c59435ee693b3f127 (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.c228
1 files changed, 228 insertions, 0 deletions
diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c
new file mode 100644
index 0000000000..1287bf0e18
--- /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);
+}