Merge branch 'master' of git://git.denx.de/u-boot-video
[oweals/u-boot.git] / fs / ext4 / ext4_common.c
index 323875fa9452e9863b8fa21376b519c28f1729da..84fba767c1ad71e3a5df53c8bbd0696e2f690f81 100644 (file)
  *
  * 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.
+ * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
 #include <ext_common.h>
 #include <ext4fs.h>
+#include <inttypes.h>
 #include <malloc.h>
+#include <memalign.h>
 #include <stddef.h>
 #include <linux/stat.h>
 #include <linux/time.h>
@@ -71,49 +61,40 @@ void put_ext4(uint64_t off, void *buf, uint32_t size)
        uint64_t startblock;
        uint64_t remainder;
        unsigned char *temp_ptr = NULL;
-       ALLOC_CACHE_ALIGN_BUFFER(unsigned char, sec_buf, SECTOR_SIZE);
        struct ext_filesystem *fs = get_fs();
+       int log2blksz = fs->dev_desc->log2blksz;
+       ALLOC_CACHE_ALIGN_BUFFER(unsigned char, sec_buf, fs->dev_desc->blksz);
 
-       startblock = off / (uint64_t)SECTOR_SIZE;
+       startblock = off >> log2blksz;
        startblock += part_offset;
-       remainder = off % (uint64_t)SECTOR_SIZE;
-       remainder &= SECTOR_SIZE - 1;
+       remainder = off & (uint64_t)(fs->dev_desc->blksz - 1);
 
        if (fs->dev_desc == NULL)
                return;
 
-       if ((startblock + (size / SECTOR_SIZE)) >
+       if ((startblock + (size >> log2blksz)) >
            (part_offset + fs->total_sect)) {
-               printf("part_offset is %lu\n", part_offset);
-               printf("total_sector is %llu\n", fs->total_sect);
+               printf("part_offset is " LBAFU "\n", part_offset);
+               printf("total_sector is %" PRIu64 "\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);
-               }
+               blk_dread(fs->dev_desc, startblock, 1, sec_buf);
+               temp_ptr = sec_buf;
+               memcpy((temp_ptr + remainder), (unsigned char *)buf, size);
+               blk_dwrite(fs->dev_desc, 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);
+               if (size >> log2blksz != 0) {
+                       blk_dwrite(fs->dev_desc, startblock, size >> log2blksz,
+                                  (unsigned long *)buf);
                } else {
-                       fs->dev_desc->block_read(fs->dev_desc->dev,
-                                                startblock, 1, sec_buf);
+                       blk_dread(fs->dev_desc, 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);
+                       blk_dwrite(fs->dev_desc, startblock, 1,
+                                  (unsigned long *)sec_buf);
                }
        }
 }
@@ -378,7 +359,6 @@ void ext4fs_update_parent_dentry(char *filename, int *p_ino, int file_type)
        struct ext_filesystem *fs = get_fs();
        /* directory entry */
        struct ext2_dirent *dir;
-       char *ptr = NULL;
        char *temp_dir = NULL;
 
        zero_buffer = zalloc(fs->blksz);
@@ -406,7 +386,7 @@ restart:
                previous_blknr = root_blknr;
        }
 
