From 698337c51a6a89d784c71a4cb90e3c72a54a6819 Mon Sep 17 00:00:00 2001 From: Kevin Mihelich Date: Wed, 31 Dec 2014 01:05:05 +0000 Subject: [PATCH] added alarm/uboot-odroid-c1 --- .../0001-add-ext4-support.patch | 5827 +++++++++++++++++ .../0002-remove-cross-compiling.patch | 36 + .../0003-sd_fusing-tweaks.patch | 41 + alarm/uboot-odroid-c1/PKGBUILD | 51 + alarm/uboot-odroid-c1/boot.ini | 25 + alarm/uboot-odroid-c1/uboot-odroid-c1.install | 32 + 6 files changed, 6012 insertions(+) create mode 100644 alarm/uboot-odroid-c1/0001-add-ext4-support.patch create mode 100644 alarm/uboot-odroid-c1/0002-remove-cross-compiling.patch create mode 100644 alarm/uboot-odroid-c1/0003-sd_fusing-tweaks.patch create mode 100644 alarm/uboot-odroid-c1/PKGBUILD create mode 100644 alarm/uboot-odroid-c1/boot.ini create mode 100644 alarm/uboot-odroid-c1/uboot-odroid-c1.install diff --git a/alarm/uboot-odroid-c1/0001-add-ext4-support.patch b/alarm/uboot-odroid-c1/0001-add-ext4-support.patch new file mode 100644 index 000000000..52b0957ea --- /dev/null +++ b/alarm/uboot-odroid-c1/0001-add-ext4-support.patch @@ -0,0 +1,5827 @@ +From c3261918cac8380a876c2717ace1addefd617fc0 Mon Sep 17 00:00:00 2001 +From: Kevin Mihelich +Date: Sun, 21 Dec 2014 18:01:59 -0700 +Subject: [PATCH 1/3] add ext4 support + +--- + Makefile | 2 +- + common/Makefile | 1 + + common/cmd_ext4.c | 407 +++++++ + doc/README.ext4 | 42 + + fs/Makefile | 1 + + fs/ext2/ext2fs.c | 179 +-- + fs/ext4/Makefile | 56 + + fs/ext4/crc16.c | 62 + + fs/ext4/crc16.h | 16 + + fs/ext4/dev.c | 145 +++ + fs/ext4/ext4_common.c | 2221 ++++++++++++++++++++++++++++++++++ + fs/ext4/ext4_common.h | 88 ++ + fs/ext4/ext4_journal.c | 666 ++++++++++ + fs/ext4/ext4_journal.h | 141 +++ + fs/ext4/ext4fs.c | 1189 ++++++++++++++++++ + include/config_cmd_all.h | 1 + + include/configs/hardkernel/odroidc.h | 2 + + include/ext4fs.h | 144 +++ + include/ext_common.h | 188 +++ + 19 files changed, 5394 insertions(+), 157 deletions(-) + create mode 100644 common/cmd_ext4.c + create mode 100644 doc/README.ext4 + create mode 100644 fs/ext4/Makefile + create mode 100644 fs/ext4/crc16.c + create mode 100644 fs/ext4/crc16.h + create mode 100644 fs/ext4/dev.c + create mode 100644 fs/ext4/ext4_common.c + create mode 100644 fs/ext4/ext4_common.h + create mode 100644 fs/ext4/ext4_journal.c + create mode 100644 fs/ext4/ext4_journal.h + create mode 100644 fs/ext4/ext4fs.c + create mode 100644 include/ext4fs.h + create mode 100644 include/ext_common.h + +diff --git a/Makefile b/Makefile +index a04649f..5f66d68 100644 +--- a/Makefile ++++ b/Makefile +@@ -198,7 +198,7 @@ endif + LIBS += arch/$(ARCH)/lib/lib$(ARCH).o + LIBS += fs/cramfs/libcramfs.o fs/fat/libfat.o fs/fdos/libfdos.o fs/jffs2/libjffs2.o \ + fs/reiserfs/libreiserfs.o fs/ext2/libext2fs.o fs/yaffs2/libyaffs2.o \ +- fs/ubifs/libubifs.o ++ fs/ext4/libext4fs.o fs/ubifs/libubifs.o + LIBS += net/libnet.o + LIBS += disk/libdisk.o + LIBS += drivers/bios_emulator/libatibiosemu.o +diff --git a/common/Makefile b/common/Makefile +index 2938551..97aa1d9 100755 +--- a/common/Makefile ++++ b/common/Makefile +@@ -118,6 +118,7 @@ COBJS-$(CONFIG_CMD_EEPROM) += cmd_eeprom.o + COBJS-$(CONFIG_CMD_ELF) += cmd_elf.o + COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_exit.o + COBJS-$(CONFIG_CMD_EXT2) += cmd_ext2.o ++COBJS-$(CONFIG_CMD_EXT4) += cmd_ext4.o + COBJS-$(CONFIG_CMD_FAT) += cmd_fat.o + COBJS-$(CONFIG_CMD_FDC)$(CONFIG_CMD_FDOS) += cmd_fdc.o + COBJS-$(CONFIG_OF_LIBFDT) += cmd_fdt.o fdt_support.o +diff --git a/common/cmd_ext4.c b/common/cmd_ext4.c +new file mode 100644 +index 0000000..449a9c4 +--- /dev/null ++++ b/common/cmd_ext4.c +@@ -0,0 +1,407 @@ ++/* ++ * (C) Copyright 2011 - 2012 Samsung Electronics ++ * EXT4 filesystem implementation in Uboot by ++ * Uma Shankar ++ * Manjunatha C Achar ++ * ++ * Ext4fs support ++ * made from existing cmd_ext2.c file of Uboot ++ * ++ * (C) Copyright 2004 ++ * esd gmbh ++ * Reinhard Arlt ++ * ++ * made from cmd_reiserfs by ++ * ++ * (C) Copyright 2003 - 2004 ++ * Sysgo Real-Time Solutions, AG ++ * Pavel Bartusek ++ * ++ * 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 ++ * ++ */ ++ ++/* ++ * Changelog: ++ * 0.1 - Newly created file for ext4fs support. Taken from cmd_ext2.c ++ * file in uboot. Added ext4fs ls load and write support. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE) ++#include ++#endif ++ ++#if !defined(CONFIG_DOS_PARTITION) && !defined(CONFIG_EFI_PARTITION) ++#error DOS or EFI partition support must be selected ++#endif ++ ++uint64_t total_sector; ++uint64_t part_offset; ++#if defined(CONFIG_CMD_EXT4_WRITE) ++static uint64_t part_size; ++static uint16_t cur_part = 1; ++#endif ++ ++#define DOS_PART_MAGIC_OFFSET 0x1fe ++#define DOS_FS_TYPE_OFFSET 0x36 ++#define DOS_FS32_TYPE_OFFSET 0x52 ++ ++static int do_ext4_load(cmd_tbl_t *cmdtp, int flag, int argc, ++ char *const argv[]) ++{ ++ char *filename = NULL; ++ char *ep; ++ int dev; ++ unsigned long part = 1; ++ ulong addr = 0; ++ ulong part_length; ++ int filelen; ++ disk_partition_t info; ++ struct ext_filesystem *fs; ++ char buf[12]; ++ unsigned long count; ++ const char *addr_str; ++ ++ count = 0; ++ addr = simple_strtoul(argv[3], NULL, 16); ++ filename = getenv("bootfile"); ++ switch (argc) { ++ case 3: ++ addr_str = getenv("loadaddr"); ++ if (addr_str != NULL) ++ addr = simple_strtoul(addr_str, NULL, 16); ++ else ++ addr = CONFIG_SYS_LOAD_ADDR; ++ ++ break; ++ case 4: ++ break; ++ case 5: ++ filename = argv[4]; ++ break; ++ case 6: ++ filename = argv[4]; ++ count = simple_strtoul(argv[5], NULL, 16); ++ break; ++ ++ default: ++ return cmd_usage(cmdtp); ++ } ++ ++ if (!filename) { ++ puts("** No boot file defined **\n"); ++ return 1; ++ } ++ ++ dev = (int)simple_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"); ++ return 1; ++ } ++ part = simple_strtoul(++ep, NULL, 16); ++ } ++ ++ if (part != 0) { ++ if (get_partition_info(fs->dev_desc, part, &info)) { ++ printf("** Bad partition %lu **\n", part); ++ return 1; ++ } ++ ++ if (strncmp((char *)info.type, BOOT_PART_TYPE, ++ strlen(BOOT_PART_TYPE)) != 0) { ++ printf("** Invalid partition type \"%s\"" ++ " (expect \"" BOOT_PART_TYPE "\")\n", info.type); ++ return 1; ++ } ++ printf("Loading file \"%s\" " ++ "from %s device %d:%lu %s\n", ++ filename, argv[1], dev, part, info.name); ++ } else { ++ printf("Loading file \"%s\" from %s device %d\n", ++ filename, argv[1], dev); ++ } ++ ++ part_length = ext4fs_set_blk_dev(fs->dev_desc, part); ++ if (part_length == 0) { ++ printf("**Bad partition - %s %d:%lu **\n", argv[1], dev, part); ++ ext4fs_close(); ++ return 1; ++ } ++ ++ if (!ext4fs_mount(part_length)) { ++ printf("** Bad ext4 partition or disk - %s %d:%lu **\n", ++ argv[1], dev, part); ++ ext4fs_close(); ++ return 1; ++ } ++ ++ filelen = ext4fs_open(filename); ++ if (filelen < 0) { ++ printf("** File not found %s\n", filename); ++ ext4fs_close(); ++ return 1; ++ } ++ if ((count < filelen) && (count != 0)) ++ filelen = count; ++ ++ if (ext4fs_read((char *)addr, filelen) != filelen) { ++ printf("** Unable to read \"%s\" from %s %d:%lu **\n", ++ filename, argv[1], dev, part); ++ ext4fs_close(); ++ return 1; ++ } ++ ++ ext4fs_close(); ++ deinit_fs(fs->dev_desc); ++ /* Loading ok, update default load address */ ++ load_addr = addr; ++ ++ printf("%d bytes read\n", filelen); ++ sprintf(buf, "%X", filelen); ++ setenv("filesize", buf); ++ ++ return 0; ++} ++ ++static int do_ext4_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) ++{ ++ const char *filename = "/"; ++ int dev; ++ unsigned long part = 1; ++ char *ep; ++ struct ext_filesystem *fs; ++ int part_length; ++ ++ if (argc < 3) ++ return cmd_usage(cmdtp); ++ ++ dev = (int)simple_strtoul(argv[2], &ep, 16); ++ ext4_dev_desc = get_dev(argv[1], dev); ++ ++ if (ext4_dev_desc == NULL) { ++ printf("\n** 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("\n** Invalid boot device, use `dev[:part]' **\n"); ++ return 1; ++ } ++ part = simple_strtoul(++ep, NULL, 16); ++ } ++ ++ if (argc == 4) ++ filename = argv[3]; ++ ++ part_length = ext4fs_set_blk_dev(fs->dev_desc, part); ++ if (part_length == 0) { ++ printf("** Bad partition - %s %d:%lu **\n", argv[1], dev, part); ++ ext4fs_close(); ++ return 1; ++ } ++ ++ if (!ext4fs_mount(part_length)) { ++ printf("** Bad ext4 partition or disk - %s %d:%lu **\n", ++ argv[1], dev, part); ++ ext4fs_close(); ++ return 1; ++ } ++ if (ext4fs_ls(filename)) { ++ printf("** Error ext4fs_ls() **\n"); ++ ext4fs_close(); ++ return 1; ++ }; ++ ++ ext4fs_close(); ++ deinit_fs(fs->dev_desc); ++ ++ return 0; ++} ++ ++#if defined(CONFIG_CMD_EXT4_WRITE) ++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; ++} ++ ++static int do_ext4_write(cmd_tbl_t *cmdtp, int flag, int argc, ++ char *const argv[]) ++{ ++ const char *filename = "/"; ++ int part_length; ++ unsigned long part = 1; ++ int dev; ++ char *ep; ++ unsigned long ram_address; ++ unsigned long file_size; ++ disk_partition_t info; ++ struct ext_filesystem *fs; ++ ++ if (argc < 6) ++ return cmd_usage(cmdtp); ++ ++ dev = (int)simple_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 = simple_strtoul(++ep, NULL, 16); ++ } ++ ++ /* get the filename */ ++ filename = argv[3]; ++ ++ /* get the address in hexadecimal format (string to int) */ ++ ram_address = simple_strtoul(argv[4], NULL, 16); ++ ++ /* get the filesize in base 10 format */ ++ file_size = simple_strtoul(argv[5], NULL, 10); ++ ++ /* set the device as block device */ ++ part_length = ext4fs_set_blk_dev(fs->dev_desc, part); ++ if (part_length == 0) { ++ printf("Bad partition - %s %d:%lu\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:%lu 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:%lu\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(ext4write, 6, 1, do_ext4_write, ++ "create a file in the root directory", ++ " [Absolute filename path] [Address] [sizebytes]\n" ++ " - create a file in / directory"); ++ ++#endif ++ ++U_BOOT_CMD(ext4ls, 4, 1, do_ext4_ls, ++ "list files in a directory (default /)", ++ " [directory]\n" ++ " - list files from 'dev' on 'interface' in a 'directory'"); ++ ++U_BOOT_CMD(ext4load, 6, 0, do_ext4_load, ++ "load binary file from a Ext4 filesystem", ++ " [addr] [filename] [bytes]\n" ++ " - load binary file 'filename' from 'dev' on 'interface'\n" ++ " to address 'addr' from ext4 filesystem"); +diff --git a/doc/README.ext4 b/doc/README.ext4 +new file mode 100644 +index 0000000..aeb1adf +--- /dev/null ++++ b/doc/README.ext4 +@@ -0,0 +1,42 @@ ++This patch series adds support for ext4 ls,load and write features in uboot ++Journaling is supported for write feature. ++ ++To Enable ext4 ls and load commands, modify the board specific config file with ++#define CONFIG_CMD_EXT4 ++ ++To enable ext4 write command, modify the board specific config file with ++#define CONFIG_CMD_EXT4_WRITE ++ ++Steps to test: ++ ++1. After applying the patch, ext4 specific commands can be seen ++ in the boot loader prompt using ++ UBOOT #help ++ ++ ext4load- load binary file from a Ext4 file system ++ ext4ls - list files in a directory (default /) ++ ext4write- create a file in ext4 formatted partition ++ ++2. To list the files in ext4 formatted partition, execute ++ ext4ls <interface> <dev[:part]> [directory] ++ For example: ++ UBOOT #ext4ls mmc 0:5 /usr/lib ++ ++3. To read and load a file from an ext4 formatted partition to RAM, execute ++ ext4load <interface> <dev[:part]> [addr] [filename] [bytes] ++ For example: ++ UBOOT #ext4load mmc 2:2 0x30007fc0 uImage ++ ++4. To write a file to a ext4 formatted partition. ++ a) First load a file to RAM at a particular address for example 0x30007fc0. ++ Now execute ext4write command ++ ext4write <interface> <dev[:part]> [filename] [Address] [sizebytes] ++ For example: ++ UBOOT #ext4write mmc 2:2 /boot/uImage 0x30007fc0 6183120 ++ (here 6183120 is the size of the file to be written) ++ Note: Absolute path is required for the file to be written ++ ++References : ++ -- ext4 implementation in Linux Kernel ++ -- Uboot existing ext2 load and ls implementation ++ -- Journaling block device JBD2 implementation in linux Kernel +diff --git a/fs/Makefile b/fs/Makefile +index 22aad12..27330d4 100644 +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -24,6 +24,7 @@ + + subdirs-$(CONFIG_CMD_CRAMFS) := cramfs + subdirs-$(CONFIG_CMD_EXT2) += ext2 ++subdirs-$(CONFIG_CMD_EXT4) += ext4 + subdirs-$(CONFIG_CMD_FAT) += fat + subdirs-$(CONFIG_CMD_FDOS) += fdos + subdirs-$(CONFIG_CMD_JFFS2) += jffs2 +diff --git a/fs/ext2/ext2fs.c b/fs/ext2/ext2fs.c +index e119e13..e4423fb 100644 +--- a/fs/ext2/ext2fs.c ++++ b/fs/ext2/ext2fs.c +@@ -25,152 +25,16 @@ + + #include + #include ++#include + #include + #include + + extern int ext2fs_devread (int sector, int byte_offset, int byte_len, + char *buf); + +-/* Magic value used to identify an ext2 filesystem. */ +-#define EXT2_MAGIC 0xEF53 +-/* Amount of indirect blocks in an inode. */ +-#define INDIRECT_BLOCKS 12 +-/* Maximum lenght of a pathname. */ +-#define EXT2_PATH_MAX 4096 +-/* Maximum nesting of symlinks, used to prevent a loop. */ +-#define EXT2_MAX_SYMLINKCNT 8 +- +-/* Filetype used in directory entry. */ +-#define FILETYPE_UNKNOWN 0 +-#define FILETYPE_REG 1 +-#define FILETYPE_DIRECTORY 2 +-#define FILETYPE_SYMLINK 7 +- +-/* Filetype information as used in inodes. */ +-#define FILETYPE_INO_MASK 0170000 +-#define FILETYPE_INO_REG 0100000 +-#define FILETYPE_INO_DIRECTORY 0040000 +-#define FILETYPE_INO_SYMLINK 0120000 +- +-/* Bits used as offset in sector */ +-#define DISK_SECTOR_BITS 9 +- +-/* Log2 size of ext2 block in 512 blocks. */ +-#define LOG2_EXT2_BLOCK_SIZE(data) (__le32_to_cpu (data->sblock.log2_block_size) + 1) +- +-/* Log2 size of ext2 block in bytes. */ +-#define LOG2_BLOCK_SIZE(data) (__le32_to_cpu (data->sblock.log2_block_size) + 10) +- +-/* The size of an ext2 block in bytes. */ +-#define EXT2_BLOCK_SIZE(data) (1 << LOG2_BLOCK_SIZE(data)) +- +-/* The ext2 superblock. */ +-struct ext2_sblock { +- uint32_t total_inodes; +- uint32_t total_blocks; +- uint32_t reserved_blocks; +- uint32_t free_blocks; +- uint32_t free_inodes; +- uint32_t first_data_block; +- uint32_t log2_block_size; +- uint32_t log2_fragment_size; +- uint32_t blocks_per_group; +- uint32_t fragments_per_group; +- uint32_t inodes_per_group; +- uint32_t mtime; +- uint32_t utime; +- uint16_t mnt_count; +- uint16_t max_mnt_count; +- uint16_t magic; +- uint16_t fs_state; +- uint16_t error_handling; +- uint16_t minor_revision_level; +- uint32_t lastcheck; +- uint32_t checkinterval; +- uint32_t creator_os; +- uint32_t revision_level; +- uint16_t uid_reserved; +- uint16_t gid_reserved; +- uint32_t first_inode; +- uint16_t inode_size; +- uint16_t block_group_number; +- uint32_t feature_compatibility; +- uint32_t feature_incompat; +- uint32_t feature_ro_compat; +- uint32_t unique_id[4]; +- char volume_name[16]; +- char last_mounted_on[64]; +- uint32_t compression_info; +-}; +- +-/* The ext2 blockgroup. */ +-struct ext2_block_group { +- uint32_t block_id; +- uint32_t inode_id; +- uint32_t inode_table_id; +- uint16_t free_blocks; +- uint16_t free_inodes; +- uint16_t used_dir_cnt; +- uint32_t reserved[3]; +-}; +- +-/* The ext2 inode. */ +-struct ext2_inode { +- uint16_t mode; +- uint16_t uid; +- uint32_t size; +- uint32_t atime; +- uint32_t ctime; +- uint32_t mtime; +- uint32_t dtime; +- uint16_t gid; +- uint16_t nlinks; +- uint32_t blockcnt; /* Blocks of 512 bytes!! */ +- uint32_t flags; +- uint32_t osd1; +- union { +- struct datablocks { +- uint32_t dir_blocks[INDIRECT_BLOCKS]; +- uint32_t indir_block; +- uint32_t double_indir_block; +- uint32_t tripple_indir_block; +- } blocks; +- char symlink[60]; +- } b; +- uint32_t version; +- uint32_t acl; +- uint32_t dir_acl; +- uint32_t fragment_addr; +- uint32_t osd2[3]; +-}; +- +-/* The header of an ext2 directory entry. */ +-struct ext2_dirent { +- uint32_t inode; +- uint16_t direntlen; +- uint8_t namelen; +- uint8_t filetype; +-}; +- +-struct ext2fs_node { +- struct ext2_data *data; +- struct ext2_inode inode; +- int ino; +- int inode_read; +-}; +- +-/* Information about a "mounted" ext2 filesystem. */ +-struct ext2_data { +- struct ext2_sblock sblock; +- struct ext2_inode *inode; +- struct ext2fs_node diropen; +-}; +- +- +-typedef struct ext2fs_node *ext2fs_node_t; + + struct ext2_data *ext2fs_root = NULL; +-ext2fs_node_t ext2fs_file = NULL; ++struct ext2fs_node *ext2fs_file; + int symlinknest = 0; + uint32_t *indir1_block = NULL; + int indir1_size = 0; +@@ -243,14 +107,14 @@ static int ext2fs_read_inode + } + + +-void ext2fs_free_node (ext2fs_node_t node, ext2fs_node_t currroot) { ++void ext2fs_free_node (struct ext2fs_node *node, struct ext2fs_node *currroot) { + if ((node != &ext2fs_root->diropen) && (node != currroot)) { + free (node); + } + } + + +-static int ext2fs_read_block (ext2fs_node_t node, int fileblock) { ++static int ext2fs_read_block (struct ext2fs_node *node, int fileblock) { + struct ext2_data *data = node->data; + struct ext2_inode *inode = &node->inode; + int blknr; +@@ -390,7 +254,8 @@ static int ext2fs_read_block (ext2fs_node_t node, int fileblock) { + + + int ext2fs_read_file +- (ext2fs_node_t node, int pos, unsigned int len, char *buf) { ++ (struct ext2fs_node *node, int pos, unsigned int len, char *buf) ++{ + int i; + int blockcnt; + int log2blocksize = LOG2_EXT2_BLOCK_SIZE (node->data); +@@ -449,8 +314,8 @@ int ext2fs_read_file + return (len); + } + +- +-static int ext2fs_iterate_dir (ext2fs_node_t dir, char *name, ext2fs_node_t * fnode, int *ftype) ++int ext2fs_iterate_dir(struct ext2fs_node *dir, char *name, ++ struct ext2fs_node **fnode, int *ftype) + { + unsigned int fpos = 0; + int status; +@@ -479,7 +344,7 @@ static int ext2fs_iterate_dir (ext2fs_node_t dir, char *name, ext2fs_node_t * fn + } + if (dirent.namelen != 0) { + char filename[dirent.namelen + 1]; +- ext2fs_node_t fdiro; ++ struct ext2fs_node *fdiro; + int type = FILETYPE_UNKNOWN; + + status = ext2fs_read_file (diro, +@@ -581,8 +446,8 @@ static int ext2fs_iterate_dir (ext2fs_node_t dir, char *name, ext2fs_node_t * fn + return (0); + } + +- +-static char *ext2fs_read_symlink (ext2fs_node_t node) { ++static char *ext2fs_read_symlink(struct ext2fs_node *node) ++{ + char *symlink; + struct ext2fs_node *diro = node; + int status; +@@ -619,15 +484,16 @@ static char *ext2fs_read_symlink (ext2fs_node_t node) { + + + int ext2fs_find_file1 +- (const char *currpath, +- ext2fs_node_t currroot, ext2fs_node_t * currfound, int *foundtype) { ++ (const char *currpath, struct ext2fs_node *currroot, ++ struct ext2fs_node **currfound, int *foundtype) ++{ + char fpath[strlen (currpath) + 1]; + char *name = fpath; + char *next; + int status; + int type = FILETYPE_DIRECTORY; +- ext2fs_node_t currnode = currroot; +- ext2fs_node_t oldnode = currroot; ++ struct ext2fs_node *currnode = currroot; ++ struct ext2fs_node *oldnode = currroot; + + strncpy (fpath, currpath, strlen (currpath) + 1); + +@@ -723,8 +589,9 @@ int ext2fs_find_file1 + + + int ext2fs_find_file +- (const char *path, +- ext2fs_node_t rootnode, ext2fs_node_t * foundnode, int expecttype) { ++ (const char *path, struct ext2fs_node *rootnode, ++ struct ext2fs_node **foundnode, int expecttype) ++{ + int status; + int foundtype = FILETYPE_DIRECTORY; + +@@ -750,7 +617,7 @@ int ext2fs_find_file + + + int ext2fs_ls (const char *dirname) { +- ext2fs_node_t dirnode; ++ struct ext2fs_node *dirnode; + int status; + + if (ext2fs_root == NULL) { +@@ -770,7 +637,7 @@ int ext2fs_ls (const char *dirname) { + + + int ext2fs_open (const char *filename) { +- ext2fs_node_t fdiro = NULL; ++ struct ext2fs_node *fdiro = NULL; + int status; + int len; + +@@ -800,8 +667,8 @@ fail: + } + + +-int ext2fs_close (void +- ) { ++int ext2fs_close(void) ++{ + if ((ext2fs_file != NULL) && (ext2fs_root != NULL)) { + ext2fs_free_node (ext2fs_file, &ext2fs_root->diropen); + ext2fs_file = NULL; +diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile +new file mode 100644 +index 0000000..e25daa3 +--- /dev/null ++++ b/fs/ext4/Makefile +@@ -0,0 +1,56 @@ ++# ++# (C) Copyright 2006 ++# Wolfgang Denk, DENX Software Engineering, wd at denx.de. ++# ++# (C) Copyright 2003 ++# Pavel Bartusek, Sysgo Real-Time Solutions AG, pba at sysgo.de ++# ++# ++# See file CREDITS for list of people who contributed to this ++# project. ++# ++# 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)libext4fs.o ++ ++AOBJS = ++COBJS-$(CONFIG_CMD_EXT4) := ext4fs.o ext4_common.o dev.o ++ifndef CONFIG_CMD_EXT4 ++COBJS-$(CONFIG_CMD_EXT4_WRITE) := ext4fs.o ext4_common.o dev.o ++endif ++COBJS-$(CONFIG_CMD_EXT4_WRITE) += ext4_journal.o crc16.o ++ ++SRCS := $(AOBJS:.o=.S) $(COBJS-y:.o=.c) ++OBJS := $(addprefix $(obj),$(AOBJS) $(COBJS-y)) ++ ++ ++all: $(LIB) $(AOBJS) ++ ++$(LIB): $(obj).depend $(OBJS) ++ $(AR) $(ARFLAGS) $@ $(OBJS) ++# $(call cmd_link_o_target, $(OBJS)) ++ ++######################################################################### ++ ++# defines $(obj).depend target ++include $(SRCTREE)/rules.mk ++ ++sinclude $(obj).depend ++ ++######################################################################### +diff --git a/fs/ext4/crc16.c b/fs/ext4/crc16.c +new file mode 100644 +index 0000000..379bd22 +--- /dev/null ++++ b/fs/ext4/crc16.c +@@ -0,0 +1,62 @@ ++/* ++ * crc16.c ++ * ++ * This source code is licensed under the GNU General Public License, ++ * Version 2. See the file COPYING for more details. ++ */ ++ ++#include ++#include ++#include ++#include "crc16.h" ++ ++/** CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1) */ ++static __u16 const crc16_table[256] = { ++ 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, ++ 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, ++ 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, ++ 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, ++ 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, ++ 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, ++ 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, ++ 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, ++ 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, ++ 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, ++ 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, ++ 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, ++ 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, ++ 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, ++ 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, ++ 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, ++ 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, ++ 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, ++ 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, ++ 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, ++ 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, ++ 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, ++ 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, ++ 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, ++ 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, ++ 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, ++ 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, ++ 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, ++ 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, ++ 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, ++ 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, ++ 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 ++}; ++ ++/** ++ * Compute the CRC-16 for the data buffer ++*/ ++ ++unsigned int ext2fs_crc16(unsigned int crc, ++ const void *buffer, unsigned int len) ++{ ++ const unsigned char *cp = buffer; ++ ++ while (len--) ++ crc = (((crc >> 8) & 0xffU) ^ ++ crc16_table[(crc ^ *cp++) & 0xffU]) & 0x0000ffffU; ++ return crc; ++} +diff --git a/fs/ext4/crc16.h b/fs/ext4/crc16.h +new file mode 100644 +index 0000000..cefb2b6 +--- /dev/null ++++ b/fs/ext4/crc16.h +@@ -0,0 +1,16 @@ ++/* ++ * 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 <bgardner at wabtec.com> ++ * 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 ++extern unsigned int ext2fs_crc16(unsigned int crc, ++ const void *buffer, unsigned int len); ++#endif +diff --git a/fs/ext4/dev.c b/fs/ext4/dev.c +new file mode 100644 +index 0000000..56dd669 +--- /dev/null ++++ b/fs/ext4/dev.c +@@ -0,0 +1,145 @@ ++/* ++ * (C) Copyright 2011 - 2012 Samsung Electronics ++ * EXT4 filesystem implementation in Uboot by ++ * Uma Shankar <uma.shankar at samsung.com> ++ * Manjunatha C Achar <a.manjunatha at samsung.com> ++ * ++ * made from existing ext2/dev.c file of Uboot ++ * (C) Copyright 2004 ++ * esd gmbh ++ * Reinhard Arlt <reinhard.arlt at esd-electronics.com> ++ * ++ * based on code of fs/reiserfs/dev.c by ++ * ++ * (C) Copyright 2003 - 2004 ++ * Sysgo AG, , Pavel Bartusek <pba at sysgo.com> ++ * ++ * 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. ++ * ++ */ ++ ++/* ++ * Changelog: ++ * 0.1 - Newly created file for ext4fs support. Taken from ++ * fs/ext2/dev.c file in uboot. ++ */ ++ ++#include ++#include ++#include ++ ++static block_dev_desc_t *ext4fs_block_dev_desc; ++static disk_partition_t part_info; ++ ++int ext4fs_set_blk_dev(block_dev_desc_t *rbdd, int part) ++{ ++ ext4fs_block_dev_desc = rbdd; ++ ++ if (part == 0) { ++ /* disk doesn't use partition table */ ++ part_info.start = 0; ++ part_info.size = rbdd->lba; ++ part_info.blksz = rbdd->blksz; ++ } else { ++ if (get_partition_info(ext4fs_block_dev_desc, ++ part, &part_info)) ++ return 0; ++ } ++ return part_info.size; ++} ++ ++int ext4fs_devread(int sector, int byte_offset, int byte_len, char *buf) ++{ ++ char sec_buf[SECTOR_SIZE]; ++ unsigned block_len; ++ ++ /* Check partition boundaries */ ++ if ((sector < 0) ++ || ((sector + ((byte_offset + byte_len - 1) >> SECTOR_BITS)) >= ++ part_info.size)) { ++ printf("%s read outside partition %d\n", __func__, sector); ++ return 0; ++ } ++ ++ /* Get the read to the beginning of a partition */ ++ sector += byte_offset >> SECTOR_BITS; ++ byte_offset &= SECTOR_SIZE - 1; ++ ++ debug(" <%d, %d, %d>\n", sector, byte_offset, byte_len); ++ ++ if (ext4fs_block_dev_desc == NULL) { ++ printf("** Invalid Block Device Descriptor (NULL)\n"); ++ return 0; ++ } ++ ++ if (byte_offset != 0) { ++ /* read first part which isn't aligned with start of sector */ ++ if (ext4fs_block_dev_desc-> ++ block_read(ext4fs_block_dev_desc->dev, ++ part_info.start + sector, 1, ++ (unsigned long *) sec_buf) != 1) { ++ printf(" ** ext2fs_devread() read error **\n"); ++ return 0; ++ } ++ memcpy(buf, sec_buf + byte_offset, ++ min(SECTOR_SIZE - byte_offset, byte_len)); ++ buf += min(SECTOR_SIZE - byte_offset, byte_len); ++ byte_len -= min(SECTOR_SIZE - byte_offset, byte_len); ++ sector++; ++ } ++ ++ if (byte_len == 0) ++ return 1; ++ ++ /* read sector aligned part */ ++ block_len = byte_len & ~(SECTOR_SIZE - 1); ++ ++ if (block_len == 0) { ++ u8 p[SECTOR_SIZE]; ++ ++ block_len = SECTOR_SIZE; ++ ext4fs_block_dev_desc->block_read(ext4fs_block_dev_desc->dev, ++ part_info.start + sector, ++ 1, (unsigned long *)p); ++ memcpy(buf, p, byte_len); ++ return 1; ++ } ++ ++ if (ext4fs_block_dev_desc->block_read(ext4fs_block_dev_desc->dev, ++ part_info.start + sector, ++ block_len / SECTOR_SIZE, ++ (unsigned long *) buf) != ++ block_len / SECTOR_SIZE) { ++ printf(" ** %s read error - block\n", __func__); ++ return 0; ++ } ++ block_len = byte_len & ~(SECTOR_SIZE - 1); ++ buf += block_len; ++ byte_len -= block_len; ++ sector += block_len / SECTOR_SIZE; ++ ++ if (byte_len != 0) { ++ /* read rest of data which are not in whole sector */ ++ if (ext4fs_block_dev_desc-> ++ block_read(ext4fs_block_dev_desc->dev, ++ part_info.start + sector, 1, ++ (unsigned long *) sec_buf) != 1) { ++ printf("* %s read error - last part\n", __func__); ++ return 0; ++ } ++ memcpy(buf, sec_buf, byte_len); ++ } ++ return 1; ++} +diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c +new file mode 100644 +index 0000000..b0f3df2 +--- /dev/null ++++ b/fs/ext4/ext4_common.c +@@ -0,0 +1,2221 @@ ++/* ++ * (C) Copyright 2011 - 2012 Samsung Electronics ++ * EXT4 filesystem implementation in Uboot by ++ * Uma Shankar <uma.shankar at samsung.com> ++ * Manjunatha C Achar <a.manjunatha at samsung.com> ++ * ++ * ext4ls and ext4load : Based on ext2 ls load support in Uboot. ++ * ++ * (C) Copyright 2004 ++ * esd gmbh ++ * Reinhard Arlt <reinhard.arlt at 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ext4_common.h" ++ ++struct ext2_data *ext4fs_root; ++struct ext2fs_node *ext4fs_file; ++uint32_t *ext4fs_indir1_block; ++int ext4fs_indir1_size; ++int ext4fs_indir1_blkno = -1; ++uint32_t *ext4fs_indir2_block; ++int ext4fs_indir2_size; ++int ext4fs_indir2_blkno = -1; ++ ++uint32_t *ext4fs_indir3_block; ++int ext4fs_indir3_size; ++int ext4fs_indir3_blkno = -1; ++struct ext2_inode *g_parent_inode; ++static int symlinknest; ++ ++#if defined(CONFIG_CMD_EXT4_WRITE) ++uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n) ++{ ++ uint32_t res = size / n; ++ if (res * n != size) ++ res++; ++ ++ return res; ++} ++ ++void put_ext4(uint64_t off, void *buf, uint32_t size) ++{ ++ uint64_t startblock; ++ uint64_t remainder; ++ unsigned char *temp_ptr = NULL; ++ unsigned char sec_buf[SECTOR_SIZE]; ++ struct ext_filesystem *fs = get_fs(); ++ ++ startblock = off / (uint64_t) SECTOR_SIZE; ++ startblock += part_offset; ++ remainder = off % (uint64_t) SECTOR_SIZE; ++ remainder &= SECTOR_SIZE - 1; ++ ++ if (fs->dev_desc == NULL) ++ return; ++ ++ if ((startblock + (size / SECTOR_SIZE)) > ++ (part_offset + fs->total_sect)) { ++ printf("part_offset is %lu\n", part_offset); ++ printf("total_sector is %llu\n", fs->total_sect); ++ printf("error: overflow occurs\n"); ++ return; ++ } ++ ++ if (remainder) { ++ if (fs->dev_desc->block_read) { ++ fs->dev_desc->block_read(fs->dev_desc->dev, ++ startblock, 1, sec_buf); ++ temp_ptr = sec_buf; ++ memcpy((temp_ptr + remainder), ++ (unsigned char *)buf, size); ++ fs->dev_desc->block_write(fs->dev_desc->dev, ++ startblock, 1, sec_buf); ++ } ++ } else { ++ if (size / SECTOR_SIZE != 0) { ++ fs->dev_desc->block_write(fs->dev_desc->dev, ++ startblock, ++ size / SECTOR_SIZE, ++ (unsigned long *)buf); ++ } else { ++ fs->dev_desc->block_read(fs->dev_desc->dev, ++ startblock, 1, sec_buf); ++ temp_ptr = sec_buf; ++ memcpy(temp_ptr, buf, size); ++ fs->dev_desc->block_write(fs->dev_desc->dev, ++ startblock, 1, ++ (unsigned long *)sec_buf); ++ } ++ } ++} ++ ++static int _get_new_inode_no(unsigned char *buffer) ++{ ++ struct ext_filesystem *fs = get_fs(); ++ unsigned char input; ++ int operand, status; ++ int count = 1; ++ int j = 0; ++ ++ /* get the blocksize of the filesystem */ ++ unsigned char *ptr = buffer; ++ while (*ptr == 255) { ++ ptr++; ++ count += 8; ++ if (count > ext4fs_root->sblock.inodes_per_group) ++ return -1; ++ } ++ ++ for (j = 0; j < fs->blksz; j++) { ++ input = *ptr; ++ int i = 0; ++ while (i <= 7) { ++ operand = 1 << i; ++ status = input & operand; ++ if (status) { ++ i++; ++ count++; ++ } else { ++ *ptr |= operand; ++ return count; ++ } ++ } ++ ptr = ptr + 1; ++ } ++ ++ return -1; ++} ++ ++static int _get_new_blk_no(unsigned char *buffer) ++{ ++ unsigned char input; ++ int operand, status; ++ int count = 0; ++ int j = 0; ++ unsigned char *ptr = buffer; ++ struct ext_filesystem *fs = get_fs(); ++ ++ if (fs->blksz != 1024) ++ count = 0; ++ else ++ count = 1; ++ ++ while (*ptr == 255) { ++ ptr++; ++ count += 8; ++ if (count == (fs->blksz * 8)) ++ return -1; ++ } ++ ++ for (j = 0; j < fs->blksz; j++) { ++ input = *ptr; ++ int i = 0; ++ while (i <= 7) { ++ operand = 1 << i; ++ status = input & operand; ++ if (status) { ++ i++; ++ count++; ++ } else { ++ *ptr |= operand; ++ return count; ++ } ++ } ++ ptr = ptr + 1; ++ } ++ ++ return -1; ++} ++ ++int ext4fs_set_block_bmap(long int blockno, unsigned char *buffer, int index) ++{ ++ int i, remainder, status; ++ unsigned char *ptr = buffer; ++ unsigned char operand; ++ i = blockno / 8; ++ remainder = blockno % 8; ++ int blocksize = EXT2_BLOCK_SIZE(ext4fs_root); ++ ++ i = i - (index * blocksize); ++ if (blocksize != 1024) { ++ ptr = ptr + i; ++ operand = 1 << remainder; ++ status = *ptr & operand; ++ if (status) ++ return -1; ++ ++ *ptr = *ptr | operand; ++ return 0; ++ } else { ++ if (remainder == 0) { ++ ptr = ptr + i - 1; ++ operand = (1 << 7); ++ } else { ++ ptr = ptr + i; ++ operand = (1 << (remainder - 1)); ++ } ++ status = *ptr & operand; ++ if (status) ++ return -1; ++ ++ *ptr = *ptr | operand; ++ return 0; ++ } ++} ++ ++void ext4fs_reset_block_bmap(long int blockno, unsigned char *buffer, int index) ++{ ++ int i, remainder, status; ++ unsigned char *ptr = buffer; ++ unsigned char operand; ++ i = blockno / 8; ++ remainder = blockno % 8; ++ int blocksize = EXT2_BLOCK_SIZE(ext4fs_root); ++ ++ i = i - (index * blocksize); ++ if (blocksize != 1024) { ++ ptr = ptr + i; ++ operand = (1 << remainder); ++ status = *ptr & operand; ++ if (status) ++ *ptr = *ptr & ~(operand); ++ } else { ++ if (remainder == 0) { ++ ptr = ptr + i - 1; ++ operand = (1 << 7); ++ } else { ++ ptr = ptr + i; ++ operand = (1 << (remainder - 1)); ++ } ++ status = *ptr & operand; ++ if (status) ++ *ptr = *ptr & ~(operand); ++ } ++} ++ ++int ext4fs_set_inode_bmap(int inode_no, unsigned char *buffer, int index) ++{ ++ int i, remainder, status; ++ unsigned char *ptr = buffer; ++ unsigned char operand; ++ ++ inode_no -= (index * ext4fs_root->sblock.inodes_per_group); ++ i = inode_no / 8; ++ remainder = inode_no % 8; ++ if (remainder == 0) { ++ ptr = ptr + i - 1; ++ operand = (1 << 7); ++ } else { ++ ptr = ptr + i; ++ operand = (1 << (remainder - 1)); ++ } ++ status = *ptr & operand; ++ if (status) ++ return -1; ++ ++ *ptr = *ptr | operand; ++ ++ return 0; ++} ++ ++void ext4fs_reset_inode_bmap(int inode_no, unsigned char *buffer, int index) ++{ ++ int i, remainder, status; ++ unsigned char *ptr = buffer; ++ unsigned char operand; ++ ++ inode_no -= (index * ext4fs_root->sblock.inodes_per_group); ++ i = inode_no / 8; ++ remainder = inode_no % 8; ++ if (remainder == 0) { ++ ptr = ptr + i - 1; ++ operand = (1 << 7); ++ } else { ++ ptr = ptr + i; ++ operand = (1 << (remainder - 1)); ++ } ++ status = *ptr & operand; ++ if (status) ++ *ptr = *ptr & ~(operand); ++} ++ ++int ext4fs_checksum_update(unsigned int i) ++{ ++ struct ext2_block_group *desc; ++ struct ext_filesystem *fs = get_fs(); ++ __u16 crc = 0; ++ ++ desc = (struct ext2_block_group *)&fs->gd[i]; ++ if (fs->sb->feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) { ++ int offset = offsetof(struct ext2_block_group, bg_checksum); ++ ++ crc = ext2fs_crc16(~0, fs->sb->unique_id, ++ sizeof(fs->sb->unique_id)); ++ crc = ext2fs_crc16(crc, &i, sizeof(i)); ++ crc = ext2fs_crc16(crc, desc, offset); ++ offset += sizeof(desc->bg_checksum); /* skip checksum */ ++ assert(offset == sizeof(*desc)); ++ } ++ ++ return crc; ++} ++ ++static int check_void_in_dentry(struct ext2_dirent *dir, char *filename) ++{ ++ int dentry_length; ++ int sizeof_void_space; ++ int new_entry_byte_reqd; ++ short padding_factor = 0; ++ ++ if (dir->namelen % 4 != 0) ++ padding_factor = 4 - (dir->namelen % 4); ++ ++ dentry_length = sizeof(struct ext2_dirent) + ++ dir->namelen + padding_factor; ++ sizeof_void_space = dir->direntlen - dentry_length; ++ if (sizeof_void_space == 0) ++ return 0; ++ ++ padding_factor = 0; ++ if (strlen(filename) % 4 != 0) ++ padding_factor = 4 - (strlen(filename) % 4); ++ ++ new_entry_byte_reqd = strlen(filename) + ++ sizeof(struct ext2_dirent) + padding_factor; ++ if (sizeof_void_space >= new_entry_byte_reqd) { ++ dir->direntlen = dentry_length; ++ return sizeof_void_space; ++ } ++ ++ return 0; ++} ++ ++void ext4fs_update_parent_dentry(char *filename, int *p_ino, int file_type) ++{ ++ unsigned int *zero_buffer = NULL; ++ char *root_first_block_buffer = NULL; ++ int direct_blk_idx; ++ long int root_blknr; ++ long int first_block_no_of_root = 0; ++ long int previous_blknr = -1; ++ int totalbytes = 0; ++ short int padding_factor = 0; ++ unsigned int new_entry_byte_reqd; ++ unsigned int last_entry_dirlen; ++ int sizeof_void_space = 0; ++ int templength = 0; ++ int inodeno; ++ int status; ++ struct ext_filesystem *fs = get_fs(); ++ /* directory entry */ ++ struct ext2_dirent *dir; ++ char *ptr = NULL; ++ char *temp_dir = NULL; ++ ++ zero_buffer = zalloc(fs->blksz); ++ if (!zero_buffer) { ++ printf("No Memory\n"); ++ return; ++ } ++ root_first_block_buffer = zalloc(fs->blksz); ++ if (!root_first_block_buffer) { ++ free(zero_buffer); ++ printf("No Memory\n"); ++ return; ++ } ++ restart: ++ ++ /* read the block no allocated to a file */ ++ for (direct_blk_idx = 0; direct_blk_idx < INDIRECT_BLOCKS; ++ direct_blk_idx++) { ++ root_blknr = read_allocated_block(g_parent_inode, ++ direct_blk_idx); ++ if (root_blknr == 0) { ++ first_block_no_of_root = previous_blknr; ++ break; ++ } ++ previous_blknr = root_blknr; ++ } ++ ++ status = ext4fs_devread(first_block_no_of_root ++ * fs->sect_perblk, ++ 0, fs->blksz, root_first_block_buffer); ++ if (status == 0) ++ goto fail; ++ ++ if (ext4fs_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) { ++ /* ++ * blocksize-totalbytes because last directory length ++ * i.e. dir->direntlen is free availble space in the ++ * block that means it is a last entry of directory ++ * entry ++ */ ++ ++ /* traversing the each directory entry */ ++ if (fs->blksz - totalbytes == dir->direntlen) { ++ if (strlen(filename) % 4 != 0) ++ padding_factor = 4 - (strlen(filename) % 4); ++ ++ new_entry_byte_reqd = strlen(filename) + ++ sizeof(struct ext2_dirent) + padding_factor; ++ padding_factor = 0; ++ /* ++ * update last directory entry length to its ++ * length because we are creating new directory ++ * entry ++ */ ++ if (dir->namelen % 4 != 0) ++ padding_factor = 4 - (dir->namelen % 4); ++ ++ last_entry_dirlen = dir->namelen + ++ sizeof(struct ext2_dirent) + padding_factor; ++ if ((fs->blksz - totalbytes - last_entry_dirlen) < ++ new_entry_byte_reqd) { ++ printf("1st Block Full:Allocate new block\n"); ++ ++ if (direct_blk_idx == INDIRECT_BLOCKS - 1) { ++ printf("Directory exceeds limit\n"); ++ goto fail; ++ } ++ g_parent_inode->b.blocks.dir_blocks ++ [direct_blk_idx] = ext4fs_get_new_blk_no(); ++ if (g_parent_inode->b.blocks.dir_blocks ++ [direct_blk_idx] == -1) { ++ printf("no block left to assign\n"); ++ goto fail; ++ } ++ put_ext4(((uint64_t) ++ (g_parent_inode->b. ++ blocks.dir_blocks[direct_blk_idx] * ++ fs->blksz)), zero_buffer, fs->blksz); ++ g_parent_inode->size = ++ g_parent_inode->size + fs->blksz; ++ g_parent_inode->blockcnt = ++ g_parent_inode->blockcnt + fs->sect_perblk; ++ if (ext4fs_put_metadata ++ (root_first_block_buffer, ++ first_block_no_of_root)) ++ goto fail; ++ goto restart; ++ } ++ dir->direntlen = last_entry_dirlen; ++ break; ++ } ++ ++ templength = dir->direntlen; ++ totalbytes = totalbytes + templength; ++ sizeof_void_space = check_void_in_dentry(dir, filename); ++ if (sizeof_void_space) ++ break; ++ ++ dir = (struct ext2_dirent *)((char *)dir + templength); ++ ptr = (char *)dir; ++ } ++ ++ /* make a pointer ready for creating next directory entry */ ++ templength = dir->direntlen; ++ totalbytes = totalbytes + templength; ++ dir = (struct ext2_dirent *)((char *)dir + templength); ++ ptr = (char *)dir; ++ ++ /* get the next available inode number */ ++ inodeno = ext4fs_get_new_inode_no(); ++ if (inodeno == -1) { ++ printf("no inode left to assign\n"); ++ goto fail; ++ } ++ dir->inode = inodeno; ++ if (sizeof_void_space) ++ dir->direntlen = sizeof_void_space; ++ else ++ dir->direntlen = fs->blksz - totalbytes; ++ ++ dir->namelen = strlen(filename); ++ dir->filetype = FILETYPE_REG; /* regular file */ ++ temp_dir = (char *)dir; ++ temp_dir = temp_dir + sizeof(struct ext2_dirent); ++ memcpy(temp_dir, filename, strlen(filename)); ++ ++ *p_ino = inodeno; ++ ++ /* update or write the 1st block of root inode */ ++ if (ext4fs_put_metadata(root_first_block_buffer, ++ first_block_no_of_root)) ++ goto fail; ++ ++ fail: ++ free(zero_buffer); ++ free(root_first_block_buffer); ++} ++ ++static int search_dir(struct ext2_inode *parent_inode, char *dirname) ++{ ++ int status; ++ int inodeno; ++ int totalbytes; ++ int templength; ++ int direct_blk_idx; ++ long int blknr; ++ int found = 0; ++ char *ptr = NULL; ++ unsigned char *block_buffer = NULL; ++ struct ext2_dirent *dir = NULL; ++ struct ext2_dirent *previous_dir = NULL; ++ struct ext_filesystem *fs = get_fs(); ++ ++ /* 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(parent_inode, direct_blk_idx); ++ if (blknr == 0) ++ goto fail; ++ ++ /* read the blocks of parenet inode */ ++ block_buffer = zalloc(fs->blksz); ++ if (!block_buffer) ++ goto fail; ++ ++ status = ext4fs_devread(blknr * fs->sect_perblk, ++ 0, fs->blksz, (char *)block_buffer); ++ if (status == 0) ++ goto fail; ++ ++ dir = (struct ext2_dirent *)block_buffer; ++ ptr = (char *)dir; ++ totalbytes = 0; ++ while (dir->direntlen >= 0) { ++ /* ++ * blocksize-totalbytes because last directory ++ * length i.e.,*dir->direntlen is free availble ++ * space in the block that means ++ * it is a last entry of directory entry ++ */ ++ if (strlen(dirname) == dir->namelen) { ++ if (strncmp(dirname, ptr + ++ sizeof(struct ext2_dirent), ++ dir->namelen) == 0) { ++ 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) { ++ free(block_buffer); ++ block_buffer = NULL; ++ return inodeno; ++ } ++ ++ free(block_buffer); ++ block_buffer = NULL; ++ } ++ ++ fail: ++ free(block_buffer); ++ ++ return -1; ++} ++ ++static int find_dir_depth(char *dirname) ++{ ++ char *token = strtok(dirname, "/"); ++ int count = 0; ++ while (token != NULL) { ++ token = strtok(NULL, "/"); ++ count++; ++ } ++ return count + 1 + 1; ++ /* ++ * for example for string /home/temp ++ * depth=home(1)+temp(1)+1 extra for NULL; ++ * so count is 4; ++ */ ++} ++ ++static int parse_path(char **arr, char *dirname) ++{ ++ char *token = strtok(dirname, "/"); ++ int i = 0; ++ ++ /* add root */ ++ arr[i] = zalloc(strlen("/") + 1); ++ if (!arr[i]) ++ return -ENOMEM; ++ ++ arr[i++] = "/"; ++ ++ /* add each path entry after root */ ++ while (token != NULL) { ++ arr[i] = zalloc(strlen(token) + 1); ++ if (!arr[i]) ++ return -ENOMEM; ++ memcpy(arr[i++], token, strlen(token)); ++ token = strtok(NULL, "/"); ++ } ++ arr[i] = NULL; ++ ++ return 0; ++} ++ ++int ext4fs_iget(int inode_no, struct ext2_inode *inode) ++{ ++ if (ext4fs_read_inode(ext4fs_root, inode_no, inode) == 0) ++ return -1; ++ ++ return 0; ++} ++ ++/* ++ * Function: ext4fs_get_parent_inode_num ++ * Return Value: inode Number of the parent directory of file/Directory to 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 ext4fs_get_parent_inode_num(const char *dirname, char *dname, int flags) ++{ ++ int i; ++ int depth = 0; ++ int matched_inode_no; ++ int result_inode_no = -1; ++ char **ptr = NULL; ++ char *depth_dirname = NULL; ++ char *parse_dirname = NULL; ++ struct ext2_inode *parent_inode = NULL; ++ struct ext2_inode *first_inode = NULL; ++ struct ext2_inode temp_inode; ++ ++ if (*dirname != '/') { ++ printf("Please supply Absolute path\n"); ++ return -1; ++ } ++ ++ /* TODO: input validation make equivalent to linux */ ++ depth_dirname = zalloc(strlen(dirname) + 1); ++ if (!depth_dirname) ++ return -ENOMEM; ++ ++ memcpy(depth_dirname, dirname, strlen(dirname)); ++ depth = find_dir_depth(depth_dirname); ++ parse_dirname = zalloc(strlen(dirname) + 1); ++ if (!parse_dirname) ++ goto fail; ++ memcpy(parse_dirname, dirname, strlen(dirname)); ++ ++ /* allocate memory for each directory level */ ++ ptr = zalloc((depth) * sizeof(char *)); ++ if (!ptr) ++ goto fail; ++ if (parse_path(ptr, parse_dirname)) ++ goto fail; ++ parent_inode = zalloc(sizeof(struct ext2_inode)); ++ if (!parent_inode) ++ goto fail; ++ first_inode = zalloc(sizeof(struct ext2_inode)); ++ if (!first_inode) ++ goto fail; ++ memcpy(parent_inode, ext4fs_root->inode, sizeof(struct ext2_inode)); ++ memcpy(first_inode, parent_inode, sizeof(struct ext2_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 ext2_inode)); ++ if (ext4fs_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) { ++ ext4fs_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: ++ free(depth_dirname); ++ free(parse_dirname); ++ free(ptr); ++ free(parent_inode); ++ free(first_inode); ++ ++ return result_inode_no; ++} ++ ++static int check_filename(char *filename, unsigned int blknr) ++{ ++ unsigned int first_block_no_of_root; ++ int totalbytes = 0; ++ int templength = 0; ++ int status, inodeno; ++ int found = 0; ++ char *root_first_block_buffer = NULL; ++ char *root_first_block_addr = NULL; ++ struct ext2_dirent *dir = NULL; ++ struct ext2_dirent *previous_dir = NULL; ++ char *ptr = NULL; ++ struct ext_filesystem *fs = get_fs(); ++ ++ /* get the first block of root */ ++ first_block_no_of_root = blknr; ++ root_first_block_buffer = zalloc(fs->blksz); ++ if (!root_first_block_buffer) ++ return -ENOMEM; ++ root_first_block_addr = root_first_block_buffer; ++ status = ext4fs_devread(first_block_no_of_root * ++ fs->sect_perblk, 0, ++ fs->blksz, root_first_block_buffer); ++ if (status == 0) ++ goto fail; ++ ++ if (ext4fs_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) { ++ /* ++ * blocksize-totalbytes because last ++ * directory length i.e., *dir->direntlen ++ * is free availble space in the block that ++ * means it is a last entry of directory entry ++ */ ++ 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 (ext4fs_put_metadata(root_first_block_addr, ++ first_block_no_of_root)) ++ goto fail; ++ return inodeno; ++ } ++ fail: ++ 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; ++} ++ ++long int ext4fs_get_new_blk_no(void) ++{ ++ short i; ++ short status; ++ int remainder; ++ unsigned int bg_idx; ++ static int prev_bg_bitmap_index = -1; ++ unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group; ++ struct ext_filesystem *fs = get_fs(); ++ char *journal_buffer = zalloc(fs->blksz); ++ char *zero_buffer = zalloc(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 = ext4fs_devread(gd[i].block_id * ++ fs->sect_perblk, 0, ++ fs->blksz, ++ journal_buffer); ++ if (status == 0) ++ goto fail; ++ if (ext4fs_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 / blk_per_grp; ++ } else { ++ bg_idx = fs->curr_blkno / blk_per_grp; ++ remainder = fs->curr_blkno % blk_per_grp; ++ if (!remainder) ++ bg_idx--; ++ } ++ ++ /* ++ * To skip completely filled block group bitmaps ++ * Optimize the block allocation ++ */ ++ 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 + blk_per_grp; ++ 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 (ext4fs_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 = ext4fs_devread(gd[bg_idx].block_id ++ * fs->sect_perblk, ++ 0, fs->blksz, journal_buffer); ++ if (status == 0) ++ goto fail; ++ if (ext4fs_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: ++ free(journal_buffer); ++ free(zero_buffer); ++ ++ return fs->curr_blkno; ++ fail: ++ free(journal_buffer); ++ free(zero_buffer); ++ ++ return -1; ++} ++ ++int ext4fs_get_new_inode_no(void) ++{ ++ short i; ++ short status; ++ unsigned int ibmap_idx; ++ static int prev_inode_bitmap_index = -1; ++ unsigned int inodes_per_grp = ext4fs_root->sblock.inodes_per_group; ++ struct ext_filesystem *fs = get_fs(); ++ char *journal_buffer = zalloc(fs->blksz); ++ char *zero_buffer = zalloc(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 * inodes_per_grp); ++ fs->first_pass_ibmap++; ++ gd[i].free_inodes--; ++ gd[i].bg_itable_unused--; ++ fs->sb->free_inodes--; ++ status = ext4fs_devread(gd[i].inode_id * ++ fs->sect_perblk, 0, ++ fs->blksz, ++ journal_buffer); ++ if (status == 0) ++ goto fail; ++ if (ext4fs_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 / inodes_per_grp; ++ 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 (ext4fs_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 = ext4fs_devread(gd[ibmap_idx].inode_id ++ * fs->sect_perblk, ++ 0, fs->blksz, journal_buffer); ++ if (status == 0) ++ goto fail; ++ if (ext4fs_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: ++ free(journal_buffer); ++ free(zero_buffer); ++ ++ return fs->curr_inode_no; ++ fail: ++ free(journal_buffer); ++ free(zero_buffer); ++ ++ return -1; ++ ++} ++ ++static void alloc_single_indirect_block(struct ext2_inode *file_inode, ++ unsigned int *total_remaining_blocks, ++ unsigned int *no_blks_reqd) ++{ ++ short i; ++ short status; ++ long int actual_block_no; ++ long int si_blockno; ++ /* si :single indirect */ ++ unsigned int *si_buffer = NULL; ++ unsigned int *si_start_addr = NULL; ++ struct ext_filesystem *fs = get_fs(); ++ ++ if (*total_remaining_blocks != 0) { ++ si_buffer = zalloc(fs->blksz); ++ if (!si_buffer) { ++ printf("No Memory\n"); ++ return; ++ } ++ si_start_addr = si_buffer; ++ si_blockno = ext4fs_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 = ext4fs_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 = ext4fs_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 %u: %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: ++ free(si_start_addr); ++} ++ ++static void alloc_double_indirect_block(struct ext2_inode *file_inode, ++ unsigned int *total_remaining_blocks, ++ unsigned int *no_blks_reqd) ++{ ++ short i; ++ short j; ++ short status; ++ long int actual_block_no; ++ /* di:double indirect */ ++ long int di_blockno_parent; ++ long int 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; ++ struct ext_filesystem *fs = get_fs(); ++ ++ if (*total_remaining_blocks != 0) { ++ /* double indirect parent block connecting to inode */ ++ di_blockno_parent = ext4fs_get_new_blk_no(); ++ if (di_blockno_parent == -1) { ++ printf("no block left to assign\n"); ++ goto fail; ++ } ++ di_parent_buffer = zalloc(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 = ext4fs_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 = ext4fs_get_new_blk_no(); ++ if (di_blockno_child == -1) { ++ printf("no block left to assign\n"); ++ goto fail; ++ } ++ di_child_buff = zalloc(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 = ext4fs_devread(di_blockno_child * ++ fs->sect_perblk, 0, ++ fs->blksz, ++ (char *)di_child_buff); ++ memset(di_child_buff, '\0', fs->blksz); ++ /* filling of actual datablocks for each child */ ++ for (j = 0; j < (fs->blksz / sizeof(int)); j++) { ++ actual_block_no = ext4fs_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); ++ free(di_child_buff_start); ++ di_child_buff_start = NULL; ++ ++ 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: ++ free(di_block_start_addr); ++} ++ ++static void alloc_triple_indirect_block(struct ext2_inode *file_inode, ++ unsigned int *total_remaining_blocks, ++ unsigned int *no_blks_reqd) ++{ ++ short i; ++ short j; ++ short k; ++ long int actual_block_no; ++ /* ti: Triple Indirect */ ++ long int ti_gp_blockno; ++ long int ti_parent_blockno; ++ long int 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; ++ struct ext_filesystem *fs = get_fs(); ++ if (*total_remaining_blocks != 0) { ++ /* triple indirect grand parent block connecting to inode */ ++ ti_gp_blockno = ext4fs_get_new_blk_no(); ++ if (ti_gp_blockno == -1) { ++ printf("no block left to assign\n"); ++ goto fail; ++ } ++ ti_gp_buff = zalloc(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 = ext4fs_get_new_blk_no(); ++ if (ti_parent_blockno == -1) { ++ printf("no block left to assign\n"); ++ goto fail; ++ } ++ ti_parent_buff = zalloc(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 = ext4fs_get_new_blk_no(); ++ if (ti_child_blockno == -1) { ++ printf("no block left assign\n"); ++ goto fail; ++ } ++ ti_child_buff = zalloc(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 actual datablocks for each child */ ++ for (k = 0; k < (fs->blksz / sizeof(int)); ++ k++) { ++ actual_block_no = ++ ext4fs_get_new_blk_no(); ++ if (actual_block_no == -1) { ++ printf("no block left\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); ++ 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); ++ 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.triple_indir_block = ti_gp_blockno; ++ } ++ fail: ++ free(ti_gp_buff_start_addr); ++} ++ ++void ext4fs_allocate_blocks(struct ext2_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; ++ ++ /* allocation of direct blocks */ ++ for (i = 0; i < INDIRECT_BLOCKS; i++) { ++ direct_blockno = ext4fs_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; ++ } ++ ++ alloc_single_indirect_block(file_inode, &total_remaining_blocks, ++ &no_blks_reqd); ++ alloc_double_indirect_block(file_inode, &total_remaining_blocks, ++ &no_blks_reqd); ++ alloc_triple_indirect_block(file_inode, &total_remaining_blocks, ++ &no_blks_reqd); ++ *total_no_of_block += no_blks_reqd; ++} ++ ++#endif ++ ++static struct ext4_extent_header *ext4fs_get_extent_block ++ (struct ext2_data *data, char *buf, ++ struct ext4_extent_header *ext_block, ++ uint32_t fileblock, int log2_blksz) ++{ ++ struct ext4_extent_idx *index; ++ unsigned long long block; ++ struct ext_filesystem *fs = get_fs(); ++ int i; ++ ++ while (1) { ++ index = (struct ext4_extent_idx *)(ext_block + 1); ++ ++ if (le32_to_cpu(ext_block->eh_magic) != EXT4_EXT_MAGIC) ++ return 0; ++ ++ if (ext_block->eh_depth == 0) ++ return ext_block; ++ i = -1; ++ do { ++ i++; ++ if (i >= le32_to_cpu(ext_block->eh_entries)) ++ break; ++ } while (fileblock > le32_to_cpu(index[i].ei_block)); ++ ++ if (--i < 0) ++ return 0; ++ ++ block = le32_to_cpu(index[i].ei_leaf_hi); ++ block = (block << 32) + le32_to_cpu(index[i].ei_leaf_lo); ++ ++ if (ext4fs_devread(block << log2_blksz, 0, fs->blksz, buf)) ++ ext_block = (struct ext4_extent_header *)buf; ++ else ++ return 0; ++ } ++} ++ ++static int ext4fs_blockgroup ++ (struct ext2_data *data, int group, struct ext2_block_group *blkgrp) ++{ ++ long int blkno; ++ unsigned int blkoff, desc_per_blk; ++ ++ desc_per_blk = EXT2_BLOCK_SIZE(data) / sizeof(struct ext2_block_group); ++ ++ blkno = __le32_to_cpu(data->sblock.first_data_block) + 1 + ++ group / desc_per_blk; ++ blkoff = (group % desc_per_blk) * sizeof(struct ext2_block_group); ++ ++ debug("ext4fs read %d group descriptor (blkno %ld blkoff %u)\n", ++ group, blkno, blkoff); ++ ++ return ext4fs_devread(blkno << LOG2_EXT2_BLOCK_SIZE(data), ++ blkoff, sizeof(struct ext2_block_group), ++ (char *)blkgrp); ++} ++ ++int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode) ++{ ++ struct ext2_block_group blkgrp; ++ struct ext2_sblock *sblock = &data->sblock; ++ struct ext_filesystem *fs = get_fs(); ++ int inodes_per_block, status; ++ long int blkno; ++ unsigned int blkoff; ++ ++ /* It is easier to calculate if the first inode is 0. */ ++ ino--; ++ status = ext4fs_blockgroup(data, ino / __le32_to_cpu ++ (sblock->inodes_per_group), &blkgrp); ++ if (status == 0) ++ return 0; ++ ++ inodes_per_block = EXT2_BLOCK_SIZE(data) / fs->inodesz; ++ blkno = __le32_to_cpu(blkgrp.inode_table_id) + ++ (ino % __le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block; ++ blkoff = (ino % inodes_per_block) * fs->inodesz; ++ /* Read the inode. */ ++ status = ext4fs_devread(blkno << LOG2_EXT2_BLOCK_SIZE(data), blkoff, ++ sizeof(struct ext2_inode), (char *)inode); ++ if (status == 0) ++ return 0; ++ ++ return 1; ++} ++ ++long int read_allocated_block(struct ext2_inode *inode, int fileblock) ++{ ++ long int blknr; ++ int blksz; ++ int log2_blksz; ++ int status; ++ long int rblock; ++ long int perblock_parent; ++ long int perblock_child; ++ unsigned long long start; ++ /* get the blocksize of the filesystem */ ++ blksz = EXT2_BLOCK_SIZE(ext4fs_root); ++ log2_blksz = LOG2_EXT2_BLOCK_SIZE(ext4fs_root); ++ if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) { ++ char *buf = zalloc(blksz); ++ if (!buf) ++ return -ENOMEM; ++ struct ext4_extent_header *ext_block; ++ struct ext4_extent *extent; ++ int i = -1; ++ ext_block = ext4fs_get_extent_block(ext4fs_root, buf, ++ (struct ext4_extent_header ++ *)inode->b. ++ blocks.dir_blocks, ++ fileblock, log2_blksz); ++ if (!ext_block) { ++ printf("invalid extent block\n"); ++ free(buf); ++ return -EINVAL; ++ } ++ ++ extent = (struct ext4_extent *)(ext_block + 1); ++ ++ do { ++ i++; ++ if (i >= le32_to_cpu(ext_block->eh_entries)) ++ break; ++ } while (fileblock >= le32_to_cpu(extent[i].ee_block)); ++ if (--i >= 0) { ++ fileblock -= le32_to_cpu(extent[i].ee_block); ++ if (fileblock >= le32_to_cpu(extent[i].ee_len)) { ++ free(buf); ++ return 0; ++ } ++ ++ start = le32_to_cpu(extent[i].ee_start_hi); ++ start = (start << 32) + ++ le32_to_cpu(extent[i].ee_start_lo); ++ free(buf); ++ return fileblock + start; ++ } ++ ++ printf("Extent Error\n"); ++ free(buf); ++ return -1; ++ } ++ ++ /* Direct blocks. */ ++ if (fileblock < INDIRECT_BLOCKS) ++ blknr = __le32_to_cpu(inode->b.blocks.dir_blocks[fileblock]); ++ ++ /* Indirect. */ ++ else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4))) { ++ if (ext4fs_indir1_block == NULL) { ++ ext4fs_indir1_block = zalloc(blksz); ++ if (ext4fs_indir1_block == NULL) { ++ printf("** SI ext2fs read block (indir 1)" ++ "malloc failed. **\n"); ++ return -1; ++ } ++ ext4fs_indir1_size = blksz; ++ ext4fs_indir1_blkno = -1; ++ } ++ if (blksz != ext4fs_indir1_size) { ++ free(ext4fs_indir1_block); ++ ext4fs_indir1_block = NULL; ++ ext4fs_indir1_size = 0; ++ ext4fs_indir1_blkno = -1; ++ ext4fs_indir1_block = zalloc(blksz); ++ if (ext4fs_indir1_block == NULL) { ++ printf("** SI ext2fs read block (indir 1):" ++ "malloc failed. **\n"); ++ return -1; ++ } ++ ext4fs_indir1_size = blksz; ++ } ++ if ((__le32_to_cpu(inode->b.blocks.indir_block) << ++ log2_blksz) != ext4fs_indir1_blkno) { ++ status = ++ ext4fs_devread(__le32_to_cpu ++ (inode->b.blocks. ++ indir_block) << log2_blksz, 0, ++ blksz, (char *)ext4fs_indir1_block); ++ if (status == 0) { ++ printf("** SI ext2fs read block (indir 1)" ++ "failed. **\n"); ++ return 0; ++ } ++ ext4fs_indir1_blkno = ++ __le32_to_cpu(inode->b.blocks. ++ indir_block) << log2_blksz; ++ } ++ blknr = __le32_to_cpu(ext4fs_indir1_block ++ [fileblock - INDIRECT_BLOCKS]); ++ } ++ /* Double indirect. */ ++ else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4 * ++ (blksz / 4 + 1)))) { ++ ++ long int perblock = blksz / 4; ++ long int rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4); ++ ++ if (ext4fs_indir1_block == NULL) { ++ ext4fs_indir1_block = zalloc(blksz); ++ if (ext4fs_indir1_block == NULL) { ++ printf("** DI ext2fs read block (indir 2 1)" ++ "malloc failed. **\n"); ++ return -1; ++ } ++ ext4fs_indir1_size = blksz; ++ ext4fs_indir1_blkno = -1; ++ } ++ if (blksz != ext4fs_indir1_size) { ++ free(ext4fs_indir1_block); ++ ext4fs_indir1_block = NULL; ++ ext4fs_indir1_size = 0; ++ ext4fs_indir1_blkno = -1; ++ ext4fs_indir1_block = zalloc(blksz); ++ if (ext4fs_indir1_block == NULL) { ++ printf("** DI ext2fs read block (indir 2 1)" ++ "malloc failed. **\n"); ++ return -1; ++ } ++ ext4fs_indir1_size = blksz; ++ } ++ if ((__le32_to_cpu(inode->b.blocks.double_indir_block) << ++ log2_blksz) != ext4fs_indir1_blkno) { ++ status = ++ ext4fs_devread(__le32_to_cpu ++ (inode->b.blocks. ++ double_indir_block) << log2_blksz, ++ 0, blksz, ++ (char *)ext4fs_indir1_block); ++ if (status == 0) { ++ printf("** DI ext2fs read block (indir 2 1)" ++ "failed. **\n"); ++ return -1; ++ } ++ ext4fs_indir1_blkno = ++ __le32_to_cpu(inode->b.blocks.double_indir_block) << ++ log2_blksz; ++ } ++ ++ if (ext4fs_indir2_block == NULL) { ++ ext4fs_indir2_block = zalloc(blksz); ++ if (ext4fs_indir2_block == NULL) { ++ printf("** DI ext2fs read block (indir 2 2)" ++ "malloc failed. **\n"); ++ return -1; ++ } ++ ext4fs_indir2_size = blksz; ++ ext4fs_indir2_blkno = -1; ++ } ++ if (blksz != ext4fs_indir2_size) { ++ free(ext4fs_indir2_block); ++ ext4fs_indir2_block = NULL; ++ ext4fs_indir2_size = 0; ++ ext4fs_indir2_blkno = -1; ++ ext4fs_indir2_block = zalloc(blksz); ++ if (ext4fs_indir2_block == NULL) { ++ printf("** DI ext2fs read block (indir 2 2)" ++ "malloc failed. **\n"); ++ return -1; ++ } ++ ext4fs_indir2_size = blksz; ++ } ++ if ((__le32_to_cpu(ext4fs_indir1_block[rblock / perblock]) << ++ log2_blksz) != ext4fs_indir2_blkno) { ++ status = ext4fs_devread(__le32_to_cpu ++ (ext4fs_indir1_block ++ [rblock / ++ perblock]) << log2_blksz, 0, ++ blksz, ++ (char *)ext4fs_indir2_block); ++ if (status == 0) { ++ printf("** DI ext2fs read block (indir 2 2)" ++ "failed. **\n"); ++ return -1; ++ } ++ ext4fs_indir2_blkno = ++ __le32_to_cpu(ext4fs_indir1_block[rblock ++ / ++ perblock]) << ++ log2_blksz; ++ } ++ blknr = __le32_to_cpu(ext4fs_indir2_block[rblock % perblock]); ++ } ++ /* Tripple indirect. */ ++ else { ++ rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4 + ++ (blksz / 4 * blksz / 4)); ++ perblock_child = blksz / 4; ++ perblock_parent = ((blksz / 4) * (blksz / 4)); ++ ++ if (ext4fs_indir1_block == NULL) { ++ ext4fs_indir1_block = zalloc(blksz); ++ if (ext4fs_indir1_block == NULL) { ++ printf("** TI ext2fs read block (indir 2 1)" ++ "malloc failed. **\n"); ++ return -1; ++ } ++ ext4fs_indir1_size = blksz; ++ ext4fs_indir1_blkno = -1; ++ } ++ if (blksz != ext4fs_indir1_size) { ++ free(ext4fs_indir1_block); ++ ext4fs_indir1_block = NULL; ++ ext4fs_indir1_size = 0; ++ ext4fs_indir1_blkno = -1; ++ ext4fs_indir1_block = zalloc(blksz); ++ if (ext4fs_indir1_block == NULL) { ++ printf("** TI ext2fs read block (indir 2 1)" ++ "malloc failed. **\n"); ++ return -1; ++ } ++ ext4fs_indir1_size = blksz; ++ } ++ if ((__le32_to_cpu(inode->b.blocks.triple_indir_block) << ++ log2_blksz) != ext4fs_indir1_blkno) { ++ status = ext4fs_devread ++ (__le32_to_cpu(inode->b.blocks.triple_indir_block) ++ << log2_blksz, 0, blksz, ++ (char *)ext4fs_indir1_block); ++ if (status == 0) { ++ printf("** TI ext2fs read block (indir 2 1)" ++ "failed. **\n"); ++ return -1; ++ } ++ ext4fs_indir1_blkno = ++ __le32_to_cpu(inode->b.blocks.triple_indir_block) << ++ log2_blksz; ++ } ++ ++ if (ext4fs_indir2_block == NULL) { ++ ext4fs_indir2_block = zalloc(blksz); ++ if (ext4fs_indir2_block == NULL) { ++ printf("** TI ext2fs read block (indir 2 2)" ++ "malloc failed. **\n"); ++ return -1; ++ } ++ ext4fs_indir2_size = blksz; ++ ext4fs_indir2_blkno = -1; ++ } ++ if (blksz != ext4fs_indir2_size) { ++ free(ext4fs_indir2_block); ++ ext4fs_indir2_block = NULL; ++ ext4fs_indir2_size = 0; ++ ext4fs_indir2_blkno = -1; ++ ext4fs_indir2_block = zalloc(blksz); ++ if (ext4fs_indir2_block == NULL) { ++ printf("** TI ext2fs read block (indir 2 2)" ++ "malloc failed. **\n"); ++ return -1; ++ } ++ ext4fs_indir2_size = blksz; ++ } ++ if ((__le32_to_cpu(ext4fs_indir1_block[rblock / ++ perblock_parent]) << ++ log2_blksz) ++ != ext4fs_indir2_blkno) { ++ status = ext4fs_devread(__le32_to_cpu ++ (ext4fs_indir1_block ++ [rblock / ++ perblock_parent]) << ++ log2_blksz, 0, blksz, ++ (char *)ext4fs_indir2_block); ++ if (status == 0) { ++ printf("** TI ext2fs read block (indir 2 2)" ++ "failed. **\n"); ++ return -1; ++ } ++ ext4fs_indir2_blkno = ++ __le32_to_cpu(ext4fs_indir1_block[rblock / ++ perblock_parent]) ++ << log2_blksz; ++ } ++ ++ if (ext4fs_indir3_block == NULL) { ++ ext4fs_indir3_block = zalloc(blksz); ++ if (ext4fs_indir3_block == NULL) { ++ printf("** TI ext2fs read block (indir 2 2)" ++ "malloc failed. **\n"); ++ return -1; ++ } ++ ext4fs_indir3_size = blksz; ++ ext4fs_indir3_blkno = -1; ++ } ++ if (blksz != ext4fs_indir3_size) { ++ free(ext4fs_indir3_block); ++ ext4fs_indir3_block = NULL; ++ ext4fs_indir3_size = 0; ++ ext4fs_indir3_blkno = -1; ++ ext4fs_indir3_block = zalloc(blksz); ++ if (ext4fs_indir3_block == NULL) { ++ printf("** TI ext2fs read block (indir 2 2)" ++ "malloc failed. **\n"); ++ return -1; ++ } ++ ext4fs_indir3_size = blksz; ++ } ++ if ((__le32_to_cpu(ext4fs_indir2_block[rblock ++ / ++ perblock_child]) << ++ log2_blksz) != ext4fs_indir3_blkno) { ++ status = ++ ext4fs_devread(__le32_to_cpu ++ (ext4fs_indir2_block ++ [(rblock / perblock_child) ++ % (blksz / 4)]) << log2_blksz, 0, ++ blksz, (char *)ext4fs_indir3_block); ++ if (status == 0) { ++ printf("** TI ext2fs read block (indir 2 2)" ++ "failed. **\n"); ++ return -1; ++ } ++ ext4fs_indir3_blkno = ++ __le32_to_cpu(ext4fs_indir2_block[(rblock / ++ perblock_child) % ++ (blksz / ++ 4)]) << ++ log2_blksz; ++ } ++ ++ blknr = __le32_to_cpu(ext4fs_indir3_block ++ [rblock % perblock_child]); ++ } ++ debug("ext4fs_read_block %ld\n", blknr); ++ ++ return blknr; ++} ++ ++void ext4fs_close(void) ++{ ++ if ((ext4fs_file != NULL) && (ext4fs_root != NULL)) { ++ ext4fs_free_node(ext4fs_file, &ext4fs_root->diropen); ++ ext4fs_file = NULL; ++ } ++ if (ext4fs_root != NULL) { ++ free(ext4fs_root); ++ ext4fs_root = NULL; ++ } ++ if (ext4fs_indir1_block != NULL) { ++ free(ext4fs_indir1_block); ++ ext4fs_indir1_block = NULL; ++ ext4fs_indir1_size = 0; ++ ext4fs_indir1_blkno = -1; ++ } ++ if (ext4fs_indir2_block != NULL) { ++ free(ext4fs_indir2_block); ++ ext4fs_indir2_block = NULL; ++ ext4fs_indir2_size = 0; ++ ext4fs_indir2_blkno = -1; ++ } ++ if (ext4fs_indir3_block != NULL) { ++ free(ext4fs_indir3_block); ++ ext4fs_indir3_block = NULL; ++ ext4fs_indir3_size = 0; ++ ext4fs_indir3_blkno = -1; ++ } ++} ++ ++int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name, ++ struct ext2fs_node **fnode, int *ftype) ++{ ++ unsigned int fpos = 0; ++ int status; ++ struct ext2fs_node *diro = (struct ext2fs_node *)dir; ++ ++#ifdef DEBUG ++ if (name != NULL) ++ printf("Iterate dir %s\n", name); ++#endif /* of DEBUG */ ++ if (!diro->inode_read) { ++ status = ext4fs_read_inode(diro->data, diro->ino, &diro->inode); ++ if (status == 0) ++ return 0; ++ } ++ /* Search the file. */ ++ while (fpos < __le32_to_cpu(diro->inode.size)) { ++ struct ext2_dirent dirent; ++ ++ status = ext4fs_read_file(diro, fpos, ++ sizeof(struct ext2_dirent), ++ (char *)&dirent); ++ if (status < 1) ++ return 0; ++ ++ if (dirent.namelen != 0) { ++ char filename[dirent.namelen + 1]; ++ struct ext2fs_node *fdiro; ++ int type = FILETYPE_UNKNOWN; ++ ++ status = ext4fs_read_file(diro, ++ fpos + ++ sizeof(struct ext2_dirent), ++ dirent.namelen, filename); ++ if (status < 1) ++ return 0; ++ ++ fdiro = zalloc(sizeof(struct ext2fs_node)); ++ if (!fdiro) ++ return 0; ++ ++ fdiro->data = diro->data; ++ fdiro->ino = __le32_to_cpu(dirent.inode); ++ ++ filename[dirent.namelen] = '\0'; ++ ++ if (dirent.filetype != FILETYPE_UNKNOWN) { ++ fdiro->inode_read = 0; ++ ++ if (dirent.filetype == FILETYPE_DIRECTORY) ++ type = FILETYPE_DIRECTORY; ++ else if (dirent.filetype == FILETYPE_SYMLINK) ++ type = FILETYPE_SYMLINK; ++ else if (dirent.filetype == FILETYPE_REG) ++ type = FILETYPE_REG; ++ } else { ++ status = ext4fs_read_inode(diro->data, ++ __le32_to_cpu ++ (dirent.inode), ++ &fdiro->inode); ++ if (status == 0) { ++ free(fdiro); ++ return 0; ++ } ++ fdiro->inode_read = 1; ++ ++ if ((__le16_to_cpu(fdiro->inode.mode) & ++ FILETYPE_INO_MASK) == ++ FILETYPE_INO_DIRECTORY) { ++ type = FILETYPE_DIRECTORY; ++ } else if ((__le16_to_cpu(fdiro->inode.mode) ++ & FILETYPE_INO_MASK) == ++ FILETYPE_INO_SYMLINK) { ++ type = FILETYPE_SYMLINK; ++ } else if ((__le16_to_cpu(fdiro->inode.mode) ++ & FILETYPE_INO_MASK) == ++ FILETYPE_INO_REG) { ++ type = FILETYPE_REG; ++ } ++ } ++#ifdef DEBUG ++ printf("iterate >%s<\n", filename); ++#endif /* of DEBUG */ ++ if ((name != NULL) && (fnode != NULL) ++ && (ftype != NULL)) { ++ if (strcmp(filename, name) == 0) { ++ *ftype = type; ++ *fnode = fdiro; ++ return 1; ++ } ++ } else { ++ if (fdiro->inode_read == 0) { ++ status = ext4fs_read_inode(diro->data, ++ __le32_to_cpu( ++ dirent.inode), ++ &fdiro->inode); ++ if (status == 0) { ++ free(fdiro); ++ return 0; ++ } ++ fdiro->inode_read = 1; ++ } ++ switch (type) { ++ case FILETYPE_DIRECTORY: ++ printf(" "); ++ break; ++ case FILETYPE_SYMLINK: ++ printf(" "); ++ break; ++ case FILETYPE_REG: ++ printf(" "); ++ break; ++ default: ++ printf("< ? > "); ++ break; ++ } ++ printf("%10d %s\n", ++ __le32_to_cpu(fdiro->inode.size), ++ filename); ++ } ++ free(fdiro); ++ } ++ fpos += __le16_to_cpu(dirent.direntlen); ++ } ++ return 0; ++} ++ ++static char *ext4fs_read_symlink(struct ext2fs_node *node) ++{ ++ char *symlink; ++ struct ext2fs_node *diro = node; ++ int status; ++ ++ if (!diro->inode_read) { ++ status = ext4fs_read_inode(diro->data, diro->ino, &diro->inode); ++ if (status == 0) ++ return 0; ++ } ++ symlink = zalloc(__le32_to_cpu(diro->inode.size) + 1); ++ if (!symlink) ++ return 0; ++ ++ if (__le32_to_cpu(diro->inode.size) <= 60) { ++ strncpy(symlink, diro->inode.b.symlink, ++ __le32_to_cpu(diro->inode.size)); ++ } else { ++ status = ext4fs_read_file(diro, 0, ++ __le32_to_cpu(diro->inode.size), ++ symlink); ++ if (status == 0) { ++ free(symlink); ++ return 0; ++ } ++ } ++ symlink[__le32_to_cpu(diro->inode.size)] = '\0'; ++ return symlink; ++} ++ ++static int ext4fs_find_file1(const char *currpath, ++ struct ext2fs_node *currroot, ++ struct ext2fs_node **currfound, int *foundtype) ++{ ++ char fpath[strlen(currpath) + 1]; ++ char *name = fpath; ++ char *next; ++ int status; ++ int type = FILETYPE_DIRECTORY; ++ struct ext2fs_node *currnode = currroot; ++ struct ext2fs_node *oldnode = currroot; ++ ++ strncpy(fpath, currpath, strlen(currpath) + 1); ++ ++ /* Remove all leading slashes. */ ++ while (*name == '/') ++ name++; ++ ++ if (!*name) { ++ *currfound = currnode; ++ return 1; ++ } ++ ++ for (;;) { ++ int found; ++ ++ /* Extract the actual part from the pathname. */ ++ next = strchr(name, '/'); ++ if (next) { ++ /* Remove all leading slashes. */ ++ while (*next == '/') ++ *(next++) = '\0'; ++ } ++ ++ if (type != FILETYPE_DIRECTORY) { ++ ext4fs_free_node(currnode, currroot); ++ return 0; ++ } ++ ++ oldnode = currnode; ++ ++ /* Iterate over the directory. */ ++ found = ext4fs_iterate_dir(currnode, name, &currnode, &type); ++ if (found == 0) ++ return 0; ++ ++ if (found == -1) ++ break; ++ ++ /* Read in the symlink and follow it. */ ++ if (type == FILETYPE_SYMLINK) { ++ char *symlink; ++ ++ /* Test if the symlink does not loop. */ ++ if (++symlinknest == 8) { ++ ext4fs_free_node(currnode, currroot); ++ ext4fs_free_node(oldnode, currroot); ++ return 0; ++ } ++ ++ symlink = ext4fs_read_symlink(currnode); ++ ext4fs_free_node(currnode, currroot); ++ ++ if (!symlink) { ++ ext4fs_free_node(oldnode, currroot); ++ return 0; ++ } ++ ++ debug("Got symlink >%s<\n", symlink); ++ ++ if (symlink[0] == '/') { ++ ext4fs_free_node(oldnode, currroot); ++ oldnode = &ext4fs_root->diropen; ++ } ++ ++ /* Lookup the node the symlink points to. */ ++ status = ext4fs_find_file1(symlink, oldnode, ++ &currnode, &type); ++ ++ free(symlink); ++ ++ if (status == 0) { ++ ext4fs_free_node(oldnode, currroot); ++ return 0; ++ } ++ } ++ ++ ext4fs_free_node(oldnode, currroot); ++ ++ /* Found the node! */ ++ if (!next || *next == '\0') { ++ *currfound = currnode; ++ *foundtype = type; ++ return 1; ++ } ++ name = next; ++ } ++ return -1; ++} ++ ++int ext4fs_find_file(const char *path, struct ext2fs_node *rootnode, ++ struct ext2fs_node **foundnode, int expecttype) ++{ ++ int status; ++ int foundtype = FILETYPE_DIRECTORY; ++ ++ symlinknest = 0; ++ if (!path) ++ return 0; ++ ++ status = ext4fs_find_file1(path, rootnode, foundnode, &foundtype); ++ if (status == 0) ++ return 0; ++ ++ /* Check if the node that was found was of the expected type. */ ++ if ((expecttype == FILETYPE_REG) && (foundtype != expecttype)) ++ return 0; ++ else if ((expecttype == FILETYPE_DIRECTORY) ++ && (foundtype != expecttype)) ++ return 0; ++ ++ return 1; ++} ++ ++int ext4fs_open(const char *filename) ++{ ++ struct ext2fs_node *fdiro = NULL; ++ int status; ++ int len; ++ ++ if (ext4fs_root == NULL) ++ return -1; ++ ++ ext4fs_file = NULL; ++ status = ext4fs_find_file(filename, &ext4fs_root->diropen, &fdiro, ++ FILETYPE_REG); ++ if (status == 0) ++ goto fail; ++ ++ if (!fdiro->inode_read) { ++ status = ext4fs_read_inode(fdiro->data, fdiro->ino, ++ &fdiro->inode); ++ if (status == 0) ++ goto fail; ++ } ++ len = __le32_to_cpu(fdiro->inode.size); ++ ext4fs_file = fdiro; ++ ++ return len; ++ fail: ++ ext4fs_free_node(fdiro, &ext4fs_root->diropen); ++ ++ return -1; ++} ++ ++int ext4fs_mount(unsigned part_length) ++{ ++ struct ext2_data *data; ++ int status; ++ struct ext_filesystem *fs = get_fs(); ++ data = zalloc(sizeof(struct ext2_data)); ++ if (!data) ++ return 0; ++ ++ /* Read the superblock. */ ++ status = ext4fs_devread(1 * 2, 0, sizeof(struct ext2_sblock), ++ (char *)&data->sblock); ++ ++ if (status == 0) ++ goto fail; ++ ++ /* Make sure this is an ext2 filesystem. */ ++ if (__le16_to_cpu(data->sblock.magic) != EXT2_MAGIC) ++ goto fail; ++ ++ if (__le32_to_cpu(data->sblock.revision_level == 0)) ++ fs->inodesz = 128; ++ else ++ fs->inodesz = __le16_to_cpu(data->sblock.inode_size); ++ ++ debug("EXT2 rev %d, inode_size %d\n", ++ __le32_to_cpu(data->sblock.revision_level), fs->inodesz); ++ ++ data->diropen.data = data; ++ data->diropen.ino = 2; ++ data->diropen.inode_read = 1; ++ data->inode = &data->diropen.inode; ++ ++ status = ext4fs_read_inode(data, 2, data->inode); ++ if (status == 0) ++ goto fail; ++ ++ ext4fs_root = data; ++ ++ return 1; ++ fail: ++ printf("Failed to mount ext2 filesystem...\n"); ++ free(data); ++ ext4fs_root = NULL; ++ ++ return 0; ++} +diff --git a/fs/ext4/ext4_common.h b/fs/ext4/ext4_common.h +new file mode 100644 +index 0000000..417ebe4 +--- /dev/null ++++ b/fs/ext4/ext4_common.h +@@ -0,0 +1,88 @@ ++/* ++ * (C) Copyright 2011 - 2012 Samsung Electronics ++ * EXT4 filesystem implementation in Uboot by ++ * Uma Shankar <uma.shankar at samsung.com> ++ * Manjunatha C Achar <a.manjunatha at samsung.com> ++ * ++ * ext4ls and ext4load : based on ext2 ls load support in Uboot. ++ * ++ * (C) Copyright 2004 ++ * esd gmbh ++ * Reinhard Arlt <reinhard.arlt at 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. ++ */ ++ ++#ifndef __EXT4_COMMON__ ++#define __EXT4_COMMON__ ++#include ++#include ++#include ++#include ++#if defined(CONFIG_CMD_EXT4_WRITE) ++#include "ext4_journal.h" ++#include "crc16.h" ++#endif ++ ++#define YES 1 ++#define NO 0 ++#define TRUE 1 ++#define FALSE 0 ++#define RECOVER 1 ++#define SCAN 0 ++ ++#define S_IFLNK 0120000 /* symbolic link */ ++#define BLOCK_NO_ONE 1 ++#define SUPERBLOCK_SECTOR 2 ++#define SUPERBLOCK_SIZE 1024 ++#define F_FILE 1 ++ ++#define zalloc(size) calloc(1, size) ++ ++extern unsigned long part_offset; ++int ext4fs_read_inode(struct ext2_data *data, int ino, ++ struct ext2_inode *inode); ++int ext4fs_read_file(struct ext2fs_node *node, int pos, ++ unsigned int len, char *buf); ++int ext4fs_find_file(const char *path, struct ext2fs_node *rootnode, ++ struct ext2fs_node **foundnode, int expecttype); ++int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name, ++ struct ext2fs_node **fnode, int *ftype); ++ ++#if defined(CONFIG_CMD_EXT4_WRITE) ++uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n); ++int ext4fs_checksum_update(unsigned int i); ++int ext4fs_get_parent_inode_num(const char *dirname, char *dname, int flags); ++void ext4fs_update_parent_dentry(char *filename, int *p_ino, int file_type); ++long int ext4fs_get_new_blk_no(void); ++int ext4fs_get_new_inode_no(void); ++void ext4fs_reset_block_bmap(long int blockno, unsigned char *buffer, ++ int index); ++int ext4fs_set_block_bmap(long int blockno, unsigned char *buffer, int index); ++int ext4fs_set_inode_bmap(int inode_no, unsigned char *buffer, int index); ++void ext4fs_reset_inode_bmap(int inode_no, unsigned char *buffer, int index); ++int ext4fs_iget(int inode_no, struct ext2_inode *inode); ++void ext4fs_allocate_blocks(struct ext2_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); ++#endif ++#endif +diff --git a/fs/ext4/ext4_journal.c b/fs/ext4/ext4_journal.c +new file mode 100644 +index 0000000..e1dfd75 +--- /dev/null ++++ b/fs/ext4/ext4_journal.c +@@ -0,0 +1,666 @@ ++/* ++ * (C) Copyright 2011 - 2012 Samsung Electronics ++ * EXT4 filesystem implementation in Uboot by ++ * Uma Shankar <uma.shankar at samsung.com> ++ * Manjunatha C Achar <a.manjunatha at samsung.com> ++ * ++ * Journal data structures and headers for Journaling feature of ext4 ++ * have been referred from JBD2 (Journaling Block device 2) ++ * implementation in Linux Kernel. ++ * Written by Stephen C. Tweedie <sct at redhat.com> ++ * ++ * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved ++ * This file is part of the Linux kernel and is made available under ++ * the terms of the GNU General Public License, version 2, or at your ++ * option, any later version, incorporated herein by reference. ++ * ++ * 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 ++#include ++#include ++#include ++#include "ext4_common.h" ++ ++static struct revoke_blk_list *revk_blk_list; ++static struct revoke_blk_list *prev_node; ++static int first_node = TRUE; ++ ++int gindex; ++int gd_index; ++int jrnl_blk_idx; ++struct journal_log *journal_ptr[MAX_JOURNAL_ENTRIES]; ++struct dirty_blocks *dirty_block_ptr[MAX_JOURNAL_ENTRIES]; ++ ++int ext4fs_init_journal(void) ++{ ++ int i; ++ char *temp = NULL; ++ struct ext_filesystem *fs = get_fs(); ++ ++ /* init globals */ ++ revk_blk_list = NULL; ++ prev_node = NULL; ++ gindex = 0; ++ gd_index = 0; ++ jrnl_blk_idx = 1; ++ ++ for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { ++ journal_ptr[i] = zalloc(sizeof(struct journal_log)); ++ if (!journal_ptr[i]) ++ goto fail; ++ dirty_block_ptr[i] = zalloc(sizeof(struct dirty_blocks)); ++ if (!dirty_block_ptr[i]) ++ goto fail; ++ journal_ptr[i]->buf = NULL; ++ journal_ptr[i]->blknr = -1; ++ ++ dirty_block_ptr[i]->buf = NULL; ++ dirty_block_ptr[i]->blknr = -1; ++ } ++ ++ if (fs->blksz == 4096) { ++ temp = zalloc(fs->blksz); ++ if (!temp) ++ goto fail; ++ journal_ptr[gindex]->buf = zalloc(fs->blksz); ++ if (!journal_ptr[gindex]->buf) ++ goto fail; ++ ext4fs_devread(0, 0, fs->blksz, temp); ++ memcpy(temp + SUPERBLOCK_SIZE, fs->sb, SUPERBLOCK_SIZE); ++ memcpy(journal_ptr[gindex]->buf, temp, fs->blksz); ++ journal_ptr[gindex++]->blknr = 0; ++ free(temp); ++ } else { ++ journal_ptr[gindex]->buf = zalloc(fs->blksz); ++ if (!journal_ptr[gindex]->buf) ++ goto fail; ++ memcpy(journal_ptr[gindex]->buf, fs->sb, SUPERBLOCK_SIZE); ++ journal_ptr[gindex++]->blknr = 1; ++ } ++ ++ /* Check the file system state using journal super block */ ++ if (ext4fs_check_journal_state(SCAN)) ++ goto fail; ++ /* Check the file system state using journal super block */ ++ if (ext4fs_check_journal_state(RECOVER)) ++ goto fail; ++ ++ return 0; ++ fail: ++ return -1; ++} ++ ++void ext4fs_dump_metadata(void) ++{ ++ struct ext_filesystem *fs = get_fs(); ++ int i; ++ for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { ++ if (dirty_block_ptr[i]->blknr == -1) ++ break; ++ put_ext4((uint64_t) (dirty_block_ptr[i]->blknr * fs->blksz), ++ dirty_block_ptr[i]->buf, (uint32_t) fs->blksz); ++ } ++} ++ ++void ext4fs_free_journal(void) ++{ ++ int i; ++ for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { ++ if (dirty_block_ptr[i]->blknr == -1) ++ break; ++ if (dirty_block_ptr[i]->buf) ++ free(dirty_block_ptr[i]->buf); ++ } ++ ++ for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { ++ if (journal_ptr[i]->blknr == -1) ++ break; ++ if (journal_ptr[i]->buf) ++ free(journal_ptr[i]->buf); ++ } ++ ++ for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { ++ if (journal_ptr[i]) ++ free(journal_ptr[i]); ++ if (dirty_block_ptr[i]) ++ free(dirty_block_ptr[i]); ++ } ++ gindex = 0; ++ gd_index = 0; ++ jrnl_blk_idx = 1; ++} ++ ++int ext4fs_log_gdt(char *gd_table) ++{ ++ struct ext_filesystem *fs = get_fs(); ++ short i; ++ long int var = fs->gdtable_blkno; ++ for (i = 0; i < fs->no_blk_pergdt; i++) { ++ journal_ptr[gindex]->buf = zalloc(fs->blksz); ++ if (!journal_ptr[gindex]->buf) ++ return -ENOMEM; ++ memcpy(journal_ptr[gindex]->buf, gd_table, fs->blksz); ++ gd_table += fs->blksz; ++ journal_ptr[gindex++]->blknr = var++; ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function stores the backup copy of meta data in RAM ++ * journal_buffer -- Buffer containing meta data ++ * blknr -- Block number on disk of the meta data buffer ++ */ ++int ext4fs_log_journal(char *journal_buffer, long int blknr) ++{ ++ struct ext_filesystem *fs = get_fs(); ++ short i; ++ ++ if (!journal_buffer) { ++ printf("Invalid input arguments %s\n", __func__); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { ++ if (journal_ptr[i]->blknr == -1) ++ break; ++ if (journal_ptr[i]->blknr == blknr) ++ return 0; ++ } ++ ++ journal_ptr[gindex]->buf = zalloc(fs->blksz); ++ if (!journal_ptr[gindex]->buf) ++ return -ENOMEM; ++ ++ memcpy(journal_ptr[gindex]->buf, journal_buffer, fs->blksz); ++ journal_ptr[gindex++]->blknr = blknr; ++ ++ return 0; ++} ++ ++/* ++ * This function stores the modified meta data in RAM ++ * metadata_buffer -- Buffer containing meta data ++ * blknr -- Block number on disk of the meta data buffer ++ */ ++int ext4fs_put_metadata(char *metadata_buffer, long int blknr) ++{ ++ struct ext_filesystem *fs = get_fs(); ++ if (!metadata_buffer) { ++ printf("Invalid input arguments %s\n", __func__); ++ return -EINVAL; ++ } ++ dirty_block_ptr[gd_index]->buf = zalloc(fs->blksz); ++ if (!dirty_block_ptr[gd_index]->buf) ++ return -ENOMEM; ++ memcpy(dirty_block_ptr[gd_index]->buf, metadata_buffer, fs->blksz); ++ dirty_block_ptr[gd_index++]->blknr = blknr; ++ ++ return 0; ++} ++ ++void print_revoke_blks(char *revk_blk) ++{ ++ int offset; ++ int max; ++ long int blocknr; ++ struct journal_revoke_header_t *header; ++ ++ if (revk_blk == NULL) ++ return; ++ ++ header = (struct journal_revoke_header_t *)revk_blk; ++ offset = sizeof(struct journal_revoke_header_t); ++ max = be32_to_cpu(header->r_count); ++ printf("total bytes %d\n", max); ++ ++ while (offset < max) { ++ blocknr = be32_to_cpu(*((long int *)(revk_blk + offset))); ++ printf("revoke blknr is %ld\n", blocknr); ++ offset += 4; ++ } ++} ++ ++static struct revoke_blk_list *_get_node(void) ++{ ++ struct revoke_blk_list *tmp_node; ++ tmp_node = zalloc(sizeof(struct revoke_blk_list)); ++ if (tmp_node == NULL) ++ return NULL; ++ tmp_node->content = NULL; ++ tmp_node->next = NULL; ++ ++ return tmp_node; ++} ++ ++void ext4fs_push_revoke_blk(char *buffer) ++{ ++ struct revoke_blk_list *node = NULL; ++ struct ext_filesystem *fs = get_fs(); ++ if (buffer == NULL) { ++ printf("buffer ptr is NULL\n"); ++ return; ++ } ++ node = _get_node(); ++ if (!node) { ++ printf("_get_node: malloc failed\n"); ++ return; ++ } ++ ++ node->content = zalloc(fs->blksz); ++ if (node->content == NULL) ++ return; ++ memcpy(node->content, buffer, fs->blksz); ++ ++ if (first_node == TRUE) { ++ revk_blk_list = node; ++ prev_node = node; ++ first_node = FALSE; ++ } else { ++ prev_node->next = node; ++ prev_node = node; ++ } ++} ++ ++void ext4fs_free_revoke_blks(void) ++{ ++ struct revoke_blk_list *tmp_node = revk_blk_list; ++ struct revoke_blk_list *next_node = NULL; ++ ++ while (tmp_node != NULL) { ++ if (tmp_node->content) ++ free(tmp_node->content); ++ tmp_node = tmp_node->next; ++ } ++ ++ tmp_node = revk_blk_list; ++ while (tmp_node != NULL) { ++ next_node = tmp_node->next; ++ free(tmp_node); ++ tmp_node = next_node; ++ } ++ ++ revk_blk_list = NULL; ++ prev_node = NULL; ++ first_node = TRUE; ++} ++ ++int check_blknr_for_revoke(long int blknr, int sequence_no) ++{ ++ struct journal_revoke_header_t *header; ++ int offset; ++ int max; ++ long int blocknr; ++ char *revk_blk; ++ struct revoke_blk_list *tmp_revk_node = revk_blk_list; ++ while (tmp_revk_node != NULL) { ++ revk_blk = tmp_revk_node->content; ++ ++ header = (struct journal_revoke_header_t *)revk_blk; ++ if (sequence_no <= be32_to_cpu(header->r_header.h_sequence)) { ++ offset = sizeof(struct journal_revoke_header_t); ++ max = be32_to_cpu(header->r_count); ++ ++ while (offset < max) { ++ blocknr = be32_to_cpu(*((long int *) ++ (revk_blk + offset))); ++ if (blocknr == blknr) ++ goto found; ++ offset += 4; ++ } ++ } ++ tmp_revk_node = tmp_revk_node->next; ++ } ++ ++ return -1; ++ ++ found: ++ return 0; ++} ++ ++/* ++ * This function parses the journal blocks and replays the ++ * suceessful transactions. A transaction is successfull ++ * if commit block is found for a descriptor block ++ * The tags in descriptor block contain the disk block ++ * numbers of the metadata to be replayed ++ */ ++void recover_transaction(int prev_desc_logical_no) ++{ ++ struct ext2_inode inode_journal; ++ struct ext_filesystem *fs = get_fs(); ++ struct journal_header_t *jdb; ++ long int blknr; ++ char *p_jdb; ++ int ofs, flags; ++ int i; ++ struct ext3_journal_block_tag *tag; ++ char *temp_buff = zalloc(fs->blksz); ++ char *metadata_buff = zalloc(fs->blksz); ++ if (!temp_buff || !metadata_buff) ++ goto fail; ++ i = prev_desc_logical_no; ++ ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, ++ (struct ext2_inode *)&inode_journal); ++ blknr = read_allocated_block((struct ext2_inode *) ++ &inode_journal, i); ++ ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); ++ p_jdb = (char *)temp_buff; ++ jdb = (struct journal_header_t *)temp_buff; ++ ofs = sizeof(struct journal_header_t); ++ ++ do { ++ tag = (struct ext3_journal_block_tag *)&p_jdb[ofs]; ++ ofs += sizeof(struct ext3_journal_block_tag); ++ ++ if (ofs > fs->blksz) ++ break; ++ ++ flags = be32_to_cpu(tag->flags); ++ if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID)) ++ ofs += 16; ++ ++ i++; ++ debug("\t\ttag %u\n", be32_to_cpu(tag->block)); ++ if (revk_blk_list != NULL) { ++ if (check_blknr_for_revoke(be32_to_cpu(tag->block), ++ be32_to_cpu(jdb-> ++ h_sequence)) == ++ 0) ++ continue; ++ } ++ blknr = read_allocated_block(&inode_journal, i); ++ ext4fs_devread(blknr * fs->sect_perblk, 0, ++ fs->blksz, metadata_buff); ++ put_ext4((uint64_t) (be32_to_cpu(tag->block) * fs->blksz), ++ metadata_buff, (uint32_t) fs->blksz); ++ } while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG)); ++ fail: ++ free(temp_buff); ++ free(metadata_buff); ++} ++ ++void print_jrnl_status(int recovery_flag) ++{ ++ if (recovery_flag == RECOVER) ++ printf("Journal Recovery Completed\n"); ++ else ++ printf("Journal Scan Completed\n"); ++} ++ ++int ext4fs_check_journal_state(int recovery_flag) ++{ ++ int i; ++ int DB_FOUND = NO; ++ long int blknr; ++ int transaction_state = TRANSACTION_COMPLETE; ++ int prev_desc_logical_no = 0; ++ int curr_desc_logical_no = 0; ++ int ofs, flags, block; ++ struct ext2_inode inode_journal; ++ struct journal_superblock_t *jsb = NULL; ++ struct journal_header_t *jdb = NULL; ++ char *p_jdb = NULL; ++ struct ext3_journal_block_tag *tag = NULL; ++ char *temp_buff = NULL; ++ char *temp_buff1 = NULL; ++ struct ext_filesystem *fs = get_fs(); ++ ++ temp_buff = zalloc(fs->blksz); ++ if (!temp_buff) ++ return -ENOMEM; ++ temp_buff1 = zalloc(fs->blksz); ++ if (!temp_buff1) { ++ free(temp_buff); ++ return -ENOMEM; ++ } ++ ++ 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; ++ ++ if (fs->sb->feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) { ++ if (recovery_flag == RECOVER) ++ printf("Recovery required\n"); ++ } else { ++ if (recovery_flag == RECOVER) ++ printf("File System is consistent\n"); ++ goto end; ++ } ++ ++ if (be32_to_cpu(jsb->s_start) == 0) ++ goto end; ++ ++ if (!(jsb->s_feature_compat & ++ cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM))) ++ jsb->s_feature_compat |= ++ cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM); ++ ++ i = be32_to_cpu(jsb->s_first); ++ while (1) { ++ block = be32_to_cpu(jsb->s_first); ++ blknr = read_allocated_block(&inode_journal, i); ++ memset(temp_buff1, '\0', fs->blksz); ++ ext4fs_devread(blknr * fs->sect_perblk, ++ 0, fs->blksz, temp_buff1); ++ jdb = (struct journal_header_t *)temp_buff1; ++ ++ if (be32_to_cpu(jdb->h_blocktype) == ++ EXT3_JOURNAL_DESCRIPTOR_BLOCK) { ++ if (be32_to_cpu(jdb->h_sequence) != ++ be32_to_cpu(jsb->s_sequence)) { ++ print_jrnl_status(recovery_flag); ++ break; ++ } ++ ++ curr_desc_logical_no = i; ++ if (transaction_state == TRANSACTION_COMPLETE) ++ transaction_state = TRANSACTION_RUNNING; ++ else ++ return -1; ++ p_jdb = (char *)temp_buff1; ++ ofs = sizeof(struct journal_header_t); ++ do { ++ tag = (struct ext3_journal_block_tag *) ++ &p_jdb[ofs]; ++ ofs += sizeof(struct ext3_journal_block_tag); ++ if (ofs > fs->blksz) ++ break; ++ flags = be32_to_cpu(tag->flags); ++ if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID)) ++ ofs += 16; ++ i++; ++ debug("\t\ttag %u\n", be32_to_cpu(tag->block)); ++ } while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG)); ++ i++; ++ DB_FOUND = YES; ++ } else if (be32_to_cpu(jdb->h_blocktype) == ++ EXT3_JOURNAL_COMMIT_BLOCK) { ++ if ((be32_to_cpu(jdb->h_sequence) != ++ be32_to_cpu(jsb->s_sequence)) ++ || (DB_FOUND == NO)) { ++ print_jrnl_status(recovery_flag); ++ break; ++ } ++ ++ if (transaction_state == TRANSACTION_RUNNING) { ++ transaction_state = TRANSACTION_COMPLETE; ++ i++; ++ jsb->s_sequence = ++ cpu_to_be32(be32_to_cpu(jsb->s_sequence) + ++ 1); ++ } ++ prev_desc_logical_no = curr_desc_logical_no; ++ recover_transaction(prev_desc_logical_no); ++ DB_FOUND = NO; ++ } else if (be32_to_cpu(jdb->h_blocktype) == ++ EXT3_JOURNAL_REVOKE_BLOCK) { ++ if (be32_to_cpu(jdb->h_sequence) != ++ be32_to_cpu(jsb->s_sequence)) { ++ print_jrnl_status(recovery_flag); ++ break; ++ } ++ if (recovery_flag == SCAN) ++ ext4fs_push_revoke_blk((char *)jdb); ++ i++; ++ } else { ++ debug("Else Case\n"); ++ if (be32_to_cpu(jdb->h_sequence) != ++ be32_to_cpu(jsb->s_sequence)) { ++ print_jrnl_status(recovery_flag); ++ break; ++ } ++ } ++ } ++ ++ end: ++ if (recovery_flag == RECOVER) { ++ jsb->s_start = cpu_to_be32(1); ++ jsb->s_sequence = cpu_to_be32(be32_to_cpu(jsb->s_sequence) + 1); ++ /* get the superblock */ ++ ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE, ++ (char *)fs->sb); ++ fs->sb->feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER; ++ ++ /* Update the super block */ ++ put_ext4((uint64_t) (SUPERBLOCK_SIZE), ++ (struct ext2_sblock *)fs->sb, ++ (uint32_t) SUPERBLOCK_SIZE); ++ ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE, ++ (char *)fs->sb); ++ ++ blknr = read_allocated_block(&inode_journal, ++ EXT2_JOURNAL_SUPERBLOCK); ++ put_ext4((uint64_t) (blknr * fs->blksz), ++ (struct journal_superblock_t *)temp_buff, ++ (uint32_t) fs->blksz); ++ ext4fs_free_revoke_blks(); ++ } ++ free(temp_buff); ++ free(temp_buff1); ++ ++ return 0; ++} ++ ++static void update_descriptor_block(long int blknr) ++{ ++ int i; ++ long int jsb_blknr; ++ struct journal_header_t jdb; ++ struct ext3_journal_block_tag tag; ++ struct ext2_inode inode_journal; ++ struct journal_superblock_t *jsb = NULL; ++ char *buf = NULL; ++ char *temp = NULL; ++ struct ext_filesystem *fs = get_fs(); ++ char *temp_buff = zalloc(fs->blksz); ++ if (!temp_buff) ++ return; ++ ++ ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); ++ jsb_blknr = read_allocated_block(&inode_journal, ++ EXT2_JOURNAL_SUPERBLOCK); ++ ext4fs_devread(jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); ++ jsb = (struct journal_superblock_t *)temp_buff; ++ ++ jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_DESCRIPTOR_BLOCK); ++ jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER); ++ jdb.h_sequence = jsb->s_sequence; ++ buf = zalloc(fs->blksz); ++ if (!buf) { ++ free(temp_buff); ++ return; ++ } ++ temp = buf; ++ memcpy(buf, &jdb, sizeof(struct journal_header_t)); ++ temp += sizeof(struct journal_header_t); ++ ++ for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { ++ if (journal_ptr[i]->blknr == -1) ++ break; ++ ++ tag.block = cpu_to_be32(journal_ptr[i]->blknr); ++ tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_SAME_UUID); ++ memcpy(temp, &tag, sizeof(struct ext3_journal_block_tag)); ++ temp = temp + sizeof(struct ext3_journal_block_tag); ++ } ++ ++ tag.block = cpu_to_be32(journal_ptr[--i]->blknr); ++ tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_LAST_TAG); ++ memcpy(temp - sizeof(struct ext3_journal_block_tag), &tag, ++ sizeof(struct ext3_journal_block_tag)); ++ put_ext4((uint64_t) (blknr * fs->blksz), buf, (uint32_t) fs->blksz); ++ ++ free(temp_buff); ++ free(buf); ++} ++ ++static void update_commit_block(long int blknr) ++{ ++ struct journal_header_t jdb; ++ struct ext_filesystem *fs = get_fs(); ++ char *buf = NULL; ++ struct ext2_inode inode_journal; ++ struct journal_superblock_t *jsb; ++ long int jsb_blknr; ++ char *temp_buff = zalloc(fs->blksz); ++ if (!temp_buff) ++ return; ++ ++ ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); ++ jsb_blknr = read_allocated_block(&inode_journal, ++ EXT2_JOURNAL_SUPERBLOCK); ++ ext4fs_devread(jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); ++ jsb = (struct journal_superblock_t *)temp_buff; ++ ++ jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_COMMIT_BLOCK); ++ jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER); ++ jdb.h_sequence = jsb->s_sequence; ++ buf = zalloc(fs->blksz); ++ if (!buf) { ++ free(temp_buff); ++ return; ++ } ++ memcpy(buf, &jdb, sizeof(struct journal_header_t)); ++ put_ext4((uint64_t) (blknr * fs->blksz), buf, (uint32_t) fs->blksz); ++ ++ free(temp_buff); ++ free(buf); ++} ++ ++void ext4fs_update_journal(void) ++{ ++ struct ext2_inode inode_journal; ++ struct ext_filesystem *fs = get_fs(); ++ long int blknr; ++ int i; ++ ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); ++ blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); ++ update_descriptor_block(blknr); ++ for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { ++ if (journal_ptr[i]->blknr == -1) ++ break; ++ blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); ++ put_ext4((uint64_t) (blknr * fs->blksz), ++ journal_ptr[i]->buf, (uint32_t) fs->blksz); ++ } ++ blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); ++ update_commit_block(blknr); ++ printf("update journal finished\n"); ++} +diff --git a/fs/ext4/ext4_journal.h b/fs/ext4/ext4_journal.h +new file mode 100644 +index 0000000..e596e1e +--- /dev/null ++++ b/fs/ext4/ext4_journal.h +@@ -0,0 +1,141 @@ ++/* ++ * (C) Copyright 2011 - 2012 Samsung Electronics ++ * EXT4 filesystem implementation in Uboot by ++ * Uma Shankar <uma.shankar at samsung.com> ++ * Manjunatha C Achar <a.manjunatha at samsung.com> ++ * ++ * Journal data structures and headers for Journaling feature of ext4 ++ * have been referred from JBD2 (Journaling Block device 2) ++ * implementation in Linux Kernel. ++ * ++ * Written by Stephen C. Tweedie <sct at redhat.com> ++ * ++ * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved ++ * This file is part of the Linux kernel and is made available under ++ * the terms of the GNU General Public License, version 2, or at your ++ * option, any later version, incorporated herein by reference. ++ * ++ * 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. ++ */ ++ ++#ifndef __EXT4_JRNL__ ++#define __EXT4_JRNL__ ++ ++#define EXT2_JOURNAL_INO 8 /* Journal inode */ ++#define EXT2_JOURNAL_SUPERBLOCK 0 /* Journal Superblock number */ ++ ++#define JBD2_FEATURE_COMPAT_CHECKSUM 0x00000001 ++#define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U ++#define TRANSACTION_RUNNING 1 ++#define TRANSACTION_COMPLETE 0 ++#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ ++#define EXT3_JOURNAL_DESCRIPTOR_BLOCK 1 ++#define EXT3_JOURNAL_COMMIT_BLOCK 2 ++#define EXT3_JOURNAL_SUPERBLOCK_V1 3 ++#define EXT3_JOURNAL_SUPERBLOCK_V2 4 ++#define EXT3_JOURNAL_REVOKE_BLOCK 5 ++#define EXT3_JOURNAL_FLAG_ESCAPE 1 ++#define EXT3_JOURNAL_FLAG_SAME_UUID 2 ++#define EXT3_JOURNAL_FLAG_DELETED 4 ++#define EXT3_JOURNAL_FLAG_LAST_TAG 8 ++ ++/* Maximum entries in 1 journal transaction */ ++#define MAX_JOURNAL_ENTRIES 100 ++struct journal_log { ++ char *buf; ++ int blknr; ++}; ++ ++struct dirty_blocks { ++ char *buf; ++ int blknr; ++}; ++ ++/* Standard header for all descriptor blocks: */ ++struct journal_header_t { ++ __u32 h_magic; ++ __u32 h_blocktype; ++ __u32 h_sequence; ++}; ++ ++/* The journal superblock. All fields are in big-endian byte order. */ ++struct journal_superblock_t { ++ /* 0x0000 */ ++ struct journal_header_t s_header; ++ ++ /* Static information describing the journal */ ++ __u32 s_blocksize; /* journal device blocksize */ ++ __u32 s_maxlen; /* total blocks in journal file */ ++ __u32 s_first; /* first block of log information */ ++ ++ /* Dynamic information describing the current state of the log */ ++ __u32 s_sequence; /* first commit ID expected in log */ ++ __u32 s_start; /* blocknr of start of log */ ++ ++ /* Error value, as set by journal_abort(). */ ++ __s32 s_errno; ++ ++ /* Remaining fields are only valid in a version-2 superblock */ ++ __u32 s_feature_compat; /* compatible feature set */ ++ __u32 s_feature_incompat; /* incompatible feature set */ ++ __u32 s_feature_ro_compat; /* readonly-compatible feature set */ ++ /* 0x0030 */ ++ __u8 s_uuid[16]; /* 128-bit uuid for journal */ ++ ++ /* 0x0040 */ ++ __u32 s_nr_users; /* Nr of filesystems sharing log */ ++ ++ __u32 s_dynsuper; /* Blocknr of dynamic superblock copy */ ++ ++ /* 0x0048 */ ++ __u32 s_max_transaction; /* Limit of journal blocks per trans. */ ++ __u32 s_max_trans_data; /* Limit of data blocks per trans. */ ++ ++ /* 0x0050 */ ++ __u32 s_padding[44]; ++ ++ /* 0x0100 */ ++ __u8 s_users[16 * 48]; /* ids of all fs'es sharing the log */ ++ /* 0x0400 */ ++}; ++ ++struct ext3_journal_block_tag { ++ uint32_t block; ++ uint32_t flags; ++}; ++ ++struct journal_revoke_header_t { ++ struct journal_header_t r_header; ++ int r_count; /* Count of bytes used in the block */ ++}; ++ ++struct revoke_blk_list { ++ char *content; /* revoke block itself */ ++ struct revoke_blk_list *next; ++}; ++ ++extern struct ext2_data *ext4fs_root; ++ ++int ext4fs_init_journal(void); ++int ext4fs_log_gdt(char *gd_table); ++int ext4fs_check_journal_state(int recovery_flag); ++int ext4fs_log_journal(char *journal_buffer, long int blknr); ++int ext4fs_put_metadata(char *metadata_buffer, long int blknr); ++void ext4fs_update_journal(void); ++void ext4fs_dump_metadata(void); ++void ext4fs_push_revoke_blk(char *buffer); ++void ext4fs_free_journal(void); ++void ext4fs_free_revoke_blks(void); ++#endif +diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c +new file mode 100644 +index 0000000..db5a387 +--- /dev/null ++++ b/fs/ext4/ext4fs.c +@@ -0,0 +1,1189 @@ ++/* ++ * (C) Copyright 2011 - 2012 Samsung Electronics ++ * EXT4 filesystem implementation in Uboot by ++ * Uma Shankar <uma.shankar at samsung.com> ++ * Manjunatha C Achar <a.manjunatha at 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 at 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ext4_common.h" ++ ++int ext4fs_symlinknest; ++block_dev_desc_t *ext4_dev_desc; ++ ++struct ext_filesystem *get_fs(void) ++{ ++ if (ext4_dev_desc == NULL || ext4_dev_desc->priv == NULL) ++ printf("Invalid Input Arguments %s\n", __func__); ++ ++ return ext4_dev_desc->priv; ++} ++ ++int init_fs(block_dev_desc_t *dev_desc) ++{ ++ struct ext_filesystem *fs; ++ if (dev_desc == NULL) { ++ printf("Invalid Input Arguments %s\n", __func__); ++ return -EINVAL; ++ } ++ ++ fs = zalloc(sizeof(struct ext_filesystem)); ++ if (fs == NULL) { ++ printf("malloc failed: %s\n", __func__); ++ return -ENOMEM; ++ } ++ ++ fs->dev_desc = dev_desc; ++ dev_desc->priv = fs; ++ ++ return 0; ++} ++ ++void deinit_fs(block_dev_desc_t *dev_desc) ++{ ++ if (dev_desc == NULL) { ++ printf("Invalid Input Arguments %s\n", __func__); ++ return; ++ } ++ free(dev_desc->priv); ++ dev_desc->priv = NULL; ++} ++ ++void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot) ++{ ++ if ((node != &ext4fs_root->diropen) && (node != currroot)) ++ free(node); ++} ++ ++/* ++ * Taken from openmoko-kernel mailing list: By Andy green ++ * Optimized read file API : collects and defers contiguous sector ++ * reads into one potentially more efficient larger sequential read action ++ */ ++int ext4fs_read_file(struct ext2fs_node *node, int pos, ++ unsigned int len, char *buf) ++{ ++ int i; ++ int blockcnt; ++ int log2blocksize = LOG2_EXT2_BLOCK_SIZE(node->data); ++ int blocksize = 1 << (log2blocksize + DISK_SECTOR_BITS); ++ unsigned int filesize = __le32_to_cpu(node->inode.size); ++ int previous_block_number = -1; ++ int delayed_start = 0; ++ int delayed_extent = 0; ++ int delayed_skipfirst = 0; ++ int delayed_next = 0; ++ char *delayed_buf = NULL; ++ short status; ++ ++ /* Adjust len so it we can't read past the end of the file. */ ++ if (len > filesize) ++ len = filesize; ++ ++ blockcnt = ((len + pos) + blocksize - 1) / blocksize; ++ ++ for (i = pos / blocksize; i < blockcnt; i++) { ++ int blknr; ++ int blockoff = pos % blocksize; ++ int blockend = blocksize; ++ int skipfirst = 0; ++ blknr = read_allocated_block(&(node->inode), i); ++ if (blknr < 0) ++ return -1; ++ ++ blknr = blknr << log2blocksize; ++ ++ /* Last block. */ ++ if (i == blockcnt - 1) { ++ blockend = (len + pos) % blocksize; ++ ++ /* The last portion is exactly blocksize. */ ++ if (!blockend) ++ blockend = blocksize; ++ } ++ ++ /* First block. */ ++ if (i == pos / blocksize) { ++ skipfirst = blockoff; ++ blockend -= skipfirst; ++ } ++ if (blknr) { ++ int status; ++ ++ if (previous_block_number != -1) { ++ if (delayed_next == blknr) { ++ delayed_extent += blockend; ++ delayed_next += blockend >> SECTOR_BITS; ++ } else { /* spill */ ++ status = ext4fs_devread(delayed_start, ++ delayed_skipfirst, ++ delayed_extent, ++ delayed_buf); ++ if (status == 0) ++ return -1; ++ previous_block_number = blknr; ++ delayed_start = blknr; ++ delayed_extent = blockend; ++ delayed_skipfirst = skipfirst; ++ delayed_buf = buf; ++ delayed_next = blknr + ++ (blockend >> SECTOR_BITS); ++ } ++ } else { ++ previous_block_number = blknr; ++ delayed_start = blknr; ++ delayed_extent = blockend; ++ delayed_skipfirst = skipfirst; ++ delayed_buf = buf; ++ delayed_next = blknr + ++ (blockend >> SECTOR_BITS); ++ } ++ } else { ++ if (previous_block_number != -1) { ++ /* spill */ ++ status = ext4fs_devread(delayed_start, ++ delayed_skipfirst, ++ delayed_extent, ++ delayed_buf); ++ if (status == 0) ++ return -1; ++ previous_block_number = -1; ++ } ++ memset(buf, 0, blocksize - skipfirst); ++ } ++ buf += blocksize - skipfirst; ++ } ++ if (previous_block_number != -1) { ++ /* spill */ ++ status = ext4fs_devread(delayed_start, ++ delayed_skipfirst, delayed_extent, ++ delayed_buf); ++ if (status == 0) ++ return -1; ++ previous_block_number = -1; ++ } ++ ++ return len; ++} ++ ++int ext4fs_ls(const char *dirname) ++{ ++ struct ext2fs_node *dirnode; ++ int status; ++ ++ if (dirname == NULL) ++ return 0; ++ ++ status = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode, ++ FILETYPE_DIRECTORY); ++ if (status != 1) { ++ printf("** Can not find directory. **\n"); ++ return 1; ++ } ++ ++ ext4fs_iterate_dir(dirnode, NULL, NULL, NULL); ++ ext4fs_free_node(dirnode, &ext4fs_root->diropen); ++ ++ return 0; ++} ++ ++int ext4fs_read(char *buf, unsigned len) ++{ ++ if (ext4fs_root == NULL || ext4fs_file == NULL) ++ return 0; ++ ++ return ext4fs_read_file(ext4fs_file, 0, len, buf); ++} ++ ++#if defined(CONFIG_CMD_EXT4_WRITE) ++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->gd[i].bg_checksum = ext4fs_checksum_update(i); ++ put_ext4((uint64_t) (fs->gd[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->gd[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 *gd = 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 */ ++ gd = (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); ++ gd[bg_idx].free_blocks++; ++ fs->sb->free_blocks++; ++ /* journal backup */ ++ if (prev_bg_bmap_idx != bg_idx) { ++ status = ++ ext4fs_devread(gd[bg_idx].block_id * ++ fs->sect_perblk, 0, fs->blksz, ++ journal_buffer); ++ if (status == 0) ++ goto fail; ++ if (ext4fs_log_journal ++ (journal_buffer, gd[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 *gd = 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 */ ++ gd = (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++; ++ gd[bg_idx].free_blocks++; ++ fs->sb->free_blocks++; ++ /* journal backup */ ++ if (prev_bg_bmap_idx != bg_idx) { ++ status = ext4fs_devread(gd[bg_idx].block_id ++ * fs->sect_perblk, 0, ++ fs->blksz, ++ journal_buffer); ++ if (status == 0) ++ goto fail; ++ ++ if (ext4fs_log_journal(journal_buffer, ++ gd[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); ++ gd[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(gd[bg_idx].block_id * ++ fs->sect_perblk, 0, fs->blksz, ++ journal_buffer); ++ if (status == 0) ++ goto fail; ++ ++ if (ext4fs_log_journal(journal_buffer, ++ gd[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 *gd = 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 */ ++ gd = (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++; ++ gd[bg_idx].free_blocks++; ++ fs->sb->free_blocks++; ++ /* journal backup */ ++ if (prev_bg_bmap_idx != bg_idx) { ++ status = ++ ext4fs_devread(gd[bg_idx].block_id * ++ fs->sect_perblk, 0, ++ fs->blksz, ++ journal_buffer); ++ if (status == 0) ++ goto fail; ++ ++ if (ext4fs_log_journal(journal_buffer, ++ gd[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++; ++ gd[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(gd[bg_idx].block_id * ++ fs->sect_perblk, 0, ++ fs->blksz, journal_buffer); ++ if (status == 0) ++ goto fail; ++ ++ if (ext4fs_log_journal(journal_buffer, ++ gd[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); ++ gd[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(gd[bg_idx].block_id * ++ fs->sect_perblk, 0, fs->blksz, ++ journal_buffer); ++ if (status == 0) ++ goto fail; ++ ++ if (ext4fs_log_journal(journal_buffer, ++ gd[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 *gd = NULL; ++ struct ext_filesystem *fs = get_fs(); ++ char *journal_buffer = zalloc(fs->blksz); ++ if (!journal_buffer) ++ return -ENOMEM; ++ /* get the block group descriptor table */ ++ gd = (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); ++ ++ gd[bg_idx].free_blocks++; ++ fs->sb->free_blocks++; ++ ++ /* journal backup */ ++ if (prev_bg_bmap_idx != bg_idx) { ++ status = ++ ext4fs_devread(gd[bg_idx].block_id * ++ fs->sect_perblk, 0, ++ fs->blksz, journal_buffer); ++ if (status == 0) ++ goto fail; ++ if (ext4fs_log_journal(journal_buffer, ++ gd[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); ++ ++ gd[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(gd[bg_idx].block_id ++ * fs->sect_perblk, ++ 0, fs->blksz, ++ journal_buffer); ++ if (status == 0) ++ goto fail; ++ if (ext4fs_log_journal(journal_buffer, ++ gd[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(gd[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); ++ gd[ibmap_idx].free_inodes++; ++ fs->sb->free_inodes++; ++ /* journal backup */ ++ memset(journal_buffer, '\0', fs->blksz); ++ status = ext4fs_devread(gd[ibmap_idx].inode_id * ++ fs->sect_perblk, 0, fs->blksz, journal_buffer); ++ if (status == 0) ++ goto fail; ++ if (ext4fs_log_journal(journal_buffer, gd[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->gd = (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->gd[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->gd[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->gd[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->gd = 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_skipfirst = 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_skipfirst = skipfirst; ++ delayed_buf = buf; ++ delayed_next = blknr + ++ (blockend >> SECTOR_BITS); ++ } ++ } else { ++ previous_block_number = blknr; ++ delayed_start = blknr; ++ delayed_extent = blockend; ++ delayed_skipfirst = skipfirst; ++ delayed_buf = buf; ++ delayed_next = blknr + ++ (blockend >> SECTOR_BITS); ++ } ++ } else { ++ if (previous_block_number != -1) { ++ /* spill */ ++ 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 filename[256]; ++ ++ 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(); ++ 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 = bytes_reqd_for_file / fs->blksz; ++ if (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->gd[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->gd[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; ++} ++#endif +diff --git a/include/config_cmd_all.h b/include/config_cmd_all.h +index cdc5ff1..7cd575f 100644 +--- a/include/config_cmd_all.h ++++ b/include/config_cmd_all.h +@@ -35,6 +35,7 @@ + #define CONFIG_CMD_EEPROM /* EEPROM read/write support */ + #define CONFIG_CMD_ELF /* ELF (VxWorks) load/boot cmd */ + #define CONFIG_CMD_EXT2 /* EXT2 Support */ ++#define CONFIG_CMD_EXT4 /* EXT4 Support */ + #define CONFIG_CMD_FAT /* FAT support */ + #define CONFIG_CMD_FDC /* Floppy Disk Support */ + #define CONFIG_CMD_FDOS /* Floppy DOS support */ +diff --git a/include/configs/hardkernel/odroidc.h b/include/configs/hardkernel/odroidc.h +index 51d62b1..ae701b8 100644 +--- a/include/configs/hardkernel/odroidc.h ++++ b/include/configs/hardkernel/odroidc.h +@@ -1,6 +1,8 @@ + #ifndef __CONFIG_ODROIDC_H__ + #define __CONFIG_ODROIDC_H__ + ++#define CONFIG_CMD_EXT4 ++ + #define CONFIG_MACH_MESON8_ODROIDC // generate M8 ODROID-C machid number + + #define CONFIG_SYS_LOAD_ADDR 0x12000000 +diff --git a/include/ext4fs.h b/include/ext4fs.h +new file mode 100644 +index 0000000..156e6c7 +--- /dev/null ++++ b/include/ext4fs.h +@@ -0,0 +1,144 @@ ++/* ++ * (C) Copyright 2011 - 2012 Samsung Electronics ++ * EXT4 filesystem implementation in Uboot by ++ * Uma Shankar <uma.shankar at samsung.com> ++ * Manjunatha C Achar <a.manjunatha at samsung.com> ++ * ++ * Ext4 Extent data structures are taken from original ext4 fs code ++ * as found in the linux kernel. ++ * ++ * Copyright (c) 2003-2006, Cluster File Systems, Inc, info at clusterfs.com ++ * Written by Alex Tomas <alex at clusterfs.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * 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. ++ */ ++ ++#ifndef __EXT4__ ++#define __EXT4__ ++#include ++ ++#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ ++#define EXT4_EXT_MAGIC 0xf30a ++#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010 ++#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 ++#define EXT4_INDIRECT_BLOCKS 12 ++ ++#define EXT4_BG_INODE_UNINIT 0x0001 ++#define EXT4_BG_BLOCK_UNINIT 0x0002 ++#define EXT4_BG_INODE_ZEROED 0x0004 ++ ++/* ++ * ext4_inode has i_block array (60 bytes total). ++ * The first 12 bytes store ext4_extent_header; ++ * the remainder stores an array of ext4_extent. ++ */ ++ ++/* ++ * This is the extent on-disk structure. ++ * It's used at the bottom of the tree. ++ */ ++struct ext4_extent { ++ __le32 ee_block; /* first logical block extent covers */ ++ __le16 ee_len; /* number of blocks covered by extent */ ++ __le16 ee_start_hi; /* high 16 bits of physical block */ ++ __le32 ee_start_lo; /* low 32 bits of physical block */ ++}; ++ ++/* ++ * This is index on-disk structure. ++ * It's used at all the levels except the bottom. ++ */ ++struct ext4_extent_idx { ++ __le32 ei_block; /* index covers logical blocks from 'block' */ ++ __le32 ei_leaf_lo; /* pointer to the physical block of the next * ++ * level. leaf or next index could be there */ ++ __le16 ei_leaf_hi; /* high 16 bits of physical block */ ++ __u16 ei_unused; ++}; ++ ++/* Each block (leaves and indexes), even inode-stored has header. */ ++struct ext4_extent_header { ++ __le16 eh_magic; /* probably will support different formats */ ++ __le16 eh_entries; /* number of valid entries */ ++ __le16 eh_max; /* capacity of store in entries */ ++ __le16 eh_depth; /* has tree real underlying blocks? */ ++ __le32 eh_generation; /* generation of the tree */ ++}; ++ ++struct ext_filesystem { ++ /* Total Sector of partition */ ++ uint64_t total_sect; ++ /* Block size of partition */ ++ uint32_t blksz; ++ /* Inode size of partition */ ++ uint32_t inodesz; ++ /* Sectors per Block */ ++ uint32_t sect_perblk; ++ /* Group Descriptor Block Number */ ++ uint32_t gdtable_blkno; ++ /* Total block groups of partition */ ++ uint32_t no_blkgrp; ++ /* No of blocks required for bgdtable */ ++ uint32_t no_blk_pergdt; ++ /* Superblock */ ++ struct ext2_sblock *sb; ++ /* Block group descritpor table */ ++ struct ext2_block_group *gd; ++ char *gdtable; ++ ++ /* Block Bitmap Related */ ++ unsigned char **blk_bmaps; ++ long int curr_blkno; ++ uint16_t first_pass_bbmap; ++ ++ /* Inode Bitmap Related */ ++ unsigned char **inode_bmaps; ++ int curr_inode_no; ++ uint16_t first_pass_ibmap; ++ ++ /* Journal Related */ ++ ++ /* Block Device Descriptor */ ++ block_dev_desc_t *dev_desc; ++}; ++ ++extern block_dev_desc_t *ext4_dev_desc; ++extern struct ext2_data *ext4fs_root; ++extern struct ext2fs_node *ext4fs_file; ++ ++#if defined(CONFIG_CMD_EXT4_WRITE) ++extern struct ext2_inode *g_parent_inode; ++extern int gd_index; ++extern int gindex; ++ ++int ext4fs_init(void); ++void ext4fs_deinit(void); ++int ext4fs_filename_check(char *filename); ++int ext4fs_write(const char *fname, unsigned char *buffer, ++ unsigned long sizebytes); ++#endif ++ ++struct ext_filesystem *get_fs(void); ++int init_fs(block_dev_desc_t *dev_desc); ++void deinit_fs(block_dev_desc_t *dev_desc); ++int ext4fs_open(const char *filename); ++int ext4fs_read(char *buf, unsigned len); ++int ext4fs_mount(unsigned part_length); ++void ext4fs_close(void); ++int ext4fs_ls(const char *dirname); ++void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot); ++int ext4fs_devread(int sector, int byte_offset, int byte_len, char *buf); ++int ext4fs_set_blk_dev(block_dev_desc_t *rbdd, int part); ++long int read_allocated_block(struct ext2_inode *inode, int fileblock); ++#endif +diff --git a/include/ext_common.h b/include/ext_common.h +new file mode 100644 +index 0000000..e884787 +--- /dev/null ++++ b/include/ext_common.h +@@ -0,0 +1,188 @@ ++/* ++ * (C) Copyright 2011 - 2012 Samsung Electronics ++ * EXT4 filesystem implementation in Uboot by ++ * Uma Shankar <uma.shankar at samsung.com> ++ * Manjunatha C Achar <a.manjunatha at samsung.com> ++ * ++ * Data structures and headers for ext4 support have been taken from ++ * ext2 ls load support in Uboot ++ * ++ * (C) Copyright 2004 ++ * esd gmbh <www.esd-electronics.com> ++ * Reinhard Arlt <reinhard.arlt at esd-electronics.com> ++ * ++ * based on code from grub2 fs/ext2.c and fs/fshelp.c by ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2003, 2004 Free Software Foundation, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#ifndef __EXT_COMMON__ ++#define __EXT_COMMON__ ++ ++#define SECTOR_SIZE 0x200 ++#define SECTOR_BITS 9 ++ ++/* Magic value used to identify an ext2 filesystem. */ ++#define EXT2_MAGIC 0xEF53 ++/* Amount of indirect blocks in an inode. */ ++#define INDIRECT_BLOCKS 12 ++/* Maximum lenght of a pathname. */ ++#define EXT2_PATH_MAX 4096 ++/* Maximum nesting of symlinks, used to prevent a loop. */ ++#define EXT2_MAX_SYMLINKCNT 8 ++ ++/* Filetype used in directory entry. */ ++#define FILETYPE_UNKNOWN 0 ++#define FILETYPE_REG 1 ++#define FILETYPE_DIRECTORY 2 ++#define FILETYPE_SYMLINK 7 ++ ++/* Filetype information as used in inodes. */ ++#define FILETYPE_INO_MASK 0170000 ++#define FILETYPE_INO_REG 0100000 ++#define FILETYPE_INO_DIRECTORY 0040000 ++#define FILETYPE_INO_SYMLINK 0120000 ++#define EXT2_ROOT_INO 2 /* Root inode */ ++ ++/* Bits used as offset in sector */ ++#define DISK_SECTOR_BITS 9 ++/* The size of an ext2 block in bytes. */ ++#define EXT2_BLOCK_SIZE(data) (1 << LOG2_BLOCK_SIZE(data)) ++ ++/* Log2 size of ext2 block in 512 blocks. */ ++#define LOG2_EXT2_BLOCK_SIZE(data) (__le32_to_cpu \ ++ (data->sblock.log2_block_size) + 1) ++ ++/* Log2 size of ext2 block in bytes. */ ++#define LOG2_BLOCK_SIZE(data) (__le32_to_cpu \ ++ (data->sblock.log2_block_size) + 10) ++#define INODE_SIZE_FILESYSTEM(data) (__le32_to_cpu \ ++ (data->sblock.inode_size)) ++ ++#define EXT2_FT_DIR 2 ++#define SUCCESS 1 ++ ++/* Macro-instructions used to manage several block sizes */ ++#define EXT2_MIN_BLOCK_LOG_SIZE 10 /* 1024 */ ++#define EXT2_MAX_BLOCK_LOG_SIZE 16 /* 65536 */ ++#define EXT2_MIN_BLOCK_SIZE (1 << EXT2_MIN_BLOCK_LOG_SIZE) ++#define EXT2_MAX_BLOCK_SIZE (1 << EXT2_MAX_BLOCK_LOG_SIZE) ++ ++/* The ext2 superblock. */ ++struct ext2_sblock { ++ uint32_t total_inodes; ++ uint32_t total_blocks; ++ uint32_t reserved_blocks; ++ uint32_t free_blocks; ++ uint32_t free_inodes; ++ uint32_t first_data_block; ++ uint32_t log2_block_size; ++ uint32_t log2_fragment_size; ++ uint32_t blocks_per_group; ++ uint32_t fragments_per_group; ++ uint32_t inodes_per_group; ++ uint32_t mtime; ++ uint32_t utime; ++ uint16_t mnt_count; ++ uint16_t max_mnt_count; ++ uint16_t magic; ++ uint16_t fs_state; ++ uint16_t error_handling; ++ uint16_t minor_revision_level; ++ uint32_t lastcheck; ++ uint32_t checkinterval; ++ uint32_t creator_os; ++ uint32_t revision_level; ++ uint16_t uid_reserved; ++ uint16_t gid_reserved; ++ uint32_t first_inode; ++ uint16_t inode_size; ++ uint16_t block_group_number; ++ uint32_t feature_compatibility; ++ uint32_t feature_incompat; ++ uint32_t feature_ro_compat; ++ uint32_t unique_id[4]; ++ char volume_name[16]; ++ char last_mounted_on[64]; ++ uint32_t compression_info; ++}; ++ ++struct ext2_block_group { ++ __u32 block_id; /* Blocks bitmap block */ ++ __u32 inode_id; /* Inodes bitmap block */ ++ __u32 inode_table_id; /* Inodes table block */ ++ __u16 free_blocks; /* Free blocks count */ ++ __u16 free_inodes; /* Free inodes count */ ++ __u16 used_dir_cnt; /* Directories count */ ++ __u16 bg_flags; ++ __u32 bg_reserved[2]; ++ __u16 bg_itable_unused; /* Unused inodes count */ ++ __u16 bg_checksum; /* crc16(s_uuid+grouo_num+group_desc)*/ ++}; ++ ++/* The ext2 inode. */ ++struct ext2_inode { ++ uint16_t mode; ++ uint16_t uid; ++ uint32_t size; ++ uint32_t atime; ++ uint32_t ctime; ++ uint32_t mtime; ++ uint32_t dtime; ++ uint16_t gid; ++ uint16_t nlinks; ++ uint32_t blockcnt; /* Blocks of 512 bytes!! */ ++ uint32_t flags; ++ uint32_t osd1; ++ union { ++ struct datablocks { ++ uint32_t dir_blocks[INDIRECT_BLOCKS]; ++ uint32_t indir_block; ++ uint32_t double_indir_block; ++ uint32_t triple_indir_block; ++ } blocks; ++ char symlink[60]; ++ } b; ++ uint32_t version; ++ uint32_t acl; ++ uint32_t dir_acl; ++ uint32_t fragment_addr; ++ uint32_t osd2[3]; ++}; ++ ++/* The header of an ext2 directory entry. */ ++struct ext2_dirent { ++ uint32_t inode; ++ uint16_t direntlen; ++ uint8_t namelen; ++ uint8_t filetype; ++}; ++ ++struct ext2fs_node { ++ struct ext2_data *data; ++ struct ext2_inode inode; ++ int ino; ++ int inode_read; ++}; ++ ++/* Information about a "mounted" ext2 filesystem. */ ++struct ext2_data { ++ struct ext2_sblock sblock; ++ struct ext2_inode *inode; ++ struct ext2fs_node diropen; ++}; ++#endif +-- +2.2.1 + diff --git a/alarm/uboot-odroid-c1/0002-remove-cross-compiling.patch b/alarm/uboot-odroid-c1/0002-remove-cross-compiling.patch new file mode 100644 index 000000000..635219255 --- /dev/null +++ b/alarm/uboot-odroid-c1/0002-remove-cross-compiling.patch @@ -0,0 +1,36 @@ +From 26b9caa2359554bca862fba7298cde0d393eaee1 Mon Sep 17 00:00:00 2001 +From: Kevin Mihelich +Date: Sun, 21 Dec 2014 18:04:05 -0700 +Subject: [PATCH 2/3] remove cross-compiling + +--- + arch/arm/config.mk | 2 +- + arch/arm/cpu/aml_meson/config.mk | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/config.mk b/arch/arm/config.mk +index 0f9bffe..ecd547a 100755 +--- a/arch/arm/config.mk ++++ b/arch/arm/config.mk +@@ -21,7 +21,7 @@ + # MA 02111-1307 USA + # + +-CROSS_COMPILE ?= arm-none-eabi- ++#CROSS_COMPILE ?= arm-none-eabi- + #arm-linux- + + ifeq ($(BOARD),omap2420h4) +diff --git a/arch/arm/cpu/aml_meson/config.mk b/arch/arm/cpu/aml_meson/config.mk +index cdf0bbc..07bd9a0 100755 +--- a/arch/arm/cpu/aml_meson/config.mk ++++ b/arch/arm/cpu/aml_meson/config.mk +@@ -1,4 +1,4 @@ +-CROSS_COMPILE=arm-none-eabi- ++#CROSS_COMPILE=arm-none-eabi- + ARM_CPU=cortex-a9 + PLATFORM_CPPFLAGS += $(call cc-option,-mcpu=cortex-a9 -ffixed-r8 -mno-long-calls -Wall -fPIC ) + #USE_PRIVATE_LIBGCC=yes +-- +2.2.1 + diff --git a/alarm/uboot-odroid-c1/0003-sd_fusing-tweaks.patch b/alarm/uboot-odroid-c1/0003-sd_fusing-tweaks.patch new file mode 100644 index 000000000..17cbb9e9e --- /dev/null +++ b/alarm/uboot-odroid-c1/0003-sd_fusing-tweaks.patch @@ -0,0 +1,41 @@ +From 4dd3392b9a0642fdbbfb9c00cf094f46c32cb210 Mon Sep 17 00:00:00 2001 +From: Kevin Mihelich +Date: Mon, 22 Dec 2014 09:55:32 -0700 +Subject: [PATCH 3/3] sd_fusing tweaks + +--- + sd_fuse/sd_fusing.sh | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/sd_fuse/sd_fusing.sh b/sd_fuse/sd_fusing.sh +index f0ce95a..f65980a 100755 +--- a/sd_fuse/sd_fusing.sh ++++ b/sd_fuse/sd_fusing.sh +@@ -12,18 +12,17 @@ if [ -z $1 ]; then + fi + + if [ ! -f $BL1 ]; then +- echo "Error: $BL1 is not exist." ++ echo "Error: $BL1 does not exist." + exit 0 + fi + + if [ ! -f $UBOOT ]; then +- echo "Error: $UBOOT is not exist." ++ echo "Error: $UBOOT does not exist." + exit 0 + fi + +-sudo dd if=$BL1 of=$1 bs=1 count=442 +-sudo dd if=$BL1 of=$1 bs=512 skip=1 seek=1 +-sudo dd if=$UBOOT of=$1 bs=512 seek=64 ++dd if=$BL1 of=$1 bs=1 count=442 ++dd if=$BL1 of=$1 bs=512 skip=1 seek=1 ++dd if=$UBOOT of=$1 bs=512 seek=64 + sync +-sudo eject $1 +-echo FINISH ++echo "Successfully wrote U-Boot to $1" +-- +2.2.1 + diff --git a/alarm/uboot-odroid-c1/PKGBUILD b/alarm/uboot-odroid-c1/PKGBUILD new file mode 100644 index 000000000..572bf1182 --- /dev/null +++ b/alarm/uboot-odroid-c1/PKGBUILD @@ -0,0 +1,51 @@ +# U-Boot: ODROID-C1 +# Maintainer: Kevin Mihelich + +buildarch=4 + +pkgname=uboot-odroid-c1 +pkgver=2011.03 +pkgrel=1 +pkgdesc="U-Boot for ODROID-C1" +arch=('armv7h') +url="https://github.com/hardkernel/u-boot" +license=('GPL') +makedepends=('git' 'bc') +backup=('boot/boot.ini') +_commit=388b4ae60f25e5e1a7a625b2253a66d05ab725d0 +source=("https://github.com/hardkernel/u-boot/archive/${_commit}.tar.gz" + 'boot.ini' + '0001-add-ext4-support.patch' + '0002-remove-cross-compiling.patch' + '0003-sd_fusing-tweaks.patch') +md5sums=('b8b66d02d1fab2a4745a7b769bff4b0c' + '4b96ce4971e9724fbf5197f29742ca17' + 'c8d1d5911a15ed995cf7fd57ef86b8fe' + '127c91d5af47a6dd78fdaf19a77a5263' + '645b00a999368d95c36d6cb5ef2f1076') + +prepare() { + cd u-boot-${_commit} + + git apply ../0001-add-ext4-support.patch + git apply ../0002-remove-cross-compiling.patch + git apply ../0003-sd_fusing-tweaks.patch +} + +build() { + cd u-boot-${_commit} + + unset CFLAGS CXXFLAGS CPPFLAGS LDFLAGS + + make distclean + make odroidc_config + make EXTRAVERSION=-${pkgrel} +} + +package() { + cd u-boot-${_commit}/sd_fuse + + mkdir -p "${pkgdir}"/boot + cp bl1.bin.hardkernel sd_fusing.sh u-boot.bin "${pkgdir}"/boot + cp "${srcdir}"/boot.ini "${pkgdir}"/boot +} diff --git a/alarm/uboot-odroid-c1/boot.ini b/alarm/uboot-odroid-c1/boot.ini new file mode 100644 index 000000000..3ed501ee6 --- /dev/null +++ b/alarm/uboot-odroid-c1/boot.ini @@ -0,0 +1,25 @@ +ODROIDC-UBOOT-CONFIG + +# Possible screen resolutions +# Uncomment only a single Line! The line with setenv written. +# At least one mode must be selected. + +# setenv m "vga" # VGA 640x480 +# setenv m "480p" # 480p 720x480 +# setenv m "576p" # 576p 720x576 +# setenv m "800x480p60hz" # WVGA 800x480 +# setenv m "svga" # Super VGA 800x600 +# setenv m "xga" # XGA 1024x768 +setenv m "720p" # 720p 1280x720 +# setenv m "800p" # 800p(WXGA) 1280x800 +# setenv m "sxga" # SXGA 1280x1024 +# setenv m "1080p" # 1080P 1920x1080 +# setenv m "1920x1200" # 1920x1200 + +# HDMI BPP Mode +# setenv m_bpp "32" +setenv m_bpp "16" + +setenv bootargs "console=ttyS0,115200n8 root=/dev/mmcblk0p1 rootwait rw no_console_suspend vdaccfg=0xa000 logo=osd1,loaded,0x7900000,720p,full dmfc=3 cvbsmode=576cvbs hdmimode=${m} m_bpp=${m_bpp} mac=${ethaddr}" +setenv bootcmd "ext4load mmc 0:1 0x21000000 /boot/uImage; ext4load mmc 0:1 0x21800000 /boot/dtbs/meson8b_odroidc.dtb; bootm 0x21000000 - 0x21800000" +run bootcmd diff --git a/alarm/uboot-odroid-c1/uboot-odroid-c1.install b/alarm/uboot-odroid-c1/uboot-odroid-c1.install new file mode 100644 index 000000000..11a045c50 --- /dev/null +++ b/alarm/uboot-odroid-c1/uboot-odroid-c1.install @@ -0,0 +1,32 @@ +sd_fuse() { + if [ ! -b /dev/mmcblk0 ]; then + echo "No MMC device to flash, exiting." + exit 0 + fi + + echo "BL1 fusing" + dd if=/boot/bl1.bin.hardkernel of=/dev/mmcblk0 bs=1 count=442 + dd if=/boot/bl1.bin.hardkernel of=/dev/mmcblk0 bs=512 skip=1 seek=1 + echo "u-boot fusing" + dd if=/boot/u-boot.bin of=/dev/mmcblk0 bs=512 seek=64 +} + +flash_uboot() { + echo "A new U-Boot version needs to be flashed onto /dev/mmcblk0." + echo "Do you want to do this now? [y|N]" + read -r shouldwe + if [[ $shouldwe =~ ^([yY][eE][sS]|[yY])$ ]]; then + sd_fuse + else + echo "You can do this later by running:" + echo "# cd /boot; ./sd_fusing.sh /dev/mmcblk0" + fi +} + +post_install() { + flash_uboot +} + +post_upgrade() { + flash_uboot +}