diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/Makefile | 2 | ||||
-rw-r--r-- | fs/ext4/ext4_write.c | 996 | ||||
-rw-r--r-- | fs/ext4/ext4fs.c | 962 | ||||
-rw-r--r-- | fs/fat/fat.c | 17 | ||||
-rw-r--r-- | fs/fs.c | 241 | ||||
-rw-r--r-- | fs/sandbox/Makefile | 47 | ||||
-rw-r--r-- | fs/sandbox/sandboxfs.c | 83 | ||||
-rw-r--r-- | fs/ubifs/super.c | 4 | ||||
-rw-r--r-- | fs/ubifs/ubifs.c | 4 |
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) +{ +} @@ -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"); } |