-       status = ext4fs_devread(first_block_no_of_root
+       status = ext4fs_devread((lbaint_t)first_block_no_of_root
                                * fs->sect_perblk,
                                0, fs->blksz, root_first_block_buffer);
        if (status == 0)
@@ -415,7 +395,6 @@ restart:
        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) {
                /*
@@ -459,9 +438,9 @@ restart:
                                        goto fail;
                                }
                                put_ext4(((uint64_t)
-                                         (g_parent_inode->b.
+                                         ((uint64_t)g_parent_inode->b.
                                           blocks.dir_blocks[direct_blk_idx] *
-                                          fs->blksz)), zero_buffer, fs->blksz);
+                                          (uint64_t)fs->blksz)), zero_buffer, fs->blksz);
                                g_parent_inode->size =
                                    g_parent_inode->size + fs->blksz;
                                g_parent_inode->blockcnt =
@@ -483,14 +462,12 @@ restart:
                        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();
@@ -549,7 +526,7 @@ static int search_dir(struct ext2_inode *parent_inode, char *dirname)
                if (!block_buffer)
                        goto fail;
 
-               status = ext4fs_devread(blknr * fs->sect_perblk,
+               status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk,
                                        0, fs->blksz, (char *)block_buffer);
                if (status == 0)
                        goto fail;
@@ -629,8 +606,7 @@ static int parse_path(char **arr, char *dirname)
        arr[i] = zalloc(strlen("/") + 1);
        if (!arr[i])
                return -ENOMEM;
-
-       arr[i++] = "/";
+       memcpy(arr[i++], "/", strlen("/"));
 
        /* add each path entry after root */
        while (token != NULL) {
@@ -760,6 +736,11 @@ end:
 fail:
        free(depth_dirname);
        free(parse_dirname);
+       for (i = 0; i < depth; i++) {
+               if (!ptr[i])
+                       break;
+               free(ptr[i]);
+       }
        free(ptr);
        free(parent_inode);
        free(first_inode);
@@ -780,6 +761,7 @@ static int check_filename(char *filename, unsigned int blknr)
        struct ext2_dirent *previous_dir = NULL;
        char *ptr = NULL;
        struct ext_filesystem *fs = get_fs();
+       int ret = -1;
 
        /* get the first block of root */
        first_block_no_of_root = blknr;
@@ -787,7 +769,7 @@ static int check_filename(char *filename, unsigned int blknr)
        if (!root_first_block_buffer)
                return -ENOMEM;
        root_first_block_addr = root_first_block_buffer;
-       status = ext4fs_devread(first_block_no_of_root *
+       status = ext4fs_devread((lbaint_t)first_block_no_of_root *
                                fs->sect_perblk, 0,
                                fs->blksz, root_first_block_buffer);
        if (status == 0)
@@ -833,12 +815,12 @@ static int check_filename(char *filename, unsigned int blknr)
                if (ext4fs_put_metadata(root_first_block_addr,
                                        first_block_no_of_root))
                        goto fail;
-               return inodeno;
+               ret = inodeno;
        }
 fail:
        free(root_first_block_buffer);
 
-       return -1;
+       return ret;
 }
 
 int ext4fs_filename_check(char *filename)
@@ -880,8 +862,8 @@ long int ext4fs_get_new_blk_no(void)
                for (i = 0; i < fs->no_blkgrp; i++) {
                        if (bgd[i].free_blocks) {
                                if (bgd[i].bg_flags & EXT4_BG_BLOCK_UNINIT) {
-                                       put_ext4(((uint64_t) (bgd[i].block_id *
-                                                             fs->blksz)),
+                                       put_ext4(((uint64_t) ((uint64_t)bgd[i].block_id *
+                                                             (uint64_t)fs->blksz)),
                                                 zero_buffer, fs->blksz);
                                        bgd[i].bg_flags =
                                            bgd[i].
@@ -899,7 +881,8 @@ long int ext4fs_get_new_blk_no(void)
                                fs->first_pass_bbmap++;
                                bgd[i].free_blocks--;
                                fs->sb->free_blocks--;
-                               status = ext4fs_devread(bgd[i].block_id *
+                               status = ext4fs_devread((lbaint_t)
+                                                       bgd[i].block_id *
                                                        fs->sect_perblk, 0,
                                                        fs->blksz,
                                                        journal_buffer);
@@ -919,10 +902,8 @@ long int ext4fs_get_new_blk_no(void)
 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;
+               bg_idx = fs->curr_blkno / blk_per_grp;
+               if (fs->blksz == 1024) {
                        remainder = fs->curr_blkno % blk_per_grp;
                        if (!remainder)
                                bg_idx--;
@@ -944,8 +925,8 @@ restart:
 
                if (bgd[bg_idx].bg_flags & EXT4_BG_BLOCK_UNINIT) {
                        memset(zero_buffer, '\0', fs->blksz);
-                       put_ext4(((uint64_t) (bgd[bg_idx].block_id *
-                                       fs->blksz)), zero_buffer, fs->blksz);
+                       put_ext4(((uint64_t) ((uint64_t)bgd[bg_idx].block_id *
+                                       (uint64_t)fs->blksz)), zero_buffer, fs->blksz);
                        memcpy(fs->blk_bmaps[bg_idx], zero_buffer, fs->blksz);
                        bgd[bg_idx].bg_flags = bgd[bg_idx].bg_flags &
                                                ~EXT4_BG_BLOCK_UNINIT;
@@ -961,7 +942,7 @@ restart:
                /* journal backup */
                if (prev_bg_bitmap_index != bg_idx) {
                        memset(journal_buffer, '\0', fs->blksz);
-                       status = ext4fs_devread(bgd[bg_idx].block_id
+                       status = ext4fs_devread((lbaint_t)bgd[bg_idx].block_id
                                                * fs->sect_perblk,
                                                0, fs->blksz, journal_buffer);
                        if (status == 0)
@@ -1011,8 +992,8 @@ int ext4fs_get_new_inode_no(void)
                                                bgd[i].free_inodes;
                                if (bgd[i].bg_flags & EXT4_BG_INODE_UNINIT) {
                                        put_ext4(((uint64_t)
-                                                 (bgd[i].inode_id *
-                                                       fs->blksz)),
+                                                 ((uint64_t)bgd[i].inode_id *
+                                                       (uint64_t)fs->blksz)),
                                                 zero_buffer, fs->blksz);
                                        bgd[i].bg_flags = bgd[i].bg_flags &
                                                        ~EXT4_BG_INODE_UNINIT;
@@ -1030,7 +1011,8 @@ int ext4fs_get_new_inode_no(void)
                                bgd[i].free_inodes--;
                                bgd[i].bg_itable_unused--;
                                fs->sb->free_inodes--;
-                               status = ext4fs_devread(bgd[i].inode_id *
+                               status = ext4fs_devread((lbaint_t)
+                                                       bgd[i].inode_id *
                                                        fs->sect_perblk, 0,
                                                        fs->blksz,
                                                        journal_buffer);
@@ -1051,8 +1033,8 @@ restart:
                ibmap_idx = fs->curr_inode_no / inodes_per_grp;
                if (bgd[ibmap_idx].bg_flags & EXT4_BG_INODE_UNINIT) {
                        memset(zero_buffer, '\0', fs->blksz);
-                       put_ext4(((uint64_t) (bgd[ibmap_idx].inode_id *
-                                             fs->blksz)), zero_buffer,
+                       put_ext4(((uint64_t) ((uint64_t)bgd[ibmap_idx].inode_id *
+                                             (uint64_t)fs->blksz)), zero_buffer,
                                 fs->blksz);
                        bgd[ibmap_idx].bg_flags =
                            bgd[ibmap_idx].bg_flags & ~EXT4_BG_INODE_UNINIT;
@@ -1071,7 +1053,8 @@ restart:
                /* journal backup */
                if (prev_inode_bitmap_index != ibmap_idx) {
                        memset(journal_buffer, '\0', fs->blksz);
-                       status = ext4fs_devread(bgd[ibmap_idx].inode_id
+                       status = ext4fs_devread((lbaint_t)
+                                               bgd[ibmap_idx].inode_id
                                                * fs->sect_perblk,
                                                0, fs->blksz, journal_buffer);
                        if (status == 0)
@@ -1133,7 +1116,7 @@ static void alloc_single_indirect_block(struct ext2_inode *file_inode,
                (*no_blks_reqd)++;
                debug("SIPB %ld: %u\n", si_blockno, *total_remaining_blocks);
 
-               status = ext4fs_devread(si_blockno * fs->sect_perblk,
+               status = ext4fs_devread((lbaint_t)si_blockno * fs->sect_perblk,
                                        0, fs->blksz, (char *)si_buffer);
                memset(si_buffer, '\0', fs->blksz);
                if (status == 0)
@@ -1156,7 +1139,7 @@ static void alloc_single_indirect_block(struct ext2_inode *file_inode,
                }
 
                /* write the block to disk */
-               put_ext4(((uint64_t) (si_blockno * fs->blksz)),
+               put_ext4(((uint64_t) ((uint64_t)si_blockno * (uint64_t)fs->blksz)),
                         si_start_addr, fs->blksz);
                file_inode->b.blocks.indir_block = si_blockno;
        }
@@ -1197,9 +1180,14 @@ static void alloc_double_indirect_block(struct ext2_inode *file_inode,
                debug("DIPB %ld: %u\n", di_blockno_parent,
                      *total_remaining_blocks);
 
-               status = ext4fs_devread(di_blockno_parent *
+               status = ext4fs_devread((lbaint_t)di_blockno_parent *
                                        fs->sect_perblk, 0,
                                        fs->blksz, (char *)di_parent_buffer);
+
+               if (!status) {
+                       printf("%s: Device read error!\n", __func__);
+                       goto fail;
+               }
                memset(di_parent_buffer, '\0', fs->blksz);
 
                /*
@@ -1223,10 +1211,15 @@ static void alloc_double_indirect_block(struct ext2_inode *file_inode,
                        debug("DICB %ld: %u\n", di_blockno_child,
                              *total_remaining_blocks);
 
-                       status = ext4fs_devread(di_blockno_child *
+                       status = ext4fs_devread((lbaint_t)di_blockno_child *
                                                fs->sect_perblk, 0,
                                                fs->blksz,
                                                (char *)di_child_buff);
+
+                       if (!status) {
+                               printf("%s: Device read error!\n", __func__);
+                               goto fail;
+                       }
                        memset(di_child_buff, '\0', fs->blksz);
                        /* filling of actual datablocks for each child */
                        for (j = 0; j < (fs->blksz / sizeof(int)); j++) {
@@ -1245,7 +1238,7 @@ static void alloc_double_indirect_block(struct ext2_inode *file_inode,
                                        break;
                        }
                        /* write the block  table */
-                       put_ext4(((uint64_t) (di_blockno_child * fs->blksz)),
+                       put_ext4(((uint64_t) ((uint64_t)di_blockno_child * (uint64_t)fs->blksz)),
                                 di_child_buff_start, fs->blksz);
                        free(di_child_buff_start);
                        di_child_buff_start = NULL;
@@ -1253,7 +1246,7 @@ static void alloc_double_indirect_block(struct ext2_inode *file_inode,
                        if (*total_remaining_blocks == 0)
                                break;
                }
-               put_ext4(((uint64_t) (di_blockno_parent * fs->blksz)),
+               put_ext4(((uint64_t) ((uint64_t)di_blockno_parent * (uint64_t)fs->blksz)),
                         di_block_start_addr, fs->blksz);
                file_inode->b.blocks.double_indir_block = di_blockno_parent;
        }
@@ -1285,11 +1278,11 @@ static void alloc_triple_indirect_block(struct ext2_inode *file_inode,
                ti_gp_blockno = ext4fs_get_new_blk_no();
                if (ti_gp_blockno == -1) {
                        printf("no block left to assign\n");
-                       goto fail;
+                       return;
                }
                ti_gp_buff = zalloc(fs->blksz);
                if (!ti_gp_buff)
-                       goto fail;
+                       return;
 
                ti_gp_buff_start_addr = ti_gp_buff;
                (*no_blks_reqd)++;
@@ -1319,11 +1312,11 @@ static void alloc_triple_indirect_block(struct ext2_inode *file_inode,
                                ti_child_blockno = ext4fs_get_new_blk_no();
                                if (ti_child_blockno == -1) {
                                        printf("no block left assign\n");
-                                       goto fail;
+                                       goto fail1;
                                }
                                ti_child_buff = zalloc(fs->blksz);
                                if (!ti_child_buff)
-                                       goto fail;
+                                       goto fail1;
 
                                ti_cbuff_start_addr = ti_child_buff;
                                *ti_parent_buff = ti_child_blockno;
@@ -1339,7 +1332,8 @@ static void alloc_triple_indirect_block(struct ext2_inode *file_inode,
                                            ext4fs_get_new_blk_no();
                                        if (actual_block_no == -1) {
                                                printf("no block left\n");
-                                               goto fail;
+                                               free(ti_cbuff_start_addr);
+                                               goto fail1;
                                        }
                                        *ti_child_buff = actual_block_no;
                                        debug("TIAB %ld: %u\n", actual_block_no,
@@ -1351,8 +1345,8 @@ static void alloc_triple_indirect_block(struct ext2_inode *file_inode,
                                                break;
                                }
                                /* write the child block */
-                               put_ext4(((uint64_t) (ti_child_blockno *
-                                                     fs->blksz)),
+                               put_ext4(((uint64_t) ((uint64_t)ti_child_blockno *
+                                                     (uint64_t)fs->blksz)),
                                         ti_cbuff_start_addr, fs->blksz);
                                free(ti_cbuff_start_addr);
 
@@ -1360,7 +1354,7 @@ static void alloc_triple_indirect_block(struct ext2_inode *file_inode,
                                        break;
                        }
                        /* write the parent block */
-                       put_ext4(((uint64_t) (ti_parent_blockno * fs->blksz)),
+                       put_ext4(((uint64_t) ((uint64_t)ti_parent_blockno * (uint64_t)fs->blksz)),
                                 ti_pbuff_start_addr, fs->blksz);
                        free(ti_pbuff_start_addr);
 
@@ -1368,10 +1362,14 @@ static void alloc_triple_indirect_block(struct ext2_inode *file_inode,
                                break;
                }
                /* write the grand parent block */
-               put_ext4(((uint64_t) (ti_gp_blockno * fs->blksz)),
+               put_ext4(((uint64_t) ((uint64_t)ti_gp_blockno * (uint64_t)fs->blksz)),
                         ti_gp_buff_start_addr, fs->blksz);
                file_inode->b.blocks.triple_indir_block = ti_gp_blockno;
+               free(ti_gp_buff_start_addr);
+               return;
        }
+fail1:
+       free(ti_pbuff_start_addr);
 fail:
        free(ti_gp_buff_start_addr);
 }
@@ -1385,7 +1383,7 @@ void ext4fs_allocate_blocks(struct ext2_inode *file_inode,
        unsigned int no_blks_reqd = 0;
 
        /* allocation of direct blocks */
-       for (i = 0; i < INDIRECT_BLOCKS; i++) {
+       for (i = 0; total_remaining_blocks && i < INDIRECT_BLOCKS; i++) {
                direct_blockno = ext4fs_get_new_blk_no();
                if (direct_blockno == -1) {
                        printf("no block left to assign\n");
@@ -1395,8 +1393,6 @@ void ext4fs_allocate_blocks(struct ext2_inode *file_inode,
                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,
@@ -1417,13 +1413,13 @@ static struct ext4_extent_header *ext4fs_get_extent_block
 {
        struct ext4_extent_idx *index;
        unsigned long long block;
-       struct ext_filesystem *fs = get_fs();
+       int blksz = EXT2_BLOCK_SIZE(data);
        int i;
 
        while (1) {
                index = (struct ext4_extent_idx *)(ext_block + 1);
 
-               if (le32_to_cpu(ext_block->eh_magic) != EXT4_EXT_MAGIC)
+               if (le16_to_cpu(ext_block->eh_magic) != EXT4_EXT_MAGIC)
                        return 0;
 
                if (ext_block->eh_depth == 0)
@@ -1431,17 +1427,18 @@ static struct ext4_extent_header *ext4fs_get_extent_block
                i = -1;
                do {
                        i++;
-                       if (i >= le32_to_cpu(ext_block->eh_entries))
+                       if (i >= le16_to_cpu(ext_block->eh_entries))
                                break;
-               } while (fileblock > le32_to_cpu(index[i].ei_block));
+               } while (fileblock >= le32_to_cpu(index[i].ei_block));
 
                if (--i < 0)
                        return 0;
 
-               block = le32_to_cpu(index[i].ei_leaf_hi);
+               block = le16_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))
+               if (ext4fs_devread((lbaint_t)block << log2_blksz, 0, blksz,
+                                  buf))
                        ext_block = (struct ext4_extent_header *)buf;
                else
                        return 0;
@@ -1453,6 +1450,7 @@ static int ext4fs_blockgroup
 {
        long int blkno;
        unsigned int blkoff, desc_per_blk;
+       int log2blksz = get_fs()->dev_desc->log2blksz;
 
        desc_per_blk = EXT2_BLOCK_SIZE(data) / sizeof(struct ext2_block_group);
 
@@ -1463,7 +1461,8 @@ static int ext4fs_blockgroup
        debug("ext4fs read %d group descriptor (blkno %ld blkoff %u)\n",
              group, blkno, blkoff);
 
-       return ext4fs_devread(blkno << LOG2_EXT2_BLOCK_SIZE(data),
+       return ext4fs_devread((lbaint_t)blkno <<
+                             (LOG2_BLOCK_SIZE(data) - log2blksz),
                              blkoff, sizeof(struct ext2_block_group),
                              (char *)blkgrp);
 }
@@ -1473,6 +1472,7 @@ 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 log2blksz = get_fs()->dev_desc->log2blksz;
        int inodes_per_block, status;
        long int blkno;
        unsigned int blkoff;
@@ -1489,7 +1489,8 @@ int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode)
            (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,
+       status = ext4fs_devread((lbaint_t)blkno << (LOG2_BLOCK_SIZE(data) -
+                               log2blksz), blkoff,
                                sizeof(struct ext2_inode), (char *)inode);
        if (status == 0)
                return 0;
@@ -1509,7 +1510,9 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
        unsigned long long start;
        /* get the blocksize of the filesystem */
        blksz = EXT2_BLOCK_SIZE(ext4fs_root);
-       log2_blksz = LOG2_EXT2_BLOCK_SIZE(ext4fs_root);
+       log2_blksz = LOG2_BLOCK_SIZE(ext4fs_root)
+               - get_fs()->dev_desc->log2blksz;
+
        if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) {
                char *buf = zalloc(blksz);
                if (!buf)
@@ -1517,11 +1520,11 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
                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);
+               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);
@@ -1532,17 +1535,17 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
 
                do {
                        i++;
-                       if (i >= le32_to_cpu(ext_block->eh_entries))
+                       if (i >= le16_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)) {
+                       if (fileblock >= le16_to_cpu(extent[i].ee_len)) {
                                free(buf);
                                return 0;
                        }
 
-                       start = le32_to_cpu(extent[i].ee_start_hi);
+                       start = le16_to_cpu(extent[i].ee_start_hi);
                        start = (start << 32) +
                                        le32_to_cpu(extent[i].ee_start_lo);
                        free(buf);
@@ -1586,7 +1589,7 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
                if ((__le32_to_cpu(inode->b.blocks.indir_block) <<
                     log2_blksz) != ext4fs_indir1_blkno) {
                        status =
-                           ext4fs_devread(__le32_to_cpu
+                           ext4fs_devread((lbaint_t)__le32_to_cpu
                                           (inode->b.blocks.
                                            indir_block) << log2_blksz, 0,
                                           blksz, (char *)ext4fs_indir1_block);
@@ -1635,7 +1638,7 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
                if ((__le32_to_cpu(inode->b.blocks.double_indir_block) <<
                     log2_blksz) != ext4fs_indir1_blkno) {
                        status =
-                           ext4fs_devread(__le32_to_cpu
+                           ext4fs_devread((lbaint_t)__le32_to_cpu
                                           (inode->b.blocks.
                                            double_indir_block) << log2_blksz,
                                           0, blksz,
@@ -1675,7 +1678,7 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
                }
                if ((__le32_to_cpu(ext4fs_indir1_block[rblock / perblock]) <<
                     log2_blksz) != ext4fs_indir2_blkno) {
-                       status = ext4fs_devread(__le32_to_cpu
+                       status = ext4fs_devread((lbaint_t)__le32_to_cpu
                                                (ext4fs_indir1_block
                                                 [rblock /
                                                  perblock]) << log2_blksz, 0,
@@ -1727,7 +1730,8 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
                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)
+                           ((lbaint_t)
+                            __le32_to_cpu(inode->b.blocks.triple_indir_block)
                             << log2_blksz, 0, blksz,
                             (char *)ext4fs_indir1_block);
                        if (status == 0) {
@@ -1767,7 +1771,7 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
                                                       perblock_parent]) <<
                     log2_blksz)
                    != ext4fs_indir2_blkno) {
-                       status = ext4fs_devread(__le32_to_cpu
+                       status = ext4fs_devread((lbaint_t)__le32_to_cpu
                                                (ext4fs_indir1_block
                                                 [rblock /
                                                  perblock_parent]) <<
@@ -1812,7 +1816,7 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
                                                       perblock_child]) <<
                     log2_blksz) != ext4fs_indir3_blkno) {
                        status =
-                           ext4fs_devread(__le32_to_cpu
+                           ext4fs_devread((lbaint_t)__le32_to_cpu
                                           (ext4fs_indir2_block
                                            [(rblock / perblock_child)
                                             % (blksz / 4)]) << log2_blksz, 0,
@@ -1833,21 +1837,25 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
                blknr = __le32_to_cpu(ext4fs_indir3_block
                                      [rblock % perblock_child]);
        }
-       debug("ext4fs_read_block %ld\n", blknr);
+       debug("read_allocated_block %ld\n", blknr);
 
        return blknr;
 }
 
-void ext4fs_close(void)
+/**
+ * ext4fs_reinit_global() - Reinitialize values of ext4 write implementation's
+ *                         global pointers
+ *
+ * This function assures that for a file with the same name but different size
+ * the sequential store on the ext4 filesystem will be correct.
+ *
+ * In this function the global data, responsible for internal representation
+ * of the ext4 data are initialized to the reset state. Without this, during
+ * replacement of the smaller file with the bigger truncation of new file was
+ * performed.
+ */
+void ext4fs_reinit_global(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;
@@ -1867,12 +1875,26 @@ void ext4fs_close(void)
                ext4fs_indir3_blkno = -1;
        }
 }
+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;
+       }
+
+       ext4fs_reinit_global();
+}
 
 int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name,
                                struct ext2fs_node **fnode, int *ftype)
 {
        unsigned int fpos = 0;
        int status;
+       loff_t actread;
        struct ext2fs_node *diro = (struct ext2fs_node *) dir;
 
 #ifdef DEBUG
@@ -1890,10 +1912,15 @@ int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name,
 
                status = ext4fs_read_file(diro, fpos,
                                           sizeof(struct ext2_dirent),
-                                          (char *) &dirent);
-               if (status < 1)
+                                          (char *)&dirent, &actread);
+               if (status < 0)
                        return 0;
 
+               if (dirent.direntlen == 0) {
+                       printf("Failed to iterate over directory %s\n", name);
+                       return 0;
+               }
+
                if (dirent.namelen != 0) {
                        char filename[dirent.namelen + 1];
                        struct ext2fs_node *fdiro;
@@ -1902,8 +1929,9 @@ int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name,
                        status = ext4fs_read_file(diro,
                                                  fpos +
                                                  sizeof(struct ext2_dirent),
-                                                 dirent.namelen, filename);
-                       if (status < 1)
+                                                 dirent.namelen, filename,
+                                                 &actread);
+                       if (status < 0)
                                return 0;
 
                        fdiro = zalloc(sizeof(struct ext2fs_node));
@@ -1985,8 +2013,8 @@ int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name,
                                        printf("< ? > ");
                                        break;
                                }
-                               printf("%10d %s\n",
-                                       __le32_to_cpu(fdiro->inode.size),
+                               printf("%10u %s\n",
+                                      __le32_to_cpu(fdiro->inode.size),
                                        filename);
                        }
                        free(fdiro);
@@ -2001,6 +2029,7 @@ static char *ext4fs_read_symlink(struct ext2fs_node *node)
        char *symlink;
        struct ext2fs_node *diro = node;
        int status;
+       loff_t actread;
 
        if (!diro->inode_read) {
                status = ext4fs_read_inode(diro->data, diro->ino, &diro->inode);
@@ -2017,8 +2046,8 @@ static char *ext4fs_read_symlink(struct ext2fs_node *node)
        } else {
                status = ext4fs_read_file(diro, 0,
                                           __le32_to_cpu(diro->inode.size),
-                                          symlink);
-               if (status == 0) {
+                                          symlink, &actread);
+               if ((status < 0) || (actread == 0)) {
                        free(symlink);
                        return 0;
                }
@@ -2151,11 +2180,10 @@ int ext4fs_find_file(const char *path, struct ext2fs_node *rootnode,
        return 1;
 }
 
-int ext4fs_open(const char *filename)
+int ext4fs_open(const char *filename, loff_t *len)
 {
        struct ext2fs_node *fdiro = NULL;
        int status;
-       int len;
 
        if (ext4fs_root == NULL)
                return -1;
@@ -2172,10 +2200,10 @@ int ext4fs_open(const char *filename)
                if (status == 0)
                        goto fail;
        }
-       len = __le32_to_cpu(fdiro->inode.size);
+       *len = __le32_to_cpu(fdiro->inode.size);
        ext4fs_file = fdiro;
 
-       return len;
+       return 0;
 fail:
        ext4fs_free_node(fdiro, &ext4fs_root->diropen);
 
@@ -2187,13 +2215,12 @@ int ext4fs_mount(unsigned part_length)
        struct ext2_data *data;
        int status;
        struct ext_filesystem *fs = get_fs();
-       data = zalloc(sizeof(struct ext2_data));
+       data = zalloc(SUPERBLOCK_SIZE);
        if (!data)
                return 0;
 
        /* Read the superblock. */
-       status = ext4fs_devread(1 * 2, 0, sizeof(struct ext2_sblock),
-                               (char *)&data->sblock);
+       status = ext4_read_superblock((char *)&data->sblock);
 
        if (status == 0)
                goto fail;