ext4fs write support
PATCH 2/2 ext4fs write support
--- common/cmd_ext4.c | 133 +++++ fs/ext4/Makefile | 2 +- fs/ext4/crc16.c | 61 +++ fs/ext4/crc16.h | 17 + fs/ext4/ext4_common.c | 1386 +++++++++++++++++++++++++++++++++++++++++++++++- fs/ext4/ext4_common.h | 17 + fs/ext4/ext4_journal.c | 657 +++++++++++++++++++++++ fs/ext4/ext4_journal.h | 147 +++++ fs/ext4/ext4fs.c | 1039 ++++++++++++++++++++++++++++++++++++- include/ext4fs.h | 8 + 10 files changed, 3463 insertions(+), 4 deletions(-) create mode 100644 fs/ext4/crc16.c create mode 100644 fs/ext4/crc16.h create mode 100644 fs/ext4/ext4_journal.c create mode 100644 fs/ext4/ext4_journal.h
common/cmd_ext4.c +40 -0
@@ -55,6 +55,46 @@ static uint16_t cur_part = 1;#define DOS_FS_TYPE_OFFSET 0x36#define DOS_FS32_TYPE_OFFSET 0x52 +static int ext4_register_device (block_dev_desc_t *dev_desc,int part_no) +{ +unsigned char buffer[SECTOR_SIZE ]; +disk_partition_t info; + +if (!dev_desc->block_read) +return -1 ; + +/* check if we have a MBR (on floppies we have only a PBR) */ +if (dev_desc->block_read (dev_desc->dev,0 ,1 , (ulong *) buffer) !=1 ) { +printf ("** Can't read from device %d **\n" , dev_desc->dev); +return -1 ; + } +if (buffer[DOS_PART_MAGIC_OFFSET ] !=0x55 || + buffer[DOS_PART_MAGIC_OFFSET +1 ] !=0xaa ) { +/* no signature found */ +return -1 ; + } + +/* First we assume there is a MBR */ +if (!get_partition_info (dev_desc, part_no, &info)) { + part_offset = info.start; + cur_part = part_no; + part_size = info.size; + }else if ((strncmp ((char *)&buffer[DOS_FS_TYPE_OFFSET ], +"FAT" ,3 ) ==0 ) || (strncmp ((char *)&buffer + [DOS_FS32_TYPE_OFFSET ], +"FAT32" ,5 ) ==0 )) { +/* ok, we assume we are on a PBR only */ + cur_part =1 ; + part_offset =0 ; + }else { +printf ("** Partition %d not valid on device %d **\n" , + part_no, dev_desc->dev); +return -1 ; + } + +return 0 ; +} +int do_ext4_load (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) {char *filename =NULL ;
@@ -243,6 +283,94 @@ int do_ext4_ls(cmd_tbl_t *cmdtp, int flag, int argc,
char *const argv[])
return 0;
}
+int do_ext4_write(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{
+ char *filename = "/";
+ int part_length;
+ int part = 1;
+ int dev = 0;
+ char *ep;
+ unsigned long ram_address;
+ unsigned long file_size;
+ disk_partition_t info;
+ ExtFileSystem *fs;
+
+ if (argc < 6)
+ return cmd_usage(cmdtp);
+
+ dev = (int)strict_strtoul(argv[2], &ep, 16);
+ ext4_dev_desc = get_dev(argv[1], dev);
+ if (ext4_dev_desc == NULL) {
+ printf("Block device %s %d not \
+ supported\n", argv[1], dev);
+ return 1;
+ }
+ if (init_fs(ext4_dev_desc))
+ return 1;
+
+ fs = get_fs();
+ if (*ep) {
+ if (*ep != ':') {
+ puts("Invalid boot device, use `dev[:part]'\n");
+ goto fail;
+ }
+ part = (int)strict_strtoul(++ep, NULL, 16);
+ }
+
+ /*get the filename */
+ filename = argv[3];
+
+ /*get the address in hexadecimal format (string to int) */
+ ram_address = strict_strtoul(argv[4], NULL, 16);
+
+ /*get the filesize in base 10 format */
+ file_size = strict_strtoul(argv[5], NULL, 10);
+
+ /*set the device as block device */
+ part_length = ext2fs_set_blk_dev(fs->dev_desc, part);
+ if (part_length == 0) {
+ printf("Bad partition - %s %d:%d\n", argv[1], dev, part);
+ goto fail;
+ }
+
+ /*register the device and partition */
+ if (ext4_register_device(fs->dev_desc, part) != 0) {
+ printf("Unable to use %s %d:%d for fattable\n",
+ argv[1], dev, part);
+ goto fail;
+ }
+
+ /*get the partition information */
+ if (!get_partition_info(fs->dev_desc, part, &info)) {
+ total_sector = (info.size * info.blksz) / SECTOR_SIZE;
+ fs->total_sect = total_sector;
+ } else {
+ printf("error : get partition info\n");
+ goto fail;
+ }
+
+ /*mount the filesystem */
+ if (!ext4fs_mount(part_length)) {
+ printf("Bad ext4 partition %s %d:%d\n", argv[1], dev, part);
+ goto fail;
+ }
+
+ /*start write */
+ if (ext4fs_write(filename, (unsigned char *)ram_address, file_size)) {
+ printf("** Error ext4fs_write() **\n");
+ goto fail;
+ }
+
+ ext4fs_close();
+ deinit_fs(fs->dev_desc);
+ return 0;
+
+fail:
+ ext4fs_close();
+ deinit_fs(fs->dev_desc);
+ return 1;
+}
+
U_BOOT_CMD(ext4ls, 4, 1, do_ext4_ls,
"list files in a directory (default /)",
"<interface> <dev[:part]> [directory]\n"
@@ -253,3 +381,8 @@ U_BOOT_CMD(ext4load, 6, 0, do_ext4_load,
"<interface> <dev[:part]> [addr] [filename] [bytes]\n"
" - load binary file 'filename' from 'dev' on 'interface'\n"
" to address 'addr' from ext2 filesystem");
+U_BOOT_CMD
+ (ext4write, 6, 1, do_ext4_write,
+ "create a file in the root directory",
+ "<interface> <dev[:part]> [Absolute filename path] [Address]
[sizebytes]\n"
+ " - create a file in / directory");
fs/ext4/Makefile +1 -1
@@ -30,7 +30,7 @@ include $(TOPDIR)/config.mk LIB = $(obj)libext4fs.o AOBJS = -COBJS-$(CONFIG_CMD_EXT4) := ext4fs.o ext4_common.o +COBJS-$(CONFIG_CMD_EXT4) := ext4fs.o ext4_common.o ext4_journal.o crc16.o SRCS := $(AOBJS:.o=.S) $(COBJS-y:.o=.c) OBJS := $(addprefix $(obj),$(AOBJS) $(COBJS-y))
fs/ext4/crc16.c new file +61 -0
61 lines not on this page · raw message
fs/ext4/crc16.h new file +16 -0
@@ -0,0 +1,17 @@ +/* +* crc16.h - CRC-16 routine +* Implements the standard CRC-16: +* Width 16 +* Poly 0x8005 (x16 + x15 + x2 + 1) +* Init 0 +* +* Copyright (c) 2005 Ben Gardner <[email protected]> +* This source code is licensed under the GNU General Public License, +* Version 2. See the file COPYING for more details. +*/ +#ifndef __CRC16_H +#define __CRC16_H + +typedef unsigned int crc16_t ; +extern crc16_t ext2fs_crc16(crc16_t crc, const void *buffer, unsigned int
len);
+#endif
fs/ext4/ext4_common.c +636 -2
653 lines not on this page · raw message
be
+* created
+* dirname : Input parmater, input path name of the file/directory to be created
+* dname : Output parameter, to be filled with the name of the directory +* extracted from dirname
+*/
+int get_parent_inode_num(char *dirname, char *dname, int flags) +{
+ char **ptr = NULL;
+ int i, depth = 0;
+ char *depth_dirname = NULL;
+ char *parse_dirname = NULL;
+ struct ext4_inode *parent_inode = NULL;
+ struct ext4_inode *first_inode = NULL;
+ struct ext4_inode temp_inode;
+ int matched_inode_no;
+ int result_inode_no = -1;
+
+ if (*dirname != '/') {
+ printf("Please supply Absolute path\n");
+ return -1;
+ }
+
+ depth_dirname = (char *)xzalloc(strlen(dirname) + 1);
+ if (!depth_dirname)
+ return -1;
+
+ memcpy(depth_dirname, dirname, strlen(dirname));
+ depth = find_dir_depth(depth_dirname);
+ parse_dirname = (char *)xzalloc(strlen(dirname) + 1);
+ if (!parse_dirname)
+ goto fail;
+ memcpy(parse_dirname, dirname, strlen(dirname));
+
+ ptr = (char **)xzalloc((depth) * sizeof(char *));
+ if (!ptr)
+ goto fail;
+ if (parse_path(ptr, parse_dirname))
+ goto fail;
+ parent_inode = (struct ext4_inode *)
+ xzalloc(sizeof(struct ext4_inode));
+ if (!parent_inode)
+ goto fail;
+ first_inode = (struct ext4_inode *)
+ xzalloc(sizeof(struct ext4_inode));
+ if (!first_inode)
+ goto fail;
+ memcpy(parent_inode, ext4fs_root->inode, sizeof(struct ext4_inode));
+ memcpy(first_inode, parent_inode, sizeof(struct ext4_inode));
+ if (flags & F_FILE)
+ result_inode_no = EXT2_ROOT_INO;
+ for (i = 1; i < depth; i++) {
+ matched_inode_no = search_dir(parent_inode, ptr[i]);
+ if (matched_inode_no == -1) {
+ if (ptr[i + 1] == NULL && i == 1) {
+ result_inode_no = EXT2_ROOT_INO;
+ goto END;
+ } else {
+ if (ptr[i + 1] == NULL)
+ break;
+ printf("Invalid path\n");
+ result_inode_no = -1;
+ goto fail;
+ }
+ } else {
+ if (ptr[i + 1] != NULL) {
+ memset(parent_inode, '\0',
+ sizeof(struct ext4_inode));
+ if (iget(matched_inode_no, parent_inode)) {
+ result_inode_no = -1;
+ goto fail;
+ }
+ result_inode_no = matched_inode_no;
+ } else
+ break;
+ }
+ }
+
+END:
+ if (i == 1)
+ matched_inode_no = search_dir(first_inode, ptr[i]);
+ else
+ matched_inode_no = search_dir(parent_inode, ptr[i]);
+
+ if (matched_inode_no != -1) {
+ iget(matched_inode_no, &temp_inode);
+ if (temp_inode.mode & S_IFDIR) {
+ printf("It is a Directory\n");
+ result_inode_no = -1;
+ goto fail;
+ }
+ }
+
+ if (strlen(ptr[i]) > 256) {
+ result_inode_no = -1;
+ goto fail;
+ }
+ memcpy(dname, ptr[i], strlen(ptr[i]));
+
+fail:
+ if (depth_dirname)
+ free(depth_dirname);
+ if (parse_dirname)
+ free(parse_dirname);
+ if (ptr)
+ free(ptr);
+ if (parent_inode)
+ free(parent_inode);
+ if (first_inode)
+ free(first_inode);
+
+ return result_inode_no;
+}
+
+static int check_filename(char *filename, unsigned int blknr) +{
+ char *root_first_block_buffer, *root_first_block_addr;
+ unsigned int first_block_no_of_root;
+ ExtFileSystem *fs = get_fs();
+ struct ext2_dirent *dir;
+ struct ext2_dirent *previous_dir = NULL;
+ int totalbytes = 0;
+ int templength = 0;
+ int status, inodeno;
+ int found = 0;
+ char *ptr;
+
+ first_block_no_of_root = blknr;
+ root_first_block_buffer = (char *)xzalloc(fs->blksz);
+ if (!root_first_block_buffer)
+ return -1;
+ root_first_block_addr = root_first_block_buffer;
+ status = ext2fs_devread(first_block_no_of_root *
+ fs->sect_perblk, 0,
+ fs->blksz, root_first_block_buffer);
+ if (status == 0) {
+ goto fail;
+ } else {
+ if (log_journal(root_first_block_buffer,
+ first_block_no_of_root))
+ goto fail;
+ dir = (struct ext2_dirent *)root_first_block_buffer;
+ ptr = (char *)dir;
+ totalbytes = 0;
+ while (dir->direntlen >= 0) {
+ if (strlen(filename) == dir->namelen) {
+ if (strncmp(filename,
+ ptr + sizeof(struct ext2_dirent),
+ dir->namelen) == 0) {
+ printf("file found deleting\n");
+ previous_dir->direntlen +=
+ dir->direntlen;
+ inodeno = dir->inode;
+ dir->inode = 0;
+ found = 1;
+ break;
+ }
+ }
+
+ if (fs->blksz - totalbytes == dir->direntlen)
+ break;
+
+ /*traversing the each directory entry */
+ templength = dir->direntlen;
+ totalbytes = totalbytes + templength;
+ previous_dir = dir;
+ dir = (struct ext2_dirent *)((char *)dir + templength);
+ ptr = (char *)dir;
+ }
+ }
+
+ if (found == 1) {
+ if (put_metadata(root_first_block_addr, first_block_no_of_root))
+ goto fail;
+ return inodeno;
+ }
+
+fail:
+ if (root_first_block_buffer)
+ free(root_first_block_buffer);
+ return -1;
+}
+
+int ext4fs_filename_check(char *filename)
+{
+ short direct_blk_idx = 0;
+ long int blknr = -1;
+ int inodeno = -1;
+
+ /*read the block no allocated to a file */
+ for (direct_blk_idx = 0; direct_blk_idx < INDIRECT_BLOCKS;
+ direct_blk_idx++) {
+ blknr = read_allocated_block(g_parent_inode, direct_blk_idx);
+ if (blknr == 0)
+ break;
+ inodeno = check_filename(filename, blknr);
+ if (inodeno != -1)
+ return inodeno;
+ }
+ return -1;
+}
+
static struct ext4_extent_header *ext4fs_find_leaf(struct ext2_data *data,
char *buf, struct ext4_extent_header *ext_block, uint32_t fileblock)
{
@@ -152,6 +987,553 @@ int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext4_inode *inode)
return 1;
}
+long int get_new_blk_no(void)
+{
+ short i, status;
+ int remainder;
+ unsigned int bg_idx;
+ static int prev_bg_bitmap_index = -1;
+ ExtFileSystem *fs = get_fs();
+ char *journal_buffer = (char *)xzalloc(fs->blksz);
+ char *zero_buffer = (char *)xzalloc(fs->blksz);
+ if (!journal_buffer || !zero_buffer)
+ goto fail;
+ struct ext2_block_group *gd = (struct ext2_block_group *)fs->gdtable;
+
+ if (fs->first_pass_bbmap == 0) {
+ for (i = 0; i < fs->no_blkgrp; i++) {
+ if (gd[i].free_blocks) {
+ if (gd[i].bg_flags & EXT4_BG_BLOCK_UNINIT) {
+ put_ext4(((uint64_t) (gd[i].block_id *
+ fs->blksz)),
+ zero_buffer, fs->blksz);
+ gd[i].bg_flags =
+ gd[i].
+ bg_flags & ~EXT4_BG_BLOCK_UNINIT;
+ memcpy(fs->blk_bmaps[i], zero_buffer,
+ fs->blksz);
+ }
+ fs->curr_blkno =
+ _get_new_blk_no(fs->blk_bmaps[i]);
+ if (fs->curr_blkno == -1) {
+ /*if block bitmap is completely fill */
+ continue;
+ }
+ fs->curr_blkno = fs->curr_blkno +
+ (i * fs->blksz * 8);
+ fs->first_pass_bbmap++;
+ gd[i].free_blocks--;
+ fs->sb->free_blocks--;
+ status = ext2fs_devread(gd[i].block_id *
+ fs->sect_perblk, 0,
+ fs->blksz,
+ journal_buffer);
+ if (status == 0)
+ goto fail;
+ if (log_journal(journal_buffer, gd[i].block_id))
+ goto fail;
+ goto success;
+ } else {
+ debug("no space left on block group %d\n", i);
+ }
+ }
+ goto fail;
+ } else {
+restart:
+ fs->curr_blkno++;
+ /*get the blockbitmap index respective to blockno */
+ if (fs->blksz != 1024) {
+ bg_idx = fs->curr_blkno /
+ (uint32_t) ext4fs_root->sblock.blocks_per_group;
+ } else {
+ bg_idx = fs->curr_blkno /
+ (uint32_t) ext4fs_root->sblock.blocks_per_group;
+ remainder = fs->curr_blkno %
+ (uint32_t) ext4fs_root->sblock.blocks_per_group;
+ if (!remainder)
+ bg_idx--;
+ }
+
+ if (bg_idx >= fs->no_blkgrp)
+ goto fail;
+
+ if (gd[bg_idx].free_blocks == 0) {
+ debug("block group %u is full. Skipping\n", bg_idx);
+ fs->curr_blkno = fs->curr_blkno +
+ ext4fs_root->sblock.blocks_per_group;
+ fs->curr_blkno--;
+ goto restart;
+ }
+
+ if (gd[bg_idx].bg_flags & EXT4_BG_BLOCK_UNINIT) {
+ memset(zero_buffer, '\0', fs->blksz);
+ put_ext4(((uint64_t) (gd[bg_idx].block_id * fs->blksz)),
+ zero_buffer, fs->blksz);
+ memcpy(fs->blk_bmaps[bg_idx], zero_buffer, fs->blksz);
+ gd[bg_idx].bg_flags = gd[bg_idx].bg_flags &
+ ~EXT4_BG_BLOCK_UNINIT;
+ }
+
+ if (set_block_bmap(fs->curr_blkno, fs->blk_bmaps[bg_idx],
+ bg_idx) != 0) {
+ debug("going for restart for the block no %ld %u\n",
+ fs->curr_blkno, bg_idx);
+ goto restart;
+ }
+
+ /*journal backup */
+ if (prev_bg_bitmap_index != bg_idx) {
+ memset(journal_buffer, '\0', fs->blksz);
+ status = ext2fs_devread(gd[bg_idx].block_id
+ * fs->sect_perblk,
+ 0, fs->blksz, journal_buffer);
+ if (status == 0)
+ goto fail;
+ if (log_journal(journal_buffer, gd[bg_idx].block_id))
+ goto fail;
+
+ prev_bg_bitmap_index = bg_idx;
+ }
+ gd[bg_idx].free_blocks--;
+ fs->sb->free_blocks--;
+ goto success;
+ }
+success:
+ if (journal_buffer)
+ free(journal_buffer);
+ if (zero_buffer)
+ free(zero_buffer);
+ return fs->curr_blkno;
+fail:
+ if (journal_buffer)
+ free(journal_buffer);
+ if (zero_buffer)
+ free(zero_buffer);
+ return -1;
+}
+
+int get_new_inode_no(void)
+{
+ short i, status;
+ unsigned int ibmap_idx;
+ static int prev_inode_bitmap_index = -1;
+ ExtFileSystem *fs = get_fs();
+ char *journal_buffer = (char *)xzalloc(fs->blksz);
+ char *zero_buffer = (char *)xzalloc(fs->blksz);
+ if (!journal_buffer || !zero_buffer)
+ goto fail;
+ struct ext2_block_group *gd = (struct ext2_block_group *)fs->gdtable;
+
+ if (fs->first_pass_ibmap == 0) {
+ for (i = 0; i < fs->no_blkgrp; i++) {
+ if (gd[i].free_inodes) {
+ if (gd[i].bg_flags & EXT4_BG_INODE_UNINIT) {
+ put_ext4(((uint64_t)
+ (gd[i].inode_id * fs->blksz)),
+ zero_buffer, fs->blksz);
+ gd[i].bg_flags = gd[i].bg_flags &
+ ~EXT4_BG_INODE_UNINIT;
+ memcpy(fs->inode_bmaps[i],
+ zero_buffer, fs->blksz);
+ }
+ fs->curr_inode_no =
+ _get_new_inode_no(fs->inode_bmaps[i]);
+ if (fs->curr_inode_no == -1) {
+ /*if block bitmap is completely fill */
+ continue;
+ }
+ fs->curr_inode_no = fs->curr_inode_no +
+ (i * ext4fs_root->sblock.inodes_per_group);
+ fs->first_pass_ibmap++;
+ gd[i].free_inodes--;
+ gd[i].bg_itable_unused--;
+ fs->sb->free_inodes--;
+ status = ext2fs_devread(gd[i].inode_id *
+ fs->sect_perblk, 0,
+ fs->blksz,
+ journal_buffer);
+ if (status == 0)
+ goto fail;
+ if (log_journal(journal_buffer, gd[i].inode_id))
+ goto fail;
+ goto success;
+ } else
+ debug("no inode left on block group %d\n", i);
+ }
+ goto fail;
+ } else {
+restart:
+ fs->curr_inode_no++;
+ /*get the blockbitmap index respective to blockno */
+ ibmap_idx = fs->curr_inode_no /
+ (uint32_t) ext4fs_root->sblock.inodes_per_group;
+ if (gd[ibmap_idx].bg_flags & EXT4_BG_INODE_UNINIT) {
+ memset(zero_buffer, '\0', fs->blksz);
+ put_ext4(((uint64_t) (gd[ibmap_idx].inode_id *
+ fs->blksz)), zero_buffer,
+ fs->blksz);
+ gd[ibmap_idx].bg_flags =
+ gd[ibmap_idx].bg_flags & ~EXT4_BG_INODE_UNINIT;
+ memcpy(fs->inode_bmaps[ibmap_idx], zero_buffer,
+ fs->blksz);
+ }
+
+ if (set_inode_bmap(fs->curr_inode_no,
+ fs->inode_bmaps[ibmap_idx],
+ ibmap_idx) != 0) {
+ debug("going for restart for the block no %d %u\n",
+ fs->curr_inode_no, ibmap_idx);
+ goto restart;
+ }
+
+ /*journal backup */
+ if (prev_inode_bitmap_index != ibmap_idx) {
+ memset(journal_buffer, '\0', fs->blksz);
+ status = ext2fs_devread(gd[ibmap_idx].inode_id
+ * fs->sect_perblk,
+ 0, fs->blksz, journal_buffer);
+ if (status == 0)
+ goto fail;
+ if (log_journal(journal_buffer, gd[ibmap_idx].inode_id))
+ goto fail;
+ prev_inode_bitmap_index = ibmap_idx;
+ }
+
+ gd[ibmap_idx].free_inodes--;
+ gd[ibmap_idx].bg_itable_unused--;
+ fs->sb->free_inodes--;
+ goto success;
+ }
+
+success:
+ if (journal_buffer)
+ free(journal_buffer);
+ if (zero_buffer)
+ free(zero_buffer);
+ return fs->curr_inode_no;
+
+fail:
+ if (journal_buffer)
+ free(journal_buffer);
+ if (zero_buffer)
+ free(zero_buffer);
+ return -1;
+
+}
+
+/*allocation of single indirect blocks*/
+static void alloc_single_indirect_block(struct ext4_inode *file_inode,
+ unsigned int *total_remaining_blocks,
+ unsigned int *no_blks_reqd)
+{
+ short i, status;
+ long int actual_block_no;
+ /*single indirect */
+ unsigned int *SI_buffer = NULL;
+ long int SI_blockno;
+ unsigned int *SI_start_addr = NULL;
+ ExtFileSystem *fs = get_fs();
+
+ if (*total_remaining_blocks != 0) {
+ SI_buffer = xzalloc(fs->blksz);
+ if (!SI_buffer)
+ return;
+ SI_start_addr = SI_buffer;
+ SI_blockno = get_new_blk_no();
+ if (SI_blockno == -1) {
+ printf("no block left to assign\n");
+ goto fail;
+ }
+ (*no_blks_reqd)++;
+ debug("SIPB %ld: %u\n", SI_blockno, *total_remaining_blocks);
+
+ status = ext2fs_devread(SI_blockno * fs->sect_perblk,
+ 0, fs->blksz, (char *)SI_buffer);
+ memset(SI_buffer, '\0', fs->blksz);
+ if (status == 0)
+ goto fail;
+
+ for (i = 0; i < (fs->blksz / sizeof(int)); i++) {
+ actual_block_no = get_new_blk_no();
+ if (actual_block_no == -1) {
+ printf("no block left to assign\n");
+ goto fail;
+ }
+ *SI_buffer = actual_block_no;
+ debug("SIAB %ld: %u\n", *SI_buffer,
+ *total_remaining_blocks);
+
+ SI_buffer++;
+ (*total_remaining_blocks)--;
+ if (*total_remaining_blocks == 0)
+ break;
+ }
+
+ /*write the block to disk */
+ put_ext4(((uint64_t) (SI_blockno * fs->blksz)),
+ SI_start_addr, fs->blksz);
+ file_inode->b.blocks.indir_block = SI_blockno;
+ }
+fail:
+ if (SI_start_addr)
+ free(SI_start_addr);
+ return;
+}
+
+/*allocation of double indirect blocks*/
+static void alloc_double_indirect_block(struct ext4_inode *file_inode,
+ unsigned int *total_remaining_blocks,
+ unsigned int *no_blks_reqd)
+{
+ short i, j, status;
+ long int actual_block_no;
+ /*double indirect */
+ long int DI_blockno_parent, DI_blockno_child;
+ unsigned int *DI_parent_buffer = NULL;
+ unsigned int *DI_child_buff = NULL;
+ unsigned int *DI_block_start_addr = NULL;
+ unsigned int *DI_child_buff_start = NULL;
+ ExtFileSystem *fs = get_fs();
+
+ if (*total_remaining_blocks != 0) {
+ /*double indirect parent block connecting to inode */
+ DI_blockno_parent = get_new_blk_no();
+ if (DI_blockno_parent == -1) {
+ printf("no block left to assign\n");
+ goto fail;
+ }
+ DI_parent_buffer = xzalloc(fs->blksz);
+ if (!DI_parent_buffer)
+ goto fail;
+
+ DI_block_start_addr = DI_parent_buffer;
+ (*no_blks_reqd)++;
+ debug("DIPB %ld: %u\n", DI_blockno_parent,
+ *total_remaining_blocks);
+
+ status = ext2fs_devread(DI_blockno_parent *
+ fs->sect_perblk, 0,
+ fs->blksz, (char *)DI_parent_buffer);
+ memset(DI_parent_buffer, '\0', fs->blksz);
+
+ /*START: for each double indirect parent
+ *block create one more block*/
+ for (i = 0; i < (fs->blksz / sizeof(int)); i++) {
+ DI_blockno_child = get_new_blk_no();
+ if (DI_blockno_child == -1) {
+ printf("no block left to assign\n");
+ goto fail;
+ }
+ DI_child_buff = xzalloc(fs->blksz);
+ if (!DI_child_buff)
+ goto fail;
+
+ DI_child_buff_start = DI_child_buff;
+ *DI_parent_buffer = DI_blockno_child;
+ DI_parent_buffer++;
+ (*no_blks_reqd)++;
+ debug("DICB %ld: %u\n", DI_blockno_child,
+ *total_remaining_blocks);
+
+ status = ext2fs_devread(DI_blockno_child *
+ fs->sect_perblk, 0,
+ fs->blksz,
+ (char *)DI_child_buff);
+ memset(DI_child_buff, '\0', fs->blksz);
+ /*END: for each double indirect parent block block */
+ /*filling of actual datablocks for each child */
+ for (j = 0; j < (fs->blksz / sizeof(int)); j++) {
+ actual_block_no = get_new_blk_no();
+ if (actual_block_no == -1) {
+ printf("no block left to assign\n");
+ goto fail;
+ }
+ *DI_child_buff = actual_block_no;
+ debug("DIAB %ld: %u\n", actual_block_no,
+ *total_remaining_blocks);
+
+ DI_child_buff++;
+ (*total_remaining_blocks)--;
+ if (*total_remaining_blocks == 0)
+ break;
+ }
+ /*write the block table */
+ put_ext4(((uint64_t) (DI_blockno_child * fs->blksz)),
+ DI_child_buff_start, fs->blksz);
+ if (DI_child_buff_start)
+ free(DI_child_buff_start);
+
+ if (*total_remaining_blocks == 0)
+ break;
+ }
+ put_ext4(((uint64_t) (DI_blockno_parent * fs->blksz)),
+ DI_block_start_addr, fs->blksz);
+ file_inode->b.blocks.double_indir_block = DI_blockno_parent;
+ }
+fail:
+ if (DI_block_start_addr)
+ free(DI_block_start_addr);
+ return;
+}
+
+/*allocation of triple indirect blocks*/
+static void alloc_triple_indirect_block(struct ext4_inode *file_inode,
+ unsigned int *total_remaining_blocks,
+ unsigned int *no_blks_reqd)
+{
+ short i, j, k;
+ long int actual_block_no;
+ /*Triple Indirect */
+ long int TI_gp_blockno, TI_parent_blockno, TI_child_blockno;
+ unsigned int *TI_gp_buff = NULL;
+ unsigned int *TI_parent_buff = NULL;
+ unsigned int *TI_child_buff = NULL;
+ unsigned int *TI_gp_buff_start_addr = NULL;
+ unsigned int *TI_pbuff_start_addr = NULL;
+ unsigned int *TI_cbuff_start_addr = NULL;
+ ExtFileSystem *fs = get_fs();
+ if (*total_remaining_blocks != 0) {
+ /*triple indirect grand parent block connecting to inode */
+ TI_gp_blockno = get_new_blk_no();
+ if (TI_gp_blockno == -1) {
+ printf("no block left to assign\n");
+ goto fail;
+ }
+ TI_gp_buff = xzalloc(fs->blksz);
+ if (!TI_gp_buff)
+ goto fail;
+
+ TI_gp_buff_start_addr = TI_gp_buff;
+ (*no_blks_reqd)++;
+ debug("TIGPB %ld: %u\n", TI_gp_blockno,
+ *total_remaining_blocks);
+
+ /* for each 4 byte grand parent entry create one more block */
+ for (i = 0; i < (fs->blksz / sizeof(int)); i++) {
+ TI_parent_blockno = get_new_blk_no();
+ if (TI_parent_blockno == -1) {
+ printf("no block left to assign\n");
+ goto fail;
+ }
+ TI_parent_buff = xzalloc(fs->blksz);
+ if (!TI_parent_buff)
+ goto fail;
+
+ TI_pbuff_start_addr = TI_parent_buff;
+ *TI_gp_buff = TI_parent_blockno;
+ TI_gp_buff++;
+ (*no_blks_reqd)++;
+ debug("TIPB %ld: %u\n", TI_parent_blockno,
+ *total_remaining_blocks);
+
+ /*for each 4 byte entry parent create one more block */
+ for (j = 0; j < (fs->blksz / sizeof(int)); j++) {
+ TI_child_blockno = get_new_blk_no();
+ if (TI_child_blockno == -1) {
+ printf("no block \
+ left assign\n");
+ goto fail;
+ }
+ TI_child_buff = xzalloc(fs->blksz);
+ if (!TI_child_buff)
+ goto fail;
+
+ TI_cbuff_start_addr = TI_child_buff;
+ *TI_parent_buff = TI_child_blockno;
+ TI_parent_buff++;
+ (*no_blks_reqd)++;
+ debug("TICB %ld: %u\n", TI_parent_blockno,
+ *total_remaining_blocks);
+
+ /*filling of actual datablocks for each child */
+ for (k = 0; k < (fs->blksz / sizeof(int));
+ k++) {
+ actual_block_no = get_new_blk_no();
+ if (actual_block_no == -1) {
+ printf("no block \
+ left to assign\n");
+ goto fail;
+ }
+ *TI_child_buff = actual_block_no;
+ debug("TIAB %ld: %u\n", actual_block_no,
+ *total_remaining_blocks);
+
+ TI_child_buff++;
+ (*total_remaining_blocks)--;
+ if (*total_remaining_blocks == 0)
+ break;
+ }
+ /*write the child block */
+ put_ext4(((uint64_t) (TI_child_blockno *
+ fs->blksz)),
+ TI_cbuff_start_addr, fs->blksz);
+ if (TI_cbuff_start_addr)
+ free(TI_cbuff_start_addr);
+
+ if (*total_remaining_blocks == 0)
+ break;
+ }
+ /*write the parent block */
+ put_ext4(((uint64_t) (TI_parent_blockno * fs->blksz)),
+ TI_pbuff_start_addr, fs->blksz);
+ if (TI_pbuff_start_addr)
+ free(TI_pbuff_start_addr);
+
+ if (*total_remaining_blocks == 0)
+ break;
+ }
+ /*write the grand parent block */
+ put_ext4(((uint64_t) (TI_gp_blockno * fs->blksz)),
+ TI_gp_buff_start_addr, fs->blksz);
+ file_inode->b.blocks.tripple_indir_block = TI_gp_blockno;
+ }
+fail:
+ if (TI_gp_buff_start_addr)
+ free(TI_gp_buff_start_addr);
+ return;
+}
+
+void allocate_blocks(struct ext4_inode *file_inode,
+ unsigned int total_remaining_blocks,
+ unsigned int *total_no_of_block)
+{
+ short i;
+ long int direct_blockno;
+ unsigned int no_blks_reqd = 0;
+
+ /*-------------START:Allocation of Blocks to Inode-------------*/
+ /*allocation of direct blocks */
+ for (i = 0; i < INDIRECT_BLOCKS; i++) {
+ direct_blockno = get_new_blk_no();
+ if (direct_blockno == -1) {
+ printf("no block left to assign\n");
+ return;
+ }
+ file_inode->b.blocks.dir_blocks[i] = direct_blockno;
+ debug("DB %ld: %u\n", direct_blockno, total_remaining_blocks);
+
+ total_remaining_blocks--;
+ if (total_remaining_blocks == 0)
+ break;
+ }
+
+ /*allocation of single indirect blocks */
+ alloc_single_indirect_block(file_inode, &total_remaining_blocks,
+ &no_blks_reqd);
+
+ /*allocation of double indirect blocks */
+ alloc_double_indirect_block(file_inode, &total_remaining_blocks,
+ &no_blks_reqd);
+
+ /*allocation of triple indirect blocks */
+ alloc_triple_indirect_block(file_inode, &total_remaining_blocks,
+ &no_blks_reqd);
+
+ /*-----------------END:Allocation of Blocks to Inode-------------- */
+ *total_no_of_block += no_blks_reqd;
+ return;
+}
+
long int read_allocated_block(struct ext4_inode *inode, int fileblock) {
long int blknr;
fs/ext4/ext4_common.h +17 -0
@@ -41,4 +41,21 @@extern unsigned long part_offset;int ext4fs_read_inode (struct ext2_data *data,int ino,struct ext4_inode *inode); +uint32_t ext4fs_div_roundup (uint32_t size,uint32_t n); +int ext4fs_checksum_update (unsigned int i); +int get_parent_inode_num (char *dirname,char *dname,int flags); +void update_parent_dentry (char *filename,int *p_ino,int file_type); +long int get_new_blk_no (void ); +int get_new_inode_no (void ); +void reset_block_bmap (long int blockno,unsigned char *buffer,int index); +int set_block_bmap (long int blockno,unsigned char *buffer,int index); +int set_inode_bmap (int inode_no,unsigned char *buffer,int index); +void reset_inode_bmap (int inode_no,unsigned char *buffer,int index); +int iget (int inode_no,struct ext4_inode *inode); +void allocate_blocks (struct ext4_inode *file_inode, +unsigned int total_remaining_blocks, +unsigned int *total_no_of_block); +void put_ext4 (uint64_t off,void *buf,uint32_t size); +unsigned int be_le (unsigned int num); +unsigned int le_be (unsigned int num);#endif
fs/ext4/ext4_journal.c new file +657 -0
657 lines not on this page · raw message
fs/ext4/ext4_journal.h new file +147 -0
147 lines not on this page · raw message
fs/ext4/ext4fs.c +868 -1
884 lines not on this page · raw message
sizebytes)
+{
+ int ret = 0;
+ /*inode */
+ struct ext4_inode *file_inode = NULL;
+ unsigned char *inode_buffer = NULL;
+ int parent_inodeno;
+ int inodeno;
+ time_t timestamp = 0;
+
+ /*filesize */
+ uint64_t total_no_of_bytes_for_file;
+ unsigned int total_no_of_block_for_file;
+ unsigned int total_remaining_blocks;
+ int existing_file_inodeno;
+ char filename[256];
+
+ char *temp_ptr = NULL;
+ long int itable_blkno, parent_itable_blkno, blkoff;
+ struct ext2_sblock *sblock = &(ext4fs_root->sblock);
+ unsigned int inodes_per_block;
+ unsigned int inode_bitmap_index;
+ ExtFileSystem *fs = get_fs();
+
+ g_parent_inode = (struct ext4_inode *)
+ xzalloc(sizeof(struct ext4_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 = get_parent_inode_num(fname, filename, F_FILE);
+ if (parent_inodeno == -1)
+ goto fail;
+ if (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 */
+ total_no_of_bytes_for_file = sizebytes;
+ total_no_of_block_for_file = total_no_of_bytes_for_file / fs->blksz;
+ if (total_no_of_bytes_for_file % fs->blksz != 0) {
+ total_no_of_block_for_file++;
+ debug("total bytes for a file %u\n",
+ total_no_of_block_for_file);
+ }
+ total_remaining_blocks = total_no_of_block_for_file;
+ /*Test for available space in partition */
+ if (fs->sb->free_blocks < total_no_of_block_for_file) {
+ printf("Not enough space on partition !!!\n");
+ goto fail;
+ }
+
+ update_parent_dentry(filename, &inodeno, FILETYPE_REG);
+ /*prepare file inode */
+ inode_buffer = xmalloc(fs->inodesz);
+ memset(inode_buffer, '\0', fs->inodesz);
+ file_inode = (struct ext4_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 */
+ allocate_blocks(file_inode, total_remaining_blocks,
+ &total_no_of_block_for_file);
+ /*
+ *write the inode to inode table after last filled inode in inode table
+ *we are using hardcoded gd[0].inode_table_id becuase 0th blockgroup
+ *is suffcient to create more than 1000 file.TODO exapnd the logic to
+ *all blockgroup
+ */
+ file_inode->blockcnt = (total_no_of_block_for_file * fs->blksz)
+ / SECTOR_SIZE;
+
+ temp_ptr = (char *)xzalloc(fs->blksz);
+ if (!temp_ptr)
+ goto fail;
+ inode_bitmap_index = inodeno /
+ (uint32_t) ext4fs_root->sblock.inodes_per_group;
+ inodeno--;
+ itable_blkno =
+ __le32_to_cpu(fs->gd[inode_bitmap_index].inode_table_id) + + (inodeno % __le32_to_cpu(sblock->inodes_per_group)) + / inodes_per_block;
+ blkoff = (inodeno % inodes_per_block) * fs->inodesz;
+ ext2fs_devread(itable_blkno * fs->sect_perblk, 0, fs->blksz, temp_ptr);
+ if (log_journal(temp_ptr, itable_blkno))
+ goto fail;
+
+ memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz);
+ if (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;
+ }
+ inode_bitmap_index = parent_inodeno /
+ (uint32_t) ext4fs_root->sblock.inodes_per_group;
+ parent_inodeno--;
+ parent_itable_blkno =
+ __le32_to_cpu(fs->gd[inode_bitmap_index].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);
+ ext2fs_devread(parent_itable_blkno * fs->sect_perblk,
+ 0, fs->blksz, temp_ptr);
+ if (log_journal(temp_ptr, parent_itable_blkno))
+ goto fail;
+
+ memcpy(temp_ptr + blkoff, g_parent_inode,
+ sizeof(struct ext4_inode));
+ if (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 ext4_inode));
+ gd_index--;
+ if (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;
+ if (inode_buffer)
+ free(inode_buffer);
+ if (g_parent_inode) {
+ free(g_parent_inode);
+ g_parent_inode = NULL;
+ }
+ return 0;
+
+fail:
+ ext4fs_deinit();
+ if (inode_buffer)
+ free(inode_buffer);
+ if (g_parent_inode) {
+ free(g_parent_inode);
+ g_parent_inode = NULL;
+ }
+ return -1;
+}
include/ext4fs.h +7 -0
@@ -149,9 +149,17 @@ extern block_dev_desc_t *ext4_dev_desc;extern struct ext2_data *ext4fs_root;extern ext2fs_node_t ext4fs_file; +extern struct ext4_inode *g_parent_inode; +extern int gd_index; +extern int gindex; +ExtFileSystem *get_fs (void );int init_fs (block_dev_desc_t *);void deinit_fs (block_dev_desc_t *); +int ext4fs_init (void ); +void ext4fs_deinit (void ); +int ext4fs_write(char *fname, unsigned char *buffer, unsigned long
sizebytes);
+int ext4fs_filename_check(char *filename);
int ext4fs_open(const char *filename);
int ext4fs_read(char *buf, unsigned len);
int ext4fs_mount(unsigned part_length);
Signature · 1 line
1.7.0.4