Imported Upstream version 1.47.0
[platform/upstream/e2fsprogs.git] / lib / ext2fs / extent.c
index bde6b0f..82e75cc 100644 (file)
@@ -47,6 +47,7 @@ struct extent_path {
        int             visit_num;
        int             flags;
        blk64_t         end_blk;
+       blk64_t         blk;
        void            *curr;
 };
 
@@ -286,6 +287,7 @@ errcode_t ext2fs_extent_open2(ext2_filsys fs, ext2_ino_t ino,
        handle->path[0].end_blk =
                (EXT2_I_SIZE(handle->inode) + fs->blocksize - 1) >>
                 EXT2_BLOCK_SIZE_BITS(fs->super);
+       handle->path[0].blk = 0;
        handle->path[0].visit_num = 1;
        handle->level = 0;
        handle->magic = EXT2_ET_MAGIC_EXTENT_HANDLE;
@@ -305,14 +307,14 @@ errout:
 errcode_t ext2fs_extent_get(ext2_extent_handle_t handle,
                            int flags, struct ext2fs_extent *extent)
 {
-       struct extent_path      *path, *newpath;
+       struct extent_path      *path, *newpath, *tp;
        struct ext3_extent_header       *eh;
        struct ext3_extent_idx          *ix = 0;
        struct ext3_extent              *ex;
        errcode_t                       retval;
        blk64_t                         blk;
        blk64_t                         end_blk;
-       int                             orig_op, op;
+       int                             orig_op, op, l;
        int                             failed_csum = 0;
 
        EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
@@ -467,6 +469,11 @@ retry:
                }
                blk = ext2fs_le32_to_cpu(ix->ei_leaf) +
                        ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32);
+               for (l = handle->level, tp = path; l > 0; l--, tp--) {
+                       if (blk == tp->blk)
+                               return EXT2_ET_EXTENT_CYCLE;
+               }
+               newpath->blk = blk;
                if ((handle->fs->flags & EXT2_FLAG_IMAGE_FILE) &&
                    (handle->fs->io != handle->fs->image_io))
                        memset(newpath->buf, 0, handle->fs->blocksize);
@@ -495,6 +502,10 @@ retry:
                        ext2fs_le16_to_cpu(eh->eh_entries);
                newpath->max_entries = ext2fs_le16_to_cpu(eh->eh_max);
 
+               /* Make sure there is at least one extent present */
+               if (newpath->left <= 0)
+                       return EXT2_ET_EXTENT_NO_DOWN;
+
                if (path->left > 0) {
                        ix++;
                        newpath->end_blk = ext2fs_le32_to_cpu(ix->ei_block);
@@ -1630,6 +1641,10 @@ errcode_t ext2fs_extent_delete(ext2_extent_handle_t handle, int flags)
 
        cp = path->curr;
 
+       /* Sanity check before memmove() */
+       if (path->left < 0)
+               return EXT2_ET_EXTENT_LEAF_BAD;
+
        if (path->left) {
                memmove(cp, cp + sizeof(struct ext3_extent_idx),
                        path->left * sizeof(struct ext3_extent_idx));
@@ -1797,7 +1812,7 @@ errcode_t ext2fs_decode_extent(struct ext2fs_extent *to, void *addr, int len)
                        << 32);
        to->e_lblk = ext2fs_le32_to_cpu(from->ee_block);
        to->e_len = ext2fs_le16_to_cpu(from->ee_len);
-       to->e_flags |= EXT2_EXTENT_FLAGS_LEAF;
+       to->e_flags = EXT2_EXTENT_FLAGS_LEAF;
        if (to->e_len > EXT_INIT_MAX_LEN) {
                to->e_len -= EXT_INIT_MAX_LEN;
                to->e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
@@ -1809,7 +1824,7 @@ errcode_t ext2fs_decode_extent(struct ext2fs_extent *to, void *addr, int len)
 errcode_t ext2fs_count_blocks(ext2_filsys fs, ext2_ino_t ino,
                              struct ext2_inode *inode, blk64_t *ret_count)
 {
-       ext2_extent_handle_t    handle;
+       ext2_extent_handle_t    handle = NULL;
        struct ext2fs_extent    extent;
        errcode_t               errcode;
        int                     i;
@@ -1824,8 +1839,11 @@ errcode_t ext2fs_count_blocks(ext2_filsys fs, ext2_ino_t ino,
        if (errcode)
                goto out;
 
-       ext2fs_get_array(handle->max_depth, sizeof(blk64_t),
-                               &intermediate_nodes);
+       errcode = ext2fs_get_array(handle->max_depth, sizeof(blk64_t),
+                                  &intermediate_nodes);
+       if (errcode)
+               goto out;
+
        blkcount = handle->level;
        while (!errcode) {
                if (extent.e_flags & EXT2_EXTENT_FLAGS_LEAF) {