summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/ext4/Makefile2
-rw-r--r--fs/ext4/ext4_write.c996
-rw-r--r--fs/ext4/ext4fs.c962
-rw-r--r--fs/fat/fat.c17
-rw-r--r--fs/fs.c241
-rw-r--r--fs/sandbox/Makefile47
-rw-r--r--fs/sandbox/sandboxfs.c83
-rw-r--r--fs/ubifs/super.c4
-rw-r--r--fs/ubifs/ubifs.c4
9 files changed, 1258 insertions, 1098 deletions
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
index bb801f9054..3bde82418e 100644
--- a/fs/ext4/Makefile
+++ b/fs/ext4/Makefile
@@ -31,7 +31,7 @@ LIB = $(obj)libext4fs.o
AOBJS =
COBJS-$(CONFIG_FS_EXT4) := ext4fs.o ext4_common.o dev.o
-COBJS-$(CONFIG_EXT4_WRITE) += ext4_journal.o crc16.o
+COBJS-$(CONFIG_EXT4_WRITE) += ext4_write.o ext4_journal.o crc16.o
SRCS := $(AOBJS:.o=.S) $(COBJS-y:.o=.c)
OBJS := $(addprefix $(obj),$(AOBJS) $(COBJS-y))
diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c
new file mode 100644
index 0000000000..c4e399ccfa
--- /dev/null
+++ b/fs/ext4/ext4_write.c
@@ -0,0 +1,996 @@
+/*
+ * (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.
+ *
+ * ext4write : Based on generic ext4 protocol.
+ *
+ * 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 <linux/stat.h>
+#include <div64.h>
+#include "ext4_common.h"
+
+static void ext4fs_update(void)
+{
+ short i;
+ ext4fs_update_journal();
+ struct ext_filesystem *fs = get_fs();
+
+ /* update super block */
+ put_ext4((uint64_t)(SUPERBLOCK_SIZE),
+ (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
+
+ /* update block groups */
+ for (i = 0; i < fs->no_blkgrp; i++) {
+ fs->bgd[i].bg_checksum = ext4fs_checksum_update(i);
+ put_ext4((uint64_t)(fs->bgd[i].block_id * fs->blksz),
+ fs->blk_bmaps[i], fs->blksz);
+ }
+
+ /* update inode table groups */
+ for (i = 0; i < fs->no_blkgrp; i++) {
+ put_ext4((uint64_t) (fs->bgd[i].inode_id * fs->blksz),
+ fs->inode_bmaps[i], fs->blksz);
+ }
+
+ /* update the block group descriptor table */
+ put_ext4((uint64_t)(fs->gdtable_blkno * fs->blksz),
+ (struct ext2_block_group *)fs->gdtable,
+ (fs->blksz * fs->no_blk_pergdt));
+
+ ext4fs_dump_metadata();
+
+ gindex = 0;
+ gd_index = 0;
+}
+
+int ext4fs_get_bgdtable(void)
+{
+ int status;
+ int grp_desc_size;
+ struct ext_filesystem *fs = get_fs();
+ grp_desc_size = sizeof(struct ext2_block_group);
+ fs->no_blk_pergdt = (fs->no_blkgrp * grp_desc_size) / fs->blksz;
+ if ((fs->no_blkgrp * grp_desc_size) % fs->blksz)
+ fs->no_blk_pergdt++;
+
+ /* allocate memory for gdtable */
+ fs->gdtable = zalloc(fs->blksz * fs->no_blk_pergdt);
+ if (!fs->gdtable)
+ return -ENOMEM;
+ /* read the group descriptor table */
+ status = ext4fs_devread(fs->gdtable_blkno * fs->sect_perblk, 0,
+ fs->blksz * fs->no_blk_pergdt, fs->gdtable);
+ if (status == 0)
+ goto fail;
+
+ if (ext4fs_log_gdt(fs->gdtable)) {
+ printf("Error in ext4fs_log_gdt\n");
+ return -1;
+ }
+
+ return 0;
+fail:
+ free(fs->gdtable);
+ fs->gdtable = NULL;
+
+ return -1;
+}
+
+static void delete_single_indirect_block(struct ext2_inode *inode)
+{
+ struct ext2_block_group *bgd = NULL;
+ static int prev_bg_bmap_idx = -1;
+ long int blknr;
+ int remainder;
+ int bg_idx;
+ int status;
+ unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
+ struct ext_filesystem *fs = get_fs();
+ char *journal_buffer = zalloc(fs->blksz);
+ if (!journal_buffer) {
+ printf("No memory\n");
+ return;
+ }
+ /* get block group descriptor table */
+ bgd = (struct ext2_block_group *)fs->gdtable;
+
+ /* deleting the single indirect block associated with inode */
+ if (inode->b.blocks.indir_block != 0) {
+ debug("SIPB releasing %u\n", inode->b.blocks.indir_block);
+ blknr = inode->b.blocks.indir_block;
+ if (fs->blksz != 1024) {
+ bg_idx = blknr / blk_per_grp;
+ } else {
+ bg_idx = blknr / blk_per_grp;
+ remainder = blknr % blk_per_grp;
+ if (!remainder)
+ bg_idx--;
+ }
+ ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
+ bgd[bg_idx].free_blocks++;
+ fs->sb->free_blocks++;
+ /* journal backup */
+ if (prev_bg_bmap_idx != bg_idx) {
+ status =
+ ext4fs_devread(bgd[bg_idx].block_id *
+ fs->sect_perblk, 0, fs->blksz,
+ journal_buffer);
+ if (status == 0)
+ goto fail;
+ if (ext4fs_log_journal
+ (journal_buffer, bgd[bg_idx].block_id))
+ goto fail;
+ prev_bg_bmap_idx = bg_idx;
+ }
+ }
+fail:
+ free(journal_buffer);
+}
+
+static void delete_double_indirect_block(struct ext2_inode *inode)
+{
+ int i;
+ short status;
+ static int prev_bg_bmap_idx = -1;
+ long int blknr;
+ int remainder;
+ int bg_idx;
+ unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
+ unsigned int *di_buffer = NULL;
+ unsigned int *DIB_start_addr = NULL;
+ struct ext2_block_group *bgd = NULL;
+ struct ext_filesystem *fs = get_fs();
+ char *journal_buffer = zalloc(fs->blksz);
+ if (!journal_buffer) {
+ printf("No memory\n");
+ return;
+ }
+ /* get the block group descriptor table */
+ bgd = (struct ext2_block_group *)fs->gdtable;
+
+ if (inode->b.blocks.double_indir_block != 0) {
+ di_buffer = zalloc(fs->blksz);
+ if (!di_buffer) {
+ printf("No memory\n");
+ return;
+ }
+ DIB_start_addr = (unsigned int *)di_buffer;
+ blknr = inode->b.blocks.double_indir_block;
+ status = ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
+ (char *)di_buffer);
+ for (i = 0; i < fs->blksz / sizeof(int); i++) {
+ if (*di_buffer == 0)
+ break;
+
+ debug("DICB releasing %u\n", *di_buffer);
+ if (fs->blksz != 1024) {
+ bg_idx = (*di_buffer) / blk_per_grp;
+ } else {
+ bg_idx = (*di_buffer) / blk_per_grp;
+ remainder = (*di_buffer) % blk_per_grp;
+ if (!remainder)
+ bg_idx--;
+ }
+ ext4fs_reset_block_bmap(*di_buffer,
+ fs->blk_bmaps[bg_idx], bg_idx);
+ di_buffer++;
+ bgd[bg_idx].free_blocks++;
+ fs->sb->free_blocks++;
+ /* journal backup */
+ if (prev_bg_bmap_idx != bg_idx) {
+ status = ext4fs_devread(bgd[bg_idx].block_id
+ * fs->sect_perblk, 0,
+ fs->blksz,
+ journal_buffer);
+ if (status == 0)
+ goto fail;
+
+ if (ext4fs_log_journal(journal_buffer,
+ bgd[bg_idx].block_id))
+ goto fail;
+ prev_bg_bmap_idx = bg_idx;
+ }
+ }
+
+ /* removing the parent double indirect block */
+ blknr = inode->b.blocks.double_indir_block;
+ if (fs->blksz != 1024) {
+ bg_idx = blknr / blk_per_grp;
+ } else {
+ bg_idx = blknr / blk_per_grp;
+ remainder = blknr % blk_per_grp;
+ if (!remainder)
+ bg_idx--;
+ }
+ ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
+ bgd[bg_idx].free_blocks++;
+ fs->sb->free_blocks++;
+ /* journal backup */
+ if (prev_bg_bmap_idx != bg_idx) {
+ memset(journal_buffer, '\0', fs->blksz);
+ status = ext4fs_devread(bgd[bg_idx].block_id *
+ fs->sect_perblk, 0, fs->blksz,
+ journal_buffer);
+ if (status == 0)
+ goto fail;
+
+ if (ext4fs_log_journal(journal_buffer,
+ bgd[bg_idx].block_id))
+ goto fail;
+ prev_bg_bmap_idx = bg_idx;
+ }
+ debug("DIPB releasing %ld\n", blknr);
+ }
+fail:
+ free(DIB_start_addr);
+ free(journal_buffer);
+}
+
+static void delete_triple_indirect_block(struct ext2_inode *inode)
+{
+ int i, j;
+ short status;
+ static int prev_bg_bmap_idx = -1;
+ long int blknr;
+ int remainder;
+ int bg_idx;
+ unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
+ unsigned int *tigp_buffer = NULL;
+ unsigned int *tib_start_addr = NULL;
+ unsigned int *tip_buffer = NULL;
+ unsigned int *tipb_start_addr = NULL;
+ struct ext2_block_group *bgd = NULL;
+ struct ext_filesystem *fs = get_fs();
+ char *journal_buffer = zalloc(fs->blksz);
+ if (!journal_buffer) {
+ printf("No memory\n");
+ return;
+ }
+ /* get block group descriptor table */
+ bgd = (struct ext2_block_group *)fs->gdtable;
+
+ if (inode->b.blocks.triple_indir_block != 0) {
+ tigp_buffer = zalloc(fs->blksz);
+ if (!tigp_buffer) {
+ printf("No memory\n");
+ return;
+ }
+ tib_start_addr = (unsigned int *)tigp_buffer;
+ blknr = inode->b.blocks.triple_indir_block;
+ status = ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
+ (char *)tigp_buffer);
+ for (i = 0; i < fs->blksz / sizeof(int); i++) {
+ if (*tigp_buffer == 0)
+ break;
+ debug("tigp buffer releasing %u\n", *tigp_buffer);
+
+ tip_buffer = zalloc(fs->blksz);
+ if (!tip_buffer)
+ goto fail;
+ tipb_start_addr = (unsigned int *)tip_buffer;
+ status = ext4fs_devread((*tigp_buffer) *
+ fs->sect_perblk, 0, fs->blksz,
+ (char *)tip_buffer);
+ for (j = 0; j < fs->blksz / sizeof(int); j++) {
+ if (*tip_buffer == 0)
+ break;
+ if (fs->blksz != 1024) {
+ bg_idx = (*tip_buffer) / blk_per_grp;
+ } else {
+ bg_idx = (*tip_buffer) / blk_per_grp;
+
+ remainder = (*tip_buffer) % blk_per_grp;
+ if (!remainder)
+ bg_idx--;
+ }
+
+ ext4fs_reset_block_bmap(*tip_buffer,
+ fs->blk_bmaps[bg_idx],
+ bg_idx);
+
+ tip_buffer++;
+ bgd[bg_idx].free_blocks++;
+ fs->sb->free_blocks++;
+ /* journal backup */
+ if (prev_bg_bmap_idx != bg_idx) {
+ status =
+ ext4fs_devread(
+ bgd[bg_idx].block_id *
+ fs->sect_perblk, 0,
+ fs->blksz,
+ journal_buffer);
+ if (status == 0)
+ goto fail;
+
+ if (ext4fs_log_journal(journal_buffer,
+ bgd[bg_idx].
+ block_id))
+ goto fail;
+ prev_bg_bmap_idx = bg_idx;
+ }
+ }
+ free(tipb_start_addr);
+ tipb_start_addr = NULL;
+
+ /*
+ * removing the grand parent blocks
+ * which is connected to inode
+ */
+ if (fs->blksz != 1024) {
+ bg_idx = (*tigp_buffer) / blk_per_grp;
+ } else {
+ bg_idx = (*tigp_buffer) / blk_per_grp;
+
+ remainder = (*tigp_buffer) % blk_per_grp;
+ if (!remainder)
+ bg_idx--;
+ }
+ ext4fs_reset_block_bmap(*tigp_buffer,
+ fs->blk_bmaps[bg_idx], bg_idx);
+
+ tigp_buffer++;
+ bgd[bg_idx].free_blocks++;
+ fs->sb->free_blocks++;
+ /* journal backup */
+ if (prev_bg_bmap_idx != bg_idx) {
+ memset(journal_buffer, '\0', fs->blksz);
+ status =
+ ext4fs_devread(bgd[bg_idx].block_id *
+ fs->sect_perblk, 0,
+ fs->blksz, journal_buffer);
+ if (status == 0)
+ goto fail;
+
+ if (ext4fs_log_journal(journal_buffer,
+ bgd[bg_idx].block_id))
+ goto fail;
+ prev_bg_bmap_idx = bg_idx;
+ }
+ }
+
+ /* removing the grand parent triple indirect block */
+ blknr = inode->b.blocks.triple_indir_block;
+ if (fs->blksz != 1024) {
+ bg_idx = blknr / blk_per_grp;
+ } else {
+ bg_idx = blknr / blk_per_grp;
+ remainder = blknr % blk_per_grp;
+ if (!remainder)
+ bg_idx--;
+ }
+ ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
+ bgd[bg_idx].free_blocks++;
+ fs->sb->free_blocks++;
+ /* journal backup */
+ if (prev_bg_bmap_idx != bg_idx) {
+ memset(journal_buffer, '\0', fs->blksz);
+ status = ext4fs_devread(bgd[bg_idx].block_id *
+ fs->sect_perblk, 0, fs->blksz,
+ journal_buffer);
+ if (status == 0)
+ goto fail;
+
+ if (ext4fs_log_journal(journal_buffer,
+ bgd[bg_idx].block_id))
+ goto fail;
+ prev_bg_bmap_idx = bg_idx;
+ }
+ debug("tigp buffer itself releasing %ld\n", blknr);
+ }
+fail:
+ free(tib_start_addr);
+ free(tipb_start_addr);
+ free(journal_buffer);
+}
+
+static int ext4fs_delete_file(int inodeno)
+{
+ struct ext2_inode inode;
+ short status;
+ int i;
+ int remainder;
+ long int blknr;
+ int bg_idx;
+ int ibmap_idx;
+ char *read_buffer = NULL;
+ char *start_block_address = NULL;
+ unsigned int no_blocks;
+
+ static int prev_bg_bmap_idx = -1;
+ unsigned int inodes_per_block;
+ long int blkno;
+ unsigned int blkoff;
+ unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
+ unsigned int inode_per_grp = ext4fs_root->sblock.inodes_per_group;
+ struct ext2_inode *inode_buffer = NULL;
+ struct ext2_block_group *bgd = NULL;
+ struct ext_filesystem *fs = get_fs();
+ char *journal_buffer = zalloc(fs->blksz);
+ if (!journal_buffer)
+ return -ENOMEM;
+ /* get the block group descriptor table */
+ bgd = (struct ext2_block_group *)fs->gdtable;
+ status = ext4fs_read_inode(ext4fs_root, inodeno, &inode);
+ if (status == 0)
+ goto fail;
+
+ /* read the block no allocated to a file */
+ no_blocks = inode.size / fs->blksz;
+ if (inode.size % fs->blksz)
+ no_blocks++;
+
+ if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FL) {
+ struct ext2fs_node *node_inode =
+ zalloc(sizeof(struct ext2fs_node));
+ if (!node_inode)
+ goto fail;
+ node_inode->data = ext4fs_root;
+ node_inode->ino = inodeno;
+ node_inode->inode_read = 0;
+ memcpy(&(node_inode->inode), &inode, sizeof(struct ext2_inode));
+
+ for (i = 0; i < no_blocks; i++) {
+ blknr = read_allocated_block(&(node_inode->inode), i);
+ if (fs->blksz != 1024) {
+ bg_idx = blknr / blk_per_grp;
+ } else {
+ bg_idx = blknr / blk_per_grp;
+ remainder = blknr % blk_per_grp;
+ if (!remainder)
+ bg_idx--;
+ }
+ ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx],
+ bg_idx);
+ debug("EXT4_EXTENTS Block releasing %ld: %d\n",
+ blknr, bg_idx);
+
+ bgd[bg_idx].free_blocks++;
+ fs->sb->free_blocks++;
+
+ /* journal backup */
+ if (prev_bg_bmap_idx != bg_idx) {
+ status =
+ ext4fs_devread(bgd[bg_idx].block_id *
+ fs->sect_perblk, 0,
+ fs->blksz, journal_buffer);
+ if (status == 0)
+ goto fail;
+ if (ext4fs_log_journal(journal_buffer,
+ bgd[bg_idx].block_id))
+ goto fail;
+ prev_bg_bmap_idx = bg_idx;
+ }
+ }
+ if (node_inode) {
+ free(node_inode);
+ node_inode = NULL;
+ }
+ } else {
+
+ delete_single_indirect_block(&inode);
+ delete_double_indirect_block(&inode);
+ delete_triple_indirect_block(&inode);
+
+ /* read the block no allocated to a file */
+ no_blocks = inode.size / fs->blksz;
+ if (inode.size % fs->blksz)
+ no_blocks++;
+ for (i = 0; i < no_blocks; i++) {
+ blknr = read_allocated_block(&inode, i);
+ if (fs->blksz != 1024) {
+ bg_idx = blknr / blk_per_grp;
+ } else {
+ bg_idx = blknr / blk_per_grp;
+ remainder = blknr % blk_per_grp;
+ if (!remainder)
+ bg_idx--;
+ }
+ ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx],
+ bg_idx);
+ debug("ActualB releasing %ld: %d\n", blknr, bg_idx);
+
+ bgd[bg_idx].free_blocks++;
+ fs->sb->free_blocks++;
+ /* journal backup */
+ if (prev_bg_bmap_idx != bg_idx) {
+ memset(journal_buffer, '\0', fs->blksz);
+ status = ext4fs_devread(bgd[bg_idx].block_id
+ * fs->sect_perblk,
+ 0, fs->blksz,
+ journal_buffer);
+ if (status == 0)
+ goto fail;
+ if (ext4fs_log_journal(journal_buffer,
+ bgd[bg_idx].block_id))
+ goto fail;
+ prev_bg_bmap_idx = bg_idx;
+ }
+ }
+ }
+
+ /* from the inode no to blockno */
+ inodes_per_block = fs->blksz / fs->inodesz;
+ ibmap_idx = inodeno / inode_per_grp;
+
+ /* get the block no */
+ inodeno--;
+ blkno = __le32_to_cpu(bgd[ibmap_idx].inode_table_id) +
+ (inodeno % __le32_to_cpu(inode_per_grp)) / inodes_per_block;
+
+ /* get the offset of the inode */
+ blkoff = ((inodeno) % inodes_per_block) * fs->inodesz;
+
+ /* read the block no containing the inode */
+ read_buffer = zalloc(fs->blksz);
+ if (!read_buffer)
+ goto fail;
+ start_block_address = read_buffer;
+ status = ext4fs_devread(blkno * fs->sect_perblk,
+ 0, fs->blksz, read_buffer);
+ if (status == 0)
+ goto fail;
+
+ if (ext4fs_log_journal(read_buffer, blkno))
+ goto fail;
+
+ read_buffer = read_buffer + blkoff;
+ inode_buffer = (struct ext2_inode *)read_buffer;
+ memset(inode_buffer, '\0', sizeof(struct ext2_inode));
+
+ /* write the inode to original position in inode table */
+ if (ext4fs_put_metadata(start_block_address, blkno))
+ goto fail;
+
+ /* update the respective inode bitmaps */
+ inodeno++;
+ ext4fs_reset_inode_bmap(inodeno, fs->inode_bmaps[ibmap_idx], ibmap_idx);
+ bgd[ibmap_idx].free_inodes++;
+ fs->sb->free_inodes++;
+ /* journal backup */
+ memset(journal_buffer, '\0', fs->blksz);
+ status = ext4fs_devread(bgd[ibmap_idx].inode_id *
+ fs->sect_perblk, 0, fs->blksz, journal_buffer);
+ if (status == 0)
+ goto fail;
+ if (ext4fs_log_journal(journal_buffer, bgd[ibmap_idx].inode_id))
+ goto fail;
+
+ ext4fs_update();
+ ext4fs_deinit();
+
+ if (ext4fs_init() != 0) {
+ printf("error in File System init\n");
+ goto fail;
+ }
+
+ free(start_block_address);
+ free(journal_buffer);
+
+ return 0;
+fail:
+ free(start_block_address);
+ free(journal_buffer);
+
+ return -1;
+}
+
+int ext4fs_init(void)
+{
+ short status;
+ int i;
+ unsigned int real_free_blocks = 0;
+ struct ext_filesystem *fs = get_fs();
+
+ /* populate fs */
+ fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root);
+ fs->inodesz = INODE_SIZE_FILESYSTEM(ext4fs_root);
+ fs->sect_perblk = fs->blksz / SECTOR_SIZE;
+
+ /* get the superblock */
+ fs->sb = zalloc(SUPERBLOCK_SIZE);
+ if (!fs->sb)
+ return -ENOMEM;
+ if (!ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE,
+ (char *)fs->sb))
+ goto fail;
+
+ /* init journal */
+ if (ext4fs_init_journal())
+ goto fail;
+
+ /* get total no of blockgroups */
+ fs->no_blkgrp = (uint32_t)ext4fs_div_roundup(
+ (ext4fs_root->sblock.total_blocks -
+ ext4fs_root->sblock.first_data_block),
+ ext4fs_root->sblock.blocks_per_group);
+
+ /* get the block group descriptor table */
+ fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1);
+ if (ext4fs_get_bgdtable() == -1) {
+ printf("Error in getting the block group descriptor table\n");
+ goto fail;
+ }
+ fs->bgd = (struct ext2_block_group *)fs->gdtable;
+
+ /* load all the available bitmap block of the partition */
+ fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *));
+ if (!fs->blk_bmaps)
+ goto fail;
+ for (i = 0; i < fs->no_blkgrp; i++) {
+ fs->blk_bmaps[i] = zalloc(fs->blksz);
+ if (!fs->blk_bmaps[i])
+ goto fail;
+ }
+
+ for (i = 0; i < fs->no_blkgrp; i++) {
+ status =
+ ext4fs_devread(fs->bgd[i].block_id * fs->sect_perblk, 0,
+ fs->blksz, (char *)fs->blk_bmaps[i]);
+ if (status == 0)
+ goto fail;
+ }
+
+ /* load all the available inode bitmap of the partition */
+ fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *));
+ if (!fs->inode_bmaps)
+ goto fail;
+ for (i = 0; i < fs->no_blkgrp; i++) {
+ fs->inode_bmaps[i] = zalloc(fs->blksz);
+ if (!fs->inode_bmaps[i])
+ goto fail;
+ }
+
+ for (i = 0; i < fs->no_blkgrp; i++) {
+ status = ext4fs_devread(fs->bgd[i].inode_id * fs->sect_perblk,
+ 0, fs->blksz,
+ (char *)fs->inode_bmaps[i]);
+ if (status == 0)
+ goto fail;
+ }
+
+ /*
+ * check filesystem consistency with free blocks of file system
+ * some time we observed that superblock freeblocks does not match
+ * with the blockgroups freeblocks when improper
+ * reboot of a linux kernel
+ */
+ for (i = 0; i < fs->no_blkgrp; i++)
+ real_free_blocks = real_free_blocks + fs->bgd[i].free_blocks;
+ if (real_free_blocks != fs->sb->free_blocks)
+ fs->sb->free_blocks = real_free_blocks;
+
+ return 0;
+fail:
+ ext4fs_deinit();
+
+ return -1;
+}
+
+void ext4fs_deinit(void)
+{
+ int i;
+ struct ext2_inode inode_journal;
+ struct journal_superblock_t *jsb;
+ long int blknr;
+ struct ext_filesystem *fs = get_fs();
+
+ /* free journal */
+ char *temp_buff = zalloc(fs->blksz);
+ if (temp_buff) {
+ ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
+ &inode_journal);
+ blknr = read_allocated_block(&inode_journal,
+ EXT2_JOURNAL_SUPERBLOCK);
+ ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
+ temp_buff);
+ jsb = (struct journal_superblock_t *)temp_buff;
+ jsb->s_start = cpu_to_be32(0);
+ put_ext4((uint64_t) (blknr * fs->blksz),
+ (struct journal_superblock_t *)temp_buff, fs->blksz);
+ free(temp_buff);
+ }
+ ext4fs_free_journal();
+
+ /* get the superblock */
+ ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE, (char *)fs->sb);
+ fs->sb->feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
+ put_ext4((uint64_t)(SUPERBLOCK_SIZE),
+ (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
+ free(fs->sb);
+ fs->sb = NULL;
+
+ if (fs->blk_bmaps) {
+ for (i = 0; i < fs->no_blkgrp; i++) {
+ free(fs->blk_bmaps[i]);
+ fs->blk_bmaps[i] = NULL;
+ }
+ free(fs->blk_bmaps);
+ fs->blk_bmaps = NULL;
+ }
+
+ if (fs->inode_bmaps) {
+ for (i = 0; i < fs->no_blkgrp; i++) {
+ free(fs->inode_bmaps[i]);
+ fs->inode_bmaps[i] = NULL;
+ }
+ free(fs->inode_bmaps);
+ fs->inode_bmaps = NULL;
+ }
+
+
+ free(fs->gdtable);
+ fs->gdtable = NULL;
+ fs->bgd = NULL;
+ /*
+ * reinitiliazed the global inode and
+ * block bitmap first execution check variables
+ */
+ fs->first_pass_ibmap = 0;
+ fs->first_pass_bbmap = 0;
+ fs->curr_inode_no = 0;
+ fs->curr_blkno = 0;
+}
+
+static int ext4fs_write_file(struct ext2_inode *file_inode,
+ int pos, unsigned int len, char *buf)
+{
+ int i;
+ int blockcnt;
+ int log2blocksize = LOG2_EXT2_BLOCK_SIZE(ext4fs_root);
+ unsigned int filesize = __le32_to_cpu(file_inode->size);
+ struct ext_filesystem *fs = get_fs();
+ int previous_block_number = -1;
+ int delayed_start = 0;
+ int delayed_extent = 0;
+ int delayed_next = 0;
+ char *delayed_buf = NULL;
+
+ /* Adjust len so it we can't read past the end of the file. */
+ if (len > filesize)
+ len = filesize;
+
+ blockcnt = ((len + pos) + fs->blksz - 1) / fs->blksz;
+
+ for (i = pos / fs->blksz; i < blockcnt; i++) {
+ long int blknr;
+ int blockend = fs->blksz;
+ int skipfirst = 0;
+ blknr = read_allocated_block(file_inode, i);
+ if (blknr < 0)
+ return -1;
+
+ blknr = blknr << log2blocksize;
+
+ if (blknr) {
+ if (previous_block_number != -1) {
+ if (delayed_next == blknr) {
+ delayed_extent += blockend;
+ delayed_next += blockend >> SECTOR_BITS;
+ } else { /* spill */
+ put_ext4((uint64_t) (delayed_start *
+ SECTOR_SIZE),
+ delayed_buf,
+ (uint32_t) delayed_extent);
+ previous_block_number = blknr;
+ delayed_start = blknr;
+ delayed_extent = blockend;
+ delayed_buf = buf;
+ delayed_next = blknr +
+ (blockend >> SECTOR_BITS);
+ }
+ } else {
+ previous_block_number = blknr;
+ delayed_start = blknr;
+ delayed_extent = blockend;
+ delayed_buf = buf;
+ delayed_next = blknr +
+ (blockend >> SECTOR_BITS);
+ }
+ } else {
+ if (previous_block_number != -1) {
+ /* spill */
+ put_ext4((uint64_t) (delayed_start *
+ SECTOR_SIZE), delayed_buf,
+ (uint32_t) delayed_extent);
+ previous_block_number = -1;
+ }
+ memset(buf, 0, fs->blksz - skipfirst);
+ }
+ buf += fs->blksz - skipfirst;
+ }
+ if (previous_block_number != -1) {
+ /* spill */
+ put_ext4((uint64_t) (delayed_start * SECTOR_SIZE),
+ delayed_buf, (uint32_t) delayed_extent);
+ previous_block_number = -1;
+ }
+
+ return len;
+}
+
+int ext4fs_write(const char *fname, unsigned char *buffer,
+ unsigned long sizebytes)
+{
+ int ret = 0;
+ struct ext2_inode *file_inode = NULL;
+ unsigned char *inode_buffer = NULL;
+ int parent_inodeno;
+ int inodeno;
+ time_t timestamp = 0;
+
+ uint64_t bytes_reqd_for_file;
+ unsigned int blks_reqd_for_file;
+ unsigned int blocks_remaining;
+ int existing_file_inodeno;
+ char *temp_ptr = NULL;
+ long int itable_blkno;
+ long int parent_itable_blkno;
+ long int blkoff;
+ struct ext2_sblock *sblock = &(ext4fs_root->sblock);
+ unsigned int inodes_per_block;
+ unsigned int ibmap_idx;
+ struct ext_filesystem *fs = get_fs();
+ ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256);
+ memset(filename, 0x00, sizeof(filename));
+
+ g_parent_inode = zalloc(sizeof(struct ext2_inode));
+ if (!g_parent_inode)
+ goto fail;
+
+ if (ext4fs_init() != 0) {
+ printf("error in File System init\n");
+ return -1;
+ }
+ inodes_per_block = fs->blksz / fs->inodesz;
+ parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE);
+ if (parent_inodeno == -1)
+ goto fail;
+ if (ext4fs_iget(parent_inodeno, g_parent_inode))
+ goto fail;
+ /* check if the filename is already present in root */
+ existing_file_inodeno = ext4fs_filename_check(filename);
+ if (existing_file_inodeno != -1) {
+ ret = ext4fs_delete_file(existing_file_inodeno);
+ fs->first_pass_bbmap = 0;
+ fs->curr_blkno = 0;
+
+ fs->first_pass_ibmap = 0;
+ fs->curr_inode_no = 0;
+ if (ret)
+ goto fail;
+ }
+ /* calucalate how many blocks required */
+ bytes_reqd_for_file = sizebytes;
+ blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz);
+ if (do_div(bytes_reqd_for_file, fs->blksz) != 0) {
+ blks_reqd_for_file++;
+ debug("total bytes for a file %u\n", blks_reqd_for_file);
+ }
+ blocks_remaining = blks_reqd_for_file;
+ /* test for available space in partition */
+ if (fs->sb->free_blocks < blks_reqd_for_file) {
+ printf("Not enough space on partition !!!\n");
+ goto fail;
+ }
+
+ ext4fs_update_parent_dentry(filename, &inodeno, FILETYPE_REG);
+ /* prepare file inode */
+ inode_buffer = zalloc(fs->inodesz);
+ if (!inode_buffer)
+ goto fail;
+ file_inode = (struct ext2_inode *)inode_buffer;
+ file_inode->mode = S_IFREG | S_IRWXU |
+ S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH;
+ /* ToDo: Update correct time */
+ file_inode->mtime = timestamp;
+ file_inode->atime = timestamp;
+ file_inode->ctime = timestamp;
+ file_inode->nlinks = 1;
+ file_inode->size = sizebytes;
+
+ /* Allocate data blocks */
+ ext4fs_allocate_blocks(file_inode, blocks_remaining,
+ &blks_reqd_for_file);
+ file_inode->blockcnt = (blks_reqd_for_file * fs->blksz) / SECTOR_SIZE;
+
+ temp_ptr = zalloc(fs->blksz);
+ if (!temp_ptr)
+ goto fail;
+ ibmap_idx = inodeno / ext4fs_root->sblock.inodes_per_group;
+ inodeno--;
+ itable_blkno = __le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
+ (inodeno % __le32_to_cpu(sblock->inodes_per_group)) /
+ inodes_per_block;
+ blkoff = (inodeno % inodes_per_block) * fs->inodesz;
+ ext4fs_devread(itable_blkno * fs->sect_perblk, 0, fs->blksz, temp_ptr);
+ if (ext4fs_log_journal(temp_ptr, itable_blkno))
+ goto fail;
+
+ memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz);
+ if (ext4fs_put_metadata(temp_ptr, itable_blkno))
+ goto fail;
+ /* copy the file content into data blocks */
+ if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) {
+ printf("Error in copying content\n");
+ goto fail;
+ }
+ ibmap_idx = parent_inodeno / ext4fs_root->sblock.inodes_per_group;
+ parent_inodeno--;
+ parent_itable_blkno = __le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
+ (parent_inodeno %
+ __le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
+ blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz;
+ if (parent_itable_blkno != itable_blkno) {
+ memset(temp_ptr, '\0', fs->blksz);
+ ext4fs_devread(parent_itable_blkno * fs->sect_perblk,
+ 0, fs->blksz, temp_ptr);
+ if (ext4fs_log_journal(temp_ptr, parent_itable_blkno))
+ goto fail;
+
+ memcpy(temp_ptr + blkoff, g_parent_inode,
+ sizeof(struct ext2_inode));
+ if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno))
+ goto fail;
+ free(temp_ptr);
+ } else {
+ /*
+ * If parent and child fall in same inode table block
+ * both should be kept in 1 buffer
+ */
+ memcpy(temp_ptr + blkoff, g_parent_inode,
+ sizeof(struct ext2_inode));
+ gd_index--;
+ if (ext4fs_put_metadata(temp_ptr, itable_blkno))
+ goto fail;
+ free(temp_ptr);
+ }
+ ext4fs_update();
+ ext4fs_deinit();
+
+ fs->first_pass_bbmap = 0;
+ fs->curr_blkno = 0;
+ fs->first_pass_ibmap = 0;
+ fs->curr_inode_no = 0;
+ free(inode_buffer);
+ free(g_parent_inode);
+ g_parent_inode = NULL;
+
+ return 0;
+fail:
+ ext4fs_deinit();
+ free(inode_buffer);
+ free(g_parent_inode);
+ g_parent_inode = NULL;
+
+ return -1;
+}
diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c
index f02c215ccc..4dddde2476 100644
--- a/fs/ext4/ext4fs.c
+++ b/fs/ext4/ext4fs.c
@@ -34,13 +34,8 @@
*/
#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 <div64.h>
#include "ext4_common.h"
int ext4fs_symlinknest;
@@ -197,960 +192,39 @@ int ext4fs_read(char *buf, unsigned len)
return ext4fs_read_file(ext4fs_file, 0, len, buf);
}
-#if defined(CONFIG_EXT4_WRITE)
-static void ext4fs_update(void)
+int ext4fs_probe(block_dev_desc_t *fs_dev_desc,
+ disk_partition_t *fs_partition)
{
- short i;
- ext4fs_update_journal();
- struct ext_filesystem *fs = get_fs();
+ ext4fs_set_blk_dev(fs_dev_desc, fs_partition);
- /* update super block */
- put_ext4((uint64_t)(SUPERBLOCK_SIZE),
- (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
-
- /* update block groups */
- for (i = 0; i < fs->no_blkgrp; i++) {
- fs->bgd[i].bg_checksum = ext4fs_checksum_update(i);
- put_ext4((uint64_t)(fs->bgd[i].block_id * fs->blksz),
- fs->blk_bmaps[i], fs->blksz);
- }
-
- /* update inode table groups */
- for (i = 0; i < fs->no_blkgrp; i++) {
- put_ext4((uint64_t) (fs->bgd[i].inode_id * fs->blksz),
- fs->inode_bmaps[i], fs->blksz);
- }
-
- /* update the block group descriptor table */
- put_ext4((uint64_t)(fs->gdtable_blkno * fs->blksz),
- (struct ext2_block_group *)fs->gdtable,
- (fs->blksz * fs->no_blk_pergdt));
-
- ext4fs_dump_metadata();
-
- gindex = 0;
- gd_index = 0;
-}
-
-int ext4fs_get_bgdtable(void)
-{
- int status;
- int grp_desc_size;
- struct ext_filesystem *fs = get_fs();
- grp_desc_size = sizeof(struct ext2_block_group);
- fs->no_blk_pergdt = (fs->no_blkgrp * grp_desc_size) / fs->blksz;
- if ((fs->no_blkgrp * grp_desc_size) % fs->blksz)
- fs->no_blk_pergdt++;
-
- /* allocate memory for gdtable */
- fs->gdtable = zalloc(fs->blksz * fs->no_blk_pergdt);
- if (!fs->gdtable)
- return -ENOMEM;
- /* read the group descriptor table */
- status = ext4fs_devread(fs->gdtable_blkno * fs->sect_perblk, 0,
- fs->blksz * fs->no_blk_pergdt, fs->gdtable);
- if (status == 0)
- goto fail;
-
- if (ext4fs_log_gdt(fs->gdtable)) {
- printf("Error in ext4fs_log_gdt\n");
+ if (!ext4fs_mount(fs_partition->size)) {
+ ext4fs_close();
return -1;
}
return 0;
-fail:
- free(fs->gdtable);
- fs->gdtable = NULL;
-
- return -1;
-}
-
-static void delete_single_indirect_block(struct ext2_inode *inode)
-{
- struct ext2_block_group *bgd = NULL;
- static int prev_bg_bmap_idx = -1;
- long int blknr;
- int remainder;
- int bg_idx;
- int status;
- unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
- struct ext_filesystem *fs = get_fs();
- char *journal_buffer = zalloc(fs->blksz);
- if (!journal_buffer) {
- printf("No memory\n");
- return;
- }
- /* get block group descriptor table */
- bgd = (struct ext2_block_group *)fs->gdtable;
-
- /* deleting the single indirect block associated with inode */
- if (inode->b.blocks.indir_block != 0) {
- debug("SIPB releasing %u\n", inode->b.blocks.indir_block);
- blknr = inode->b.blocks.indir_block;
- if (fs->blksz != 1024) {
- bg_idx = blknr / blk_per_grp;
- } else {
- bg_idx = blknr / blk_per_grp;
- remainder = blknr % blk_per_grp;
- if (!remainder)
- bg_idx--;
- }
- ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
- bgd[bg_idx].free_blocks++;
- fs->sb->free_blocks++;
- /* journal backup */
- if (prev_bg_bmap_idx != bg_idx) {
- status =
- ext4fs_devread(bgd[bg_idx].block_id *
- fs->sect_perblk, 0, fs->blksz,
- journal_buffer);
- if (status == 0)
- goto fail;
- if (ext4fs_log_journal
- (journal_buffer, bgd[bg_idx].block_id))
- goto fail;
- prev_bg_bmap_idx = bg_idx;
- }
- }
-fail:
- free(journal_buffer);
-}
-
-static void delete_double_indirect_block(struct ext2_inode *inode)
-{
- int i;
- short status;
- static int prev_bg_bmap_idx = -1;
- long int blknr;
- int remainder;
- int bg_idx;
- unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
- unsigned int *di_buffer = NULL;
- unsigned int *DIB_start_addr = NULL;
- struct ext2_block_group *bgd = NULL;
- struct ext_filesystem *fs = get_fs();
- char *journal_buffer = zalloc(fs->blksz);
- if (!journal_buffer) {
- printf("No memory\n");
- return;
- }
- /* get the block group descriptor table */
- bgd = (struct ext2_block_group *)fs->gdtable;
-
- if (inode->b.blocks.double_indir_block != 0) {
- di_buffer = zalloc(fs->blksz);
- if (!di_buffer) {
- printf("No memory\n");
- return;
- }
- DIB_start_addr = (unsigned int *)di_buffer;
- blknr = inode->b.blocks.double_indir_block;
- status = ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
- (char *)di_buffer);
- for (i = 0; i < fs->blksz / sizeof(int); i++) {
- if (*di_buffer == 0)
- break;
-
- debug("DICB releasing %u\n", *di_buffer);
- if (fs->blksz != 1024) {
- bg_idx = (*di_buffer) / blk_per_grp;
- } else {
- bg_idx = (*di_buffer) / blk_per_grp;
- remainder = (*di_buffer) % blk_per_grp;
- if (!remainder)
- bg_idx--;
- }
- ext4fs_reset_block_bmap(*di_buffer,
- fs->blk_bmaps[bg_idx], bg_idx);
- di_buffer++;
- bgd[bg_idx].free_blocks++;
- fs->sb->free_blocks++;
- /* journal backup */
- if (prev_bg_bmap_idx != bg_idx) {
- status = ext4fs_devread(bgd[bg_idx].block_id
- * fs->sect_perblk, 0,
- fs->blksz,
- journal_buffer);
- if (status == 0)
- goto fail;
-
- if (ext4fs_log_journal(journal_buffer,
- bgd[bg_idx].block_id))
- goto fail;
- prev_bg_bmap_idx = bg_idx;
- }
- }
-
- /* removing the parent double indirect block */
- blknr = inode->b.blocks.double_indir_block;
- if (fs->blksz != 1024) {
- bg_idx = blknr / blk_per_grp;
- } else {
- bg_idx = blknr / blk_per_grp;
- remainder = blknr % blk_per_grp;
- if (!remainder)
- bg_idx--;
- }
- ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
- bgd[bg_idx].free_blocks++;
- fs->sb->free_blocks++;
- /* journal backup */
- if (prev_bg_bmap_idx != bg_idx) {
- memset(journal_buffer, '\0', fs->blksz);
- status = ext4fs_devread(bgd[bg_idx].block_id *
- fs->sect_perblk, 0, fs->blksz,
- journal_buffer);
- if (status == 0)
- goto fail;
-
- if (ext4fs_log_journal(journal_buffer,
- bgd[bg_idx].block_id))
- goto fail;
- prev_bg_bmap_idx = bg_idx;
- }
- debug("DIPB releasing %ld\n", blknr);
- }
-fail:
- free(DIB_start_addr);
- free(journal_buffer);
-}
-
-static void delete_triple_indirect_block(struct ext2_inode *inode)
-{
- int i, j;
- short status;
- static int prev_bg_bmap_idx = -1;
- long int blknr;
- int remainder;
- int bg_idx;
- unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
- unsigned int *tigp_buffer = NULL;
- unsigned int *tib_start_addr = NULL;
- unsigned int *tip_buffer = NULL;
- unsigned int *tipb_start_addr = NULL;
- struct ext2_block_group *bgd = NULL;
- struct ext_filesystem *fs = get_fs();
- char *journal_buffer = zalloc(fs->blksz);
- if (!journal_buffer) {
- printf("No memory\n");
- return;
- }
- /* get block group descriptor table */
- bgd = (struct ext2_block_group *)fs->gdtable;
-
- if (inode->b.blocks.triple_indir_block != 0) {
- tigp_buffer = zalloc(fs->blksz);
- if (!tigp_buffer) {
- printf("No memory\n");
- return;
- }
- tib_start_addr = (unsigned int *)tigp_buffer;
- blknr = inode->b.blocks.triple_indir_block;
- status = ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
- (char *)tigp_buffer);
- for (i = 0; i < fs->blksz / sizeof(int); i++) {
- if (*tigp_buffer == 0)
- break;
- debug("tigp buffer releasing %u\n", *tigp_buffer);
-
- tip_buffer = zalloc(fs->blksz);
- if (!tip_buffer)
- goto fail;
- tipb_start_addr = (unsigned int *)tip_buffer;
- status = ext4fs_devread((*tigp_buffer) *
- fs->sect_perblk, 0, fs->blksz,
- (char *)tip_buffer);
- for (j = 0; j < fs->blksz / sizeof(int); j++) {
- if (*tip_buffer == 0)
- break;
- if (fs->blksz != 1024) {
- bg_idx = (*tip_buffer) / blk_per_grp;
- } else {
- bg_idx = (*tip_buffer) / blk_per_grp;
-
- remainder = (*tip_buffer) % blk_per_grp;
- if (!remainder)
- bg_idx--;
- }
-
- ext4fs_reset_block_bmap(*tip_buffer,
- fs->blk_bmaps[bg_idx],
- bg_idx);
-
- tip_buffer++;
- bgd[bg_idx].free_blocks++;
- fs->sb->free_blocks++;
- /* journal backup */
- if (prev_bg_bmap_idx != bg_idx) {
- status =
- ext4fs_devread(
- bgd[bg_idx].block_id *
- fs->sect_perblk, 0,
- fs->blksz,
- journal_buffer);
- if (status == 0)
- goto fail;
-
- if (ext4fs_log_journal(journal_buffer,
- bgd[bg_idx].
- block_id))
- goto fail;
- prev_bg_bmap_idx = bg_idx;
- }
- }
- free(tipb_start_addr);
- tipb_start_addr = NULL;
-
- /*
- * removing the grand parent blocks
- * which is connected to inode
- */
- if (fs->blksz != 1024) {
- bg_idx = (*tigp_buffer) / blk_per_grp;
- } else {
- bg_idx = (*tigp_buffer) / blk_per_grp;
-
- remainder = (*tigp_buffer) % blk_per_grp;
- if (!remainder)
- bg_idx--;
- }
- ext4fs_reset_block_bmap(*tigp_buffer,
- fs->blk_bmaps[bg_idx], bg_idx);
-
- tigp_buffer++;
- bgd[bg_idx].free_blocks++;
- fs->sb->free_blocks++;
- /* journal backup */
- if (prev_bg_bmap_idx != bg_idx) {
- memset(journal_buffer, '\0', fs->blksz);
- status =
- ext4fs_devread(bgd[bg_idx].block_id *
- fs->sect_perblk, 0,
- fs->blksz, journal_buffer);
- if (status == 0)
- goto fail;
-
- if (ext4fs_log_journal(journal_buffer,
- bgd[bg_idx].block_id))
- goto fail;
- prev_bg_bmap_idx = bg_idx;
- }
- }
-
- /* removing the grand parent triple indirect block */
- blknr = inode->b.blocks.triple_indir_block;
- if (fs->blksz != 1024) {
- bg_idx = blknr / blk_per_grp;
- } else {
- bg_idx = blknr / blk_per_grp;
- remainder = blknr % blk_per_grp;
- if (!remainder)
- bg_idx--;
- }
- ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
- bgd[bg_idx].free_blocks++;
- fs->sb->free_blocks++;
- /* journal backup */
- if (prev_bg_bmap_idx != bg_idx) {
- memset(journal_buffer, '\0', fs->blksz);
- status = ext4fs_devread(bgd[bg_idx].block_id *
- fs->sect_perblk, 0, fs->blksz,
- journal_buffer);
- if (status == 0)
- goto fail;
-
- if (ext4fs_log_journal(journal_buffer,
- bgd[bg_idx].block_id))
- goto fail;
- prev_bg_bmap_idx = bg_idx;
- }
- debug("tigp buffer itself releasing %ld\n", blknr);
- }
-fail:
- free(tib_start_addr);
- free(tipb_start_addr);
- free(journal_buffer);
-}
-
-static int ext4fs_delete_file(int inodeno)
-{
- struct ext2_inode inode;
- short status;
- int i;
- int remainder;
- long int blknr;
- int bg_idx;
- int ibmap_idx;
- char *read_buffer = NULL;
- char *start_block_address = NULL;
- unsigned int no_blocks;
-
- static int prev_bg_bmap_idx = -1;
- unsigned int inodes_per_block;
- long int blkno;
- unsigned int blkoff;
- unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
- unsigned int inode_per_grp = ext4fs_root->sblock.inodes_per_group;
- struct ext2_inode *inode_buffer = NULL;
- struct ext2_block_group *bgd = NULL;
- struct ext_filesystem *fs = get_fs();
- char *journal_buffer = zalloc(fs->blksz);
- if (!journal_buffer)
- return -ENOMEM;
- /* get the block group descriptor table */
- bgd = (struct ext2_block_group *)fs->gdtable;
- status = ext4fs_read_inode(ext4fs_root, inodeno, &inode);
- if (status == 0)
- goto fail;
-
- /* read the block no allocated to a file */
- no_blocks = inode.size / fs->blksz;
- if (inode.size % fs->blksz)
- no_blocks++;
-
- if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FL) {
- struct ext2fs_node *node_inode =
- zalloc(sizeof(struct ext2fs_node));
- if (!node_inode)
- goto fail;
- node_inode->data = ext4fs_root;
- node_inode->ino = inodeno;
- node_inode->inode_read = 0;
- memcpy(&(node_inode->inode), &inode, sizeof(struct ext2_inode));
-
- for (i = 0; i < no_blocks; i++) {
- blknr = read_allocated_block(&(node_inode->inode), i);
- if (fs->blksz != 1024) {
- bg_idx = blknr / blk_per_grp;
- } else {
- bg_idx = blknr / blk_per_grp;
- remainder = blknr % blk_per_grp;
- if (!remainder)
- bg_idx--;
- }
- ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx],
- bg_idx);
- debug("EXT4_EXTENTS Block releasing %ld: %d\n",
- blknr, bg_idx);
-
- bgd[bg_idx].free_blocks++;
- fs->sb->free_blocks++;
-
- /* journal backup */
- if (prev_bg_bmap_idx != bg_idx) {
- status =
- ext4fs_devread(bgd[bg_idx].block_id *
- fs->sect_perblk, 0,
- fs->blksz, journal_buffer);
- if (status == 0)
- goto fail;
- if (ext4fs_log_journal(journal_buffer,
- bgd[bg_idx].block_id))
- goto fail;
- prev_bg_bmap_idx = bg_idx;
- }
- }
- if (node_inode) {
- free(node_inode);
- node_inode = NULL;
- }
- } else {
-
- delete_single_indirect_block(&inode);
- delete_double_indirect_block(&inode);
- delete_triple_indirect_block(&inode);
-
- /* read the block no allocated to a file */
- no_blocks = inode.size / fs->blksz;
- if (inode.size % fs->blksz)
- no_blocks++;
- for (i = 0; i < no_blocks; i++) {
- blknr = read_allocated_block(&inode, i);
- if (fs->blksz != 1024) {
- bg_idx = blknr / blk_per_grp;
- } else {
- bg_idx = blknr / blk_per_grp;
- remainder = blknr % blk_per_grp;
- if (!remainder)
- bg_idx--;
- }
- ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx],
- bg_idx);
- debug("ActualB releasing %ld: %d\n", blknr, bg_idx);
-
- bgd[bg_idx].free_blocks++;
- fs->sb->free_blocks++;
- /* journal backup */
- if (prev_bg_bmap_idx != bg_idx) {
- memset(journal_buffer, '\0', fs->blksz);
- status = ext4fs_devread(bgd[bg_idx].block_id
- * fs->sect_perblk,
- 0, fs->blksz,
- journal_buffer);
- if (status == 0)
- goto fail;
- if (ext4fs_log_journal(journal_buffer,
- bgd[bg_idx].block_id))
- goto fail;
- prev_bg_bmap_idx = bg_idx;
- }
- }
- }
-
- /* from the inode no to blockno */
- inodes_per_block = fs->blksz / fs->inodesz;
- ibmap_idx = inodeno / inode_per_grp;
-
- /* get the block no */
- inodeno--;
- blkno = __le32_to_cpu(bgd[ibmap_idx].inode_table_id) +
- (inodeno % __le32_to_cpu(inode_per_grp)) / inodes_per_block;
-
- /* get the offset of the inode */
- blkoff = ((inodeno) % inodes_per_block) * fs->inodesz;
-
- /* read the block no containing the inode */
- read_buffer = zalloc(fs->blksz);
- if (!read_buffer)
- goto fail;
- start_block_address = read_buffer;
- status = ext4fs_devread(blkno * fs->sect_perblk,
- 0, fs->blksz, read_buffer);
- if (status == 0)
- goto fail;
-
- if (ext4fs_log_journal(read_buffer, blkno))
- goto fail;
-
- read_buffer = read_buffer + blkoff;
- inode_buffer = (struct ext2_inode *)read_buffer;
- memset(inode_buffer, '\0', sizeof(struct ext2_inode));
-
- /* write the inode to original position in inode table */
- if (ext4fs_put_metadata(start_block_address, blkno))
- goto fail;
-
- /* update the respective inode bitmaps */
- inodeno++;
- ext4fs_reset_inode_bmap(inodeno, fs->inode_bmaps[ibmap_idx], ibmap_idx);
- bgd[ibmap_idx].free_inodes++;
- fs->sb->free_inodes++;
- /* journal backup */
- memset(journal_buffer, '\0', fs->blksz);
- status = ext4fs_devread(bgd[ibmap_idx].inode_id *
- fs->sect_perblk, 0, fs->blksz, journal_buffer);
- if (status == 0)
- goto fail;
- if (ext4fs_log_journal(journal_buffer, bgd[ibmap_idx].inode_id))
- goto fail;
-
- ext4fs_update();
- ext4fs_deinit();
-
- if (ext4fs_init() != 0) {
- printf("error in File System init\n");
- goto fail;
- }
-
- free(start_block_address);
- free(journal_buffer);
-
- return 0;
-fail:
- free(start_block_address);
- free(journal_buffer);
-
- return -1;
-}
-
-int ext4fs_init(void)
-{
- short status;
- int i;
- unsigned int real_free_blocks = 0;
- struct ext_filesystem *fs = get_fs();
-
- /* populate fs */
- fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root);
- fs->inodesz = INODE_SIZE_FILESYSTEM(ext4fs_root);
- fs->sect_perblk = fs->blksz / SECTOR_SIZE;
-
- /* get the superblock */
- fs->sb = zalloc(SUPERBLOCK_SIZE);
- if (!fs->sb)
- return -ENOMEM;
- if (!ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE,
- (char *)fs->sb))
- goto fail;
-
- /* init journal */
- if (ext4fs_init_journal())
- goto fail;
-
- /* get total no of blockgroups */
- fs->no_blkgrp = (uint32_t)ext4fs_div_roundup(
- (ext4fs_root->sblock.total_blocks -
- ext4fs_root->sblock.first_data_block),
- ext4fs_root->sblock.blocks_per_group);
-
- /* get the block group descriptor table */
- fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1);
- if (ext4fs_get_bgdtable() == -1) {
- printf("Error in getting the block group descriptor table\n");
- goto fail;
- }
- fs->bgd = (struct ext2_block_group *)fs->gdtable;
-
- /* load all the available bitmap block of the partition */
- fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *));
- if (!fs->blk_bmaps)
- goto fail;
- for (i = 0; i < fs->no_blkgrp; i++) {
- fs->blk_bmaps[i] = zalloc(fs->blksz);
- if (!fs->blk_bmaps[i])
- goto fail;
- }
-
- for (i = 0; i < fs->no_blkgrp; i++) {
- status =
- ext4fs_devread(fs->bgd[i].block_id * fs->sect_perblk, 0,
- fs->blksz, (char *)fs->blk_bmaps[i]);
- if (status == 0)
- goto fail;
- }
-
- /* load all the available inode bitmap of the partition */
- fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *));
- if (!fs->inode_bmaps)
- goto fail;
- for (i = 0; i < fs->no_blkgrp; i++) {
- fs->inode_bmaps[i] = zalloc(fs->blksz);
- if (!fs->inode_bmaps[i])
- goto fail;
- }
-
- for (i = 0; i < fs->no_blkgrp; i++) {
- status = ext4fs_devread(fs->bgd[i].inode_id * fs->sect_perblk,
- 0, fs->blksz,
- (char *)fs->inode_bmaps[i]);
- if (status == 0)
- goto fail;
- }
-
- /*
- * check filesystem consistency with free blocks of file system
- * some time we observed that superblock freeblocks does not match
- * with the blockgroups freeblocks when improper
- * reboot of a linux kernel
- */
- for (i = 0; i < fs->no_blkgrp; i++)
- real_free_blocks = real_free_blocks + fs->bgd[i].free_blocks;
- if (real_free_blocks != fs->sb->free_blocks)
- fs->sb->free_blocks = real_free_blocks;
-
- return 0;
-fail:
- ext4fs_deinit();
-
- return -1;
-}
-
-void ext4fs_deinit(void)
-{
- int i;
- struct ext2_inode inode_journal;
- struct journal_superblock_t *jsb;
- long int blknr;
- struct ext_filesystem *fs = get_fs();
-
- /* free journal */
- char *temp_buff = zalloc(fs->blksz);
- if (temp_buff) {
- ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
- &inode_journal);
- blknr = read_allocated_block(&inode_journal,
- EXT2_JOURNAL_SUPERBLOCK);
- ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
- temp_buff);
- jsb = (struct journal_superblock_t *)temp_buff;
- jsb->s_start = cpu_to_be32(0);
- put_ext4((uint64_t) (blknr * fs->blksz),
- (struct journal_superblock_t *)temp_buff, fs->blksz);
- free(temp_buff);
- }
- ext4fs_free_journal();
-
- /* get the superblock */
- ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE, (char *)fs->sb);
- fs->sb->feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
- put_ext4((uint64_t)(SUPERBLOCK_SIZE),
- (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
- free(fs->sb);
- fs->sb = NULL;
-
- if (fs->blk_bmaps) {
- for (i = 0; i < fs->no_blkgrp; i++) {
- free(fs->blk_bmaps[i]);
- fs->blk_bmaps[i] = NULL;
- }
- free(fs->blk_bmaps);
- fs->blk_bmaps = NULL;
- }
-
- if (fs->inode_bmaps) {
- for (i = 0; i < fs->no_blkgrp; i++) {
- free(fs->inode_bmaps[i]);
- fs->inode_bmaps[i] = NULL;
- }
- free(fs->inode_bmaps);
- fs->inode_bmaps = NULL;
- }
-
-
- free(fs->gdtable);
- fs->gdtable = NULL;
- fs->bgd = NULL;
- /*
- * reinitiliazed the global inode and
- * block bitmap first execution check variables
- */
- fs->first_pass_ibmap = 0;
- fs->first_pass_bbmap = 0;
- fs->curr_inode_no = 0;
- fs->curr_blkno = 0;
-}
-
-static int ext4fs_write_file(struct ext2_inode *file_inode,
- int pos, unsigned int len, char *buf)
-{
- int i;
- int blockcnt;
- int log2blocksize = LOG2_EXT2_BLOCK_SIZE(ext4fs_root);
- unsigned int filesize = __le32_to_cpu(file_inode->size);
- struct ext_filesystem *fs = get_fs();
- int previous_block_number = -1;
- int delayed_start = 0;
- int delayed_extent = 0;
- int delayed_next = 0;
- char *delayed_buf = NULL;
-
- /* Adjust len so it we can't read past the end of the file. */
- if (len > filesize)
- len = filesize;
-
- blockcnt = ((len + pos) + fs->blksz - 1) / fs->blksz;
-
- for (i = pos / fs->blksz; i < blockcnt; i++) {
- long int blknr;
- int blockend = fs->blksz;
- int skipfirst = 0;
- blknr = read_allocated_block(file_inode, i);
- if (blknr < 0)
- return -1;
-
- blknr = blknr << log2blocksize;
-
- if (blknr) {
- if (previous_block_number != -1) {
- if (delayed_next == blknr) {
- delayed_extent += blockend;
- delayed_next += blockend >> SECTOR_BITS;
- } else { /* spill */
- put_ext4((uint64_t) (delayed_start *
- SECTOR_SIZE),
- delayed_buf,
- (uint32_t) delayed_extent);
- previous_block_number = blknr;
- delayed_start = blknr;
- delayed_extent = blockend;
- delayed_buf = buf;
- delayed_next = blknr +
- (blockend >> SECTOR_BITS);
- }
- } else {
- previous_block_number = blknr;
- delayed_start = blknr;
- delayed_extent = blockend;
- delayed_buf = buf;
- delayed_next = blknr +
- (blockend >> SECTOR_BITS);
- }
- } else {
- if (previous_block_number != -1) {
- /* spill */
- put_ext4((uint64_t) (delayed_start *
- SECTOR_SIZE), delayed_buf,
- (uint32_t) delayed_extent);
- previous_block_number = -1;
- }
- memset(buf, 0, fs->blksz - skipfirst);
- }
- buf += fs->blksz - skipfirst;
- }
- if (previous_block_number != -1) {
- /* spill */
- put_ext4((uint64_t) (delayed_start * SECTOR_SIZE),
- delayed_buf, (uint32_t) delayed_extent);
- previous_block_number = -1;
- }
-
- return len;
}
-int ext4fs_write(const char *fname, unsigned char *buffer,
- unsigned long sizebytes)
+int ext4_read_file(const char *filename, void *buf, int offset, int len)
{
- int ret = 0;
- struct ext2_inode *file_inode = NULL;
- unsigned char *inode_buffer = NULL;
- int parent_inodeno;
- int inodeno;
- time_t timestamp = 0;
-
- uint64_t bytes_reqd_for_file;
- unsigned int blks_reqd_for_file;
- unsigned int blocks_remaining;
- int existing_file_inodeno;
- char *temp_ptr = NULL;
- long int itable_blkno;
- long int parent_itable_blkno;
- long int blkoff;
- struct ext2_sblock *sblock = &(ext4fs_root->sblock);
- unsigned int inodes_per_block;
- unsigned int ibmap_idx;
- struct ext_filesystem *fs = get_fs();
- ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256);
- memset(filename, 0x00, sizeof(filename));
+ int file_len;
+ int len_read;
- g_parent_inode = zalloc(sizeof(struct ext2_inode));
- if (!g_parent_inode)
- goto fail;
-
- if (ext4fs_init() != 0) {
- printf("error in File System init\n");
+ if (offset != 0) {
+ printf("** Cannot support non-zero offset **\n");
return -1;
}
- inodes_per_block = fs->blksz / fs->inodesz;
- parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE);
- if (parent_inodeno == -1)
- goto fail;
- if (ext4fs_iget(parent_inodeno, g_parent_inode))
- goto fail;
- /* check if the filename is already present in root */
- existing_file_inodeno = ext4fs_filename_check(filename);
- if (existing_file_inodeno != -1) {
- ret = ext4fs_delete_file(existing_file_inodeno);
- fs->first_pass_bbmap = 0;
- fs->curr_blkno = 0;
-
- fs->first_pass_ibmap = 0;
- fs->curr_inode_no = 0;
- if (ret)
- goto fail;
- }
- /* calucalate how many blocks required */
- bytes_reqd_for_file = sizebytes;
- blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz);
- if (do_div(bytes_reqd_for_file, fs->blksz) != 0) {
- blks_reqd_for_file++;
- debug("total bytes for a file %u\n", blks_reqd_for_file);
- }
- blocks_remaining = blks_reqd_for_file;
- /* test for available space in partition */
- if (fs->sb->free_blocks < blks_reqd_for_file) {
- printf("Not enough space on partition !!!\n");
- goto fail;
- }
- ext4fs_update_parent_dentry(filename, &inodeno, FILETYPE_REG);
- /* prepare file inode */
- inode_buffer = zalloc(fs->inodesz);
- if (!inode_buffer)
- goto fail;
- file_inode = (struct ext2_inode *)inode_buffer;
- file_inode->mode = S_IFREG | S_IRWXU |
- S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH;
- /* ToDo: Update correct time */
- file_inode->mtime = timestamp;
- file_inode->atime = timestamp;
- file_inode->ctime = timestamp;
- file_inode->nlinks = 1;
- file_inode->size = sizebytes;
-
- /* Allocate data blocks */
- ext4fs_allocate_blocks(file_inode, blocks_remaining,
- &blks_reqd_for_file);
- file_inode->blockcnt = (blks_reqd_for_file * fs->blksz) / SECTOR_SIZE;
-
- temp_ptr = zalloc(fs->blksz);
- if (!temp_ptr)
- goto fail;
- ibmap_idx = inodeno / ext4fs_root->sblock.inodes_per_group;
- inodeno--;
- itable_blkno = __le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
- (inodeno % __le32_to_cpu(sblock->inodes_per_group)) /
- inodes_per_block;
- blkoff = (inodeno % inodes_per_block) * fs->inodesz;
- ext4fs_devread(itable_blkno * fs->sect_perblk, 0, fs->blksz, temp_ptr);
- if (ext4fs_log_journal(temp_ptr, itable_blkno))
- goto fail;
-
- memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz);
- if (ext4fs_put_metadata(temp_ptr, itable_blkno))
- goto fail;
- /* copy the file content into data blocks */
- if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) {
- printf("Error in copying content\n");
- goto fail;
- }
- ibmap_idx = parent_inodeno / ext4fs_root->sblock.inodes_per_group;
- parent_inodeno--;
- parent_itable_blkno = __le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
- (parent_inodeno %
- __le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
- blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz;
- if (parent_itable_blkno != itable_blkno) {
- memset(temp_ptr, '\0', fs->blksz);
- ext4fs_devread(parent_itable_blkno * fs->sect_perblk,
- 0, fs->blksz, temp_ptr);
- if (ext4fs_log_journal(temp_ptr, parent_itable_blkno))
- goto fail;
-
- memcpy(temp_ptr + blkoff, g_parent_inode,
- sizeof(struct ext2_inode));
- if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno))
- goto fail;
- free(temp_ptr);
- } else {
- /*
- * If parent and child fall in same inode table block
- * both should be kept in 1 buffer
- */
- memcpy(temp_ptr + blkoff, g_parent_inode,
- sizeof(struct ext2_inode));
- gd_index--;
- if (ext4fs_put_metadata(temp_ptr, itable_blkno))
- goto fail;
- free(temp_ptr);
+ file_len = ext4fs_open(filename);
+ if (file_len < 0) {
+ printf("** File not found %s **\n", filename);
+ return -1;
}
- ext4fs_update();
- ext4fs_deinit();
- fs->first_pass_bbmap = 0;
- fs->curr_blkno = 0;
- fs->first_pass_ibmap = 0;
- fs->curr_inode_no = 0;
- free(inode_buffer);
- free(g_parent_inode);
- g_parent_inode = NULL;
+ if (len == 0)
+ len = file_len;
- return 0;
-fail:
- ext4fs_deinit();
- free(inode_buffer);
- free(g_parent_inode);
- g_parent_inode = NULL;
+ len_read = ext4fs_read(buf, len);
- return -1;
+ return len_read;
}
-#endif
diff --git a/fs/fat/fat.c b/fs/fat/fat.c
index 66d54738a0..b0fac5e1ed 100644
--- a/fs/fat/fat.c
+++ b/fs/fat/fat.c
@@ -1260,3 +1260,20 @@ long file_fat_read(const char *filename, void *buffer, unsigned long maxsize)
{
return file_fat_read_at(filename, 0, buffer, maxsize);
}
+
+int fat_read_file(const char *filename, void *buf, int offset, int len)
+{
+ int len_read;
+
+ len_read = file_fat_read_at(filename, offset, buf, len);
+ if (len_read == -1) {
+ printf("** Unable to read file %s **\n", filename);
+ return -1;
+ }
+
+ return len_read;
+}
+
+void fat_close(void)
+{
+}
diff --git a/fs/fs.c b/fs/fs.c
index 023e7ef16a..6f5063c3af 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -20,6 +20,8 @@
#include <ext4fs.h>
#include <fat.h>
#include <fs.h>
+#include <sandboxfs.h>
+#include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -27,145 +29,103 @@ static block_dev_desc_t *fs_dev_desc;
static disk_partition_t fs_partition;
static int fs_type = FS_TYPE_ANY;
-static inline int fs_ls_unsupported(const char *dirname)
+static inline int fs_probe_unsupported(block_dev_desc_t *fs_dev_desc,
+ disk_partition_t *fs_partition)
{
printf("** Unrecognized filesystem type **\n");
return -1;
}
-static inline int fs_read_unsupported(const char *filename, ulong addr,
- int offset, int len)
-{
- printf("** Unrecognized filesystem type **\n");
- return -1;
-}
-
-#ifdef CONFIG_FS_FAT
-static int fs_probe_fat(void)
-{
- return fat_set_blk_dev(fs_dev_desc, &fs_partition);
-}
-
-static void fs_close_fat(void)
-{
-}
-
-#define fs_ls_fat file_fat_ls
-
-static int fs_read_fat(const char *filename, ulong addr, int offset, int len)
-{
- int len_read;
-
- len_read = file_fat_read_at(filename, offset,
- (unsigned char *)addr, len);
- if (len_read == -1) {
- printf("** Unable to read file %s **\n", filename);
- return -1;
- }
-
- return len_read;
-}
-#else
-static inline int fs_probe_fat(void)
+static inline int fs_ls_unsupported(const char *dirname)
{
return -1;
}
-static inline void fs_close_fat(void)
-{
-}
-
-#define fs_ls_fat fs_ls_unsupported
-#define fs_read_fat fs_read_unsupported
-#endif
-
-#ifdef CONFIG_FS_EXT4
-static int fs_probe_ext(void)
-{
- ext4fs_set_blk_dev(fs_dev_desc, &fs_partition);
-
- if (!ext4fs_mount(fs_partition.size)) {
- ext4fs_close();
- return -1;
- }
-
- return 0;
-}
-
-static void fs_close_ext(void)
-{
- ext4fs_close();
-}
-
-#define fs_ls_ext ext4fs_ls
-
-static int fs_read_ext(const char *filename, ulong addr, int offset, int len)
-{
- int file_len;
- int len_read;
-
- if (offset != 0) {
- printf("** Cannot support non-zero offset **\n");
- return -1;
- }
-
- file_len = ext4fs_open(filename);
- if (file_len < 0) {
- printf("** File not found %s **\n", filename);
- ext4fs_close();
- return -1;
- }
-
- if (len == 0)
- len = file_len;
-
- len_read = ext4fs_read((char *)addr, len);
- ext4fs_close();
-
- if (len_read != len) {
- printf("** Unable to read file %s **\n", filename);
- return -1;
- }
-
- return len_read;
-}
-#else
-static inline int fs_probe_ext(void)
+static inline int fs_read_unsupported(const char *filename, void *buf,
+ int offset, int len)
{
return -1;
}
-static inline void fs_close_ext(void)
+static inline void fs_close_unsupported(void)
{
}
-#define fs_ls_ext fs_ls_unsupported
-#define fs_read_ext fs_read_unsupported
-#endif
-
-static struct {
+struct fstype_info {
int fstype;
- int (*probe)(void);
-} fstypes[] = {
+ int (*probe)(block_dev_desc_t *fs_dev_desc,
+ disk_partition_t *fs_partition);
+ int (*ls)(const char *dirname);
+ int (*read)(const char *filename, void *buf, int offset, int len);
+ void (*close)(void);
+};
+
+static struct fstype_info fstypes[] = {
+#ifdef CONFIG_FS_FAT
{
.fstype = FS_TYPE_FAT,
- .probe = fs_probe_fat,
+ .probe = fat_set_blk_dev,
+ .close = fat_close,
+ .ls = file_fat_ls,
+ .read = fat_read_file,
},
+#endif
+#ifdef CONFIG_FS_EXT4
{
.fstype = FS_TYPE_EXT,
- .probe = fs_probe_ext,
+ .probe = ext4fs_probe,
+ .close = ext4fs_close,
+ .ls = ext4fs_ls,
+ .read = ext4_read_file,
+ },
+#endif
+#ifdef CONFIG_SANDBOX
+ {
+ .fstype = FS_TYPE_SANDBOX,
+ .probe = sandbox_fs_set_blk_dev,
+ .close = sandbox_fs_close,
+ .ls = sandbox_fs_ls,
+ .read = fs_read_sandbox,
+ },
+#endif
+ {
+ .fstype = FS_TYPE_ANY,
+ .probe = fs_probe_unsupported,
+ .close = fs_close_unsupported,
+ .ls = fs_ls_unsupported,
+ .read = fs_read_unsupported,
},
};
+static struct fstype_info *fs_get_info(int fstype)
+{
+ struct fstype_info *info;
+ int i;
+
+ for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes) - 1; i++, info++) {
+ if (fstype == info->fstype)
+ return info;
+ }
+
+ /* Return the 'unsupported' sentinel */
+ return info;
+}
+
int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
{
+ struct fstype_info *info;
int part, i;
#ifdef CONFIG_NEEDS_MANUAL_RELOC
static int relocated;
if (!relocated) {
- for (i = 0; i < ARRAY_SIZE(fstypes); i++)
- fstypes[i].probe += gd->reloc_off;
+ for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes);
+ i++, info++) {
+ info->probe += gd->reloc_off;
+ info->close += gd->reloc_off;
+ info->ls += gd->reloc_off;
+ info->read += gd->reloc_off;
+ }
relocated = 1;
}
#endif
@@ -175,32 +135,25 @@ int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
if (part < 0)
return -1;
- for (i = 0; i < ARRAY_SIZE(fstypes); i++) {
- if ((fstype != FS_TYPE_ANY) && (fstype != fstypes[i].fstype))
+ for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
+ if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY &&
+ fstype != info->fstype)
continue;
- if (!fstypes[i].probe()) {
- fs_type = fstypes[i].fstype;
+ if (!info->probe(fs_dev_desc, &fs_partition)) {
+ fs_type = info->fstype;
return 0;
}
}
- printf("** Unrecognized filesystem type **\n");
return -1;
}
static void fs_close(void)
{
- switch (fs_type) {
- case FS_TYPE_FAT:
- fs_close_fat();
- break;
- case FS_TYPE_EXT:
- fs_close_ext();
- break;
- default:
- break;
- }
+ struct fstype_info *info = fs_get_info(fs_type);
+
+ info->close();
fs_type = FS_TYPE_ANY;
}
@@ -209,18 +162,11 @@ int fs_ls(const char *dirname)
{
int ret;
- switch (fs_type) {
- case FS_TYPE_FAT:
- ret = fs_ls_fat(dirname);
- break;
- case FS_TYPE_EXT:
- ret = fs_ls_ext(dirname);
- break;
- default:
- ret = fs_ls_unsupported(dirname);
- break;
- }
+ struct fstype_info *info = fs_get_info(fs_type);
+ ret = info->ls(dirname);
+
+ fs_type = FS_TYPE_ANY;
fs_close();
return ret;
@@ -228,20 +174,23 @@ int fs_ls(const char *dirname)
int fs_read(const char *filename, ulong addr, int offset, int len)
{
+ struct fstype_info *info = fs_get_info(fs_type);
+ void *buf;
int ret;
- switch (fs_type) {
- case FS_TYPE_FAT:
- ret = fs_read_fat(filename, addr, offset, len);
- break;
- case FS_TYPE_EXT:
- ret = fs_read_ext(filename, addr, offset, len);
- break;
- default:
- ret = fs_read_unsupported(filename, addr, offset, len);
- break;
- }
+ /*
+ * We don't actually know how many bytes are being read, since len==0
+ * means read the whole file.
+ */
+ buf = map_sysmem(addr, len);
+ ret = info->read(filename, buf, offset, len);
+ unmap_sysmem(buf);
+ /* If we requested a specific number of bytes, check we got it */
+ if (ret >= 0 && len && ret != len) {
+ printf("** Unable to read file %s **\n", filename);
+ ret = -1;
+ }
fs_close();
return ret;
@@ -256,7 +205,6 @@ int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
unsigned long bytes;
unsigned long pos;
int len_read;
- char buf[12];
unsigned long time;
if (argc < 2)
@@ -308,8 +256,7 @@ int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
}
puts("\n");
- sprintf(buf, "0x%x", len_read);
- setenv("filesize", buf);
+ setenv_hex("filesize", len_read);
return 0;
}
diff --git a/fs/sandbox/Makefile b/fs/sandbox/Makefile
new file mode 100644
index 0000000000..b3155b004c
--- /dev/null
+++ b/fs/sandbox/Makefile
@@ -0,0 +1,47 @@
+#
+# Copyright (c) 2012, Google Inc.
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# (C) Copyright 2003
+# Pavel Bartusek, Sysgo Real-Time Solutions AG, pba@sysgo.de
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)libsandboxfs.o
+
+COBJS-$(CONFIG_SANDBOX) := sandboxfs.o
+
+SRCS := $(COBJS-y:.o=.c)
+OBJS := $(addprefix $(obj),$(AOBJS) $(COBJS-y))
+
+all: $(LIB) $(AOBJS)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/fs/sandbox/sandboxfs.c b/fs/sandbox/sandboxfs.c
new file mode 100644
index 0000000000..02d26ff851
--- /dev/null
+++ b/fs/sandbox/sandboxfs.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2012, Google 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <fs.h>
+#include <os.h>
+
+int sandbox_fs_set_blk_dev(block_dev_desc_t *rbdd, disk_partition_t *info)
+{
+ return 0;
+}
+
+long sandbox_fs_read_at(const char *filename, unsigned long pos,
+ void *buffer, unsigned long maxsize)
+{
+ ssize_t size;
+ int fd, ret;
+
+ fd = os_open(filename, OS_O_RDONLY);
+ if (fd < 0)
+ return fd;
+ ret = os_lseek(fd, pos, OS_SEEK_SET);
+ if (ret == -1) {
+ os_close(fd);
+ return ret;
+ }
+ if (!maxsize)
+ maxsize = os_get_filesize(filename);
+ size = os_read(fd, buffer, maxsize);
+ os_close(fd);
+
+ return size;
+}
+
+int sandbox_fs_ls(const char *dirname)
+{
+ struct os_dirent_node *head, *node;
+ int ret;
+
+ ret = os_dirent_ls(dirname, &head);
+ if (ret)
+ return ret;
+
+ for (node = head; node; node = node->next) {
+ printf("%s %10lu %s\n", os_dirent_get_typename(node->type),
+ node->size, node->name);
+ }
+
+ return 0;
+}
+
+void sandbox_fs_close(void)
+{
+}
+
+int fs_read_sandbox(const char *filename, void *buf, int offset, int len)
+{
+ int len_read;
+
+ len_read = sandbox_fs_read_at(filename, offset, buf, len);
+ if (len_read == -1) {
+ printf("** Unable to read file %s **\n", filename);
+ return -1;
+ }
+
+ return len_read;
+}
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 30ccd98c22..9acf243eef 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -1164,10 +1164,9 @@ static struct file_system_type ubifs_fs_type = {
.get_sb = ubifs_get_sb,
};
-int ubifs_mount(char *vol_name)
+int ubifs_mount(char *name)
{
int flags;
- char name[80] = "ubi:";
void *data;
struct vfsmount *mnt;
int ret;
@@ -1186,7 +1185,6 @@ int ubifs_mount(char *vol_name)
* Mount in read-only mode
*/
flags = MS_RDONLY;
- strcat(name, vol_name);
data = NULL;
mnt = NULL;
ret = ubifs_get_sb(&ubifs_fs_type, flags, name, data, mnt);
diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c
index 44be3f53e0..273c0a9638 100644
--- a/fs/ubifs/ubifs.c
+++ b/fs/ubifs/ubifs.c
@@ -687,7 +687,6 @@ int ubifs_load(char *filename, u32 addr, u32 size)
int i;
int count;
int last_block_size = 0;
- char buf [10];
c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
/* ubifs_findfile will resolve symlinks, so we know that we get
@@ -740,8 +739,7 @@ int ubifs_load(char *filename, u32 addr, u32 size)
if (err)
printf("Error reading file '%s'\n", filename);
else {
- sprintf(buf, "%X", size);
- setenv("filesize", buf);
+ setenv_hex("filesize", size);
printf("Done\n");
}
OpenPOWER on IntegriCloud