]> git.sur5r.net Git - u-boot/blobdiff - fs/ext4/ext4_common.c
fs: ext4: fix symlink read function
[u-boot] / fs / ext4 / ext4_common.c
index 352943ec5145fd873c82cece29d61c601be13906..40b798a43fa62e0237b3e70162efcaefc76a0f61 100644 (file)
@@ -22,7 +22,9 @@
 #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>
@@ -73,35 +75,26 @@ void put_ext4(uint64_t off, void *buf, uint32_t size)
        if ((startblock + (size >> log2blksz)) >
            (part_offset + fs->total_sect)) {
                printf("part_offset is " LBAFU "\n", part_offset);
-               printf("total_sector is %llu\n", fs->total_sect);
+               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 >> log2blksz != 0) {
-                       fs->dev_desc->block_write(fs->dev_desc->dev,
-                                                 startblock,
-                                                 size >> log2blksz,
-                                                 (unsigned long *)buf);
+                       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);
                }
        }
 }
@@ -445,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 =
@@ -613,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) {
@@ -744,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);
@@ -764,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;
@@ -817,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)
@@ -864,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].
@@ -904,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--;
@@ -929,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;
@@ -996,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;
@@ -1037,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;
@@ -1143,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;
        }
@@ -1242,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;
@@ -1250,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;
        }
@@ -1282,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)++;
@@ -1316,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;
@@ -1336,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,
@@ -1348,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);
 
@@ -1357,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);
 
@@ -1365,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);
 }
@@ -1382,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");
@@ -1392,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,
@@ -1414,7 +1413,7 @@ 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) {
@@ -1430,7 +1429,7 @@ static struct ext4_extent_header *ext4fs_get_extent_block
                        i++;
                        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;
@@ -1438,7 +1437,7 @@ static struct ext4_extent_header *ext4fs_get_extent_block
                block = le16_to_cpu(index[i].ei_leaf_hi);
                block = (block << 32) + le32_to_cpu(index[i].ei_leaf_lo);
 
-               if (ext4fs_devread((lbaint_t)block << log2_blksz, 0, fs->blksz,
+               if (ext4fs_devread((lbaint_t)block << log2_blksz, 0, blksz,
                                   buf))
                        ext_block = (struct ext4_extent_header *)buf;
                else
@@ -1843,16 +1842,20 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
        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;
@@ -1872,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
@@ -1895,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;
@@ -1907,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));
@@ -1990,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);
@@ -2006,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);
@@ -2016,14 +2040,14 @@ static char *ext4fs_read_symlink(struct ext2fs_node *node)
        if (!symlink)
                return 0;
 
-       if (__le32_to_cpu(diro->inode.size) <= 60) {
+       if (__le32_to_cpu(diro->inode.size) < sizeof(diro->inode.b.symlink)) {
                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) {
+                                          symlink, &actread);
+               if ((status < 0) || (actread == 0)) {
                        free(symlink);
                        return 0;
                }
@@ -2156,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;
@@ -2177,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);