]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blobdiff - e2fsck/pass1.c
e2fsck: mark device inodes with EXT4_EXTENTS_FL bad
[thirdparty/e2fsprogs.git] / e2fsck / pass1.c
index d9df28edb96025f6a16a22f69f69e669d5920fe6..8dfa82a078fe07fc1d67ad2aa19e04479ffaaa12 100644 (file)
@@ -151,10 +151,10 @@ int e2fsck_pass1_check_device_inode(ext2_filsys fs EXT2FS_ATTR((unused)),
        int     i;
 
        /*
-        * If the index flag is set, then this is a bogus
+        * If the index or extents flag is set, then this is a bogus
         * device/fifo/socket
         */
-       if (inode->i_flags & EXT2_INDEX_FL)
+       if (inode->i_flags & (EXT2_INDEX_FL | EXT4_EXTENTS_FL))
                return 0;
 
        /*
@@ -185,42 +185,16 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
 {
        unsigned int buflen;
        unsigned int len;
-       int i;
-       ext2_extent_handle_t    handle;
-       struct ext2_extent_info info;
-       struct ext2fs_extent    extent;
 
        if ((inode->i_size_high || inode->i_size == 0) ||
            (inode->i_flags & EXT2_INDEX_FL))
                return 0;
 
-       if (inode->i_flags & EXT4_EXTENTS_FL) {
-               if (inode->i_flags & EXT4_INLINE_DATA_FL)
-                       return 0;
-               if (inode->i_size > fs->blocksize)
-                       return 0;
-               if (ext2fs_extent_open2(fs, ino, inode, &handle))
-                       return 0;
-               i = 0;
-               if (ext2fs_extent_get_info(handle, &info) ||
-                   (info.num_entries != 1) ||
-                   (info.max_depth != 0))
-                       goto exit_extent;
-               if (ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent) ||
-                   (extent.e_lblk != 0) ||
-                   (extent.e_len != 1) ||
-                   (extent.e_pblk < fs->super->s_first_data_block) ||
-                   (extent.e_pblk >= ext2fs_blocks_count(fs->super)))
-                       goto exit_extent;
-               i = 1;
-       exit_extent:
-               ext2fs_extent_free(handle);
-               return i;
-       }
-
        if (inode->i_flags & EXT4_INLINE_DATA_FL) {
                size_t inline_size;
 
+               if (inode->i_flags & EXT4_EXTENTS_FL)
+                       return 0;
                if (ext2fs_inline_data_size(fs, ino, &inline_size))
                        return 0;
                if (inode->i_size != inline_size)
@@ -230,22 +204,48 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
        }
 
        if (ext2fs_is_fast_symlink(inode)) {
-               if (inode->i_size >= sizeof(inode->i_block))
+               if (inode->i_flags & EXT4_EXTENTS_FL)
                        return 0;
-
                buf = (char *)inode->i_block;
                buflen = sizeof(inode->i_block);
        } else {
-               if ((inode->i_size >= fs->blocksize) ||
-                   (inode->i_block[0] < fs->super->s_first_data_block) ||
-                   (inode->i_block[0] >= ext2fs_blocks_count(fs->super)))
-                       return 0;
+               ext2_extent_handle_t    handle;
+               struct ext2_extent_info info;
+               struct ext2fs_extent    extent;
+               blk64_t blk;
+               int i;
 
-               for (i = 1; i < EXT2_N_BLOCKS; i++)
-                       if (inode->i_block[i])
+               if (inode->i_flags & EXT4_EXTENTS_FL) {
+                       if (ext2fs_extent_open2(fs, ino, inode, &handle))
+                               return 0;
+                       if (ext2fs_extent_get_info(handle, &info) ||
+                           (info.num_entries != 1) ||
+                           (info.max_depth != 0)) {
+                               ext2fs_extent_free(handle);
                                return 0;
+                       }
+                       if (ext2fs_extent_get(handle, EXT2_EXTENT_ROOT,
+                                             &extent) ||
+                           (extent.e_lblk != 0) ||
+                           (extent.e_len != 1)) {
+                               ext2fs_extent_free(handle);
+                               return 0;
+                       }
+                       blk = extent.e_pblk;
+                       ext2fs_extent_free(handle);
+               } else {
+                       blk = inode->i_block[0];
+
+                       for (i = 1; i < EXT2_N_BLOCKS; i++)
+                               if (inode->i_block[i])
+                                       return 0;
+               }
 
-               if (io_channel_read_blk64(fs->io, inode->i_block[0], 1, buf))
+               if (blk < fs->super->s_first_data_block ||
+                   blk >= ext2fs_blocks_count(fs->super))
+                       return 0;
+
+               if (io_channel_read_blk64(fs->io, blk, 1, buf))
                        return 0;
 
                buflen = fs->blocksize;
@@ -260,8 +260,7 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
                return 0;
 
        if (len != inode->i_size)
-               if ((inode->i_flags & EXT4_ENCRYPT_FL) == 0)
-                       return 0;
+               return 0;
        return 1;
 }
 
@@ -1543,6 +1542,7 @@ void e2fsck_pass1(e2fsck_t ctx)
                        case EXT2_ET_NO_INLINE_DATA:
                        case EXT2_ET_EXT_ATTR_CSUM_INVALID:
                        case EXT2_ET_EA_BAD_VALUE_OFFSET:
+                       case EXT2_ET_EA_INODE_CORRUPTED:
                                /* broken EA or no system.data EA; truncate */
                                if (fix_problem(ctx, PR_1_INLINE_DATA_NO_ATTR,
                                                &pctx)) {
@@ -2261,6 +2261,10 @@ static _INLINE_ void mark_block_used(e2fsck_t ctx, blk64_t block)
        clear_problem_context(&pctx);
 
        if (ext2fs_fast_test_block_bitmap2(ctx->block_found_map, block)) {
+               if (ext2fs_has_feature_shared_blocks(ctx->fs->super) &&
+                   !(ctx->options & E2F_OPT_UNSHARE_BLOCKS)) {
+                       return;
+               }
                if (!ctx->block_dup_map) {
                        pctx.errcode = e2fsck_allocate_block_bitmap(ctx->fs,
                                        _("multiply claimed block map"),
@@ -3444,10 +3448,15 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
 
                size = EXT2_I_SIZE(inode);
                if ((pb.last_init_lblock >= 0) &&
-                   /* allow allocated blocks to end of PAGE_SIZE */
+                   /* if size is smaller than expected by the block count,
+                    * allow allocated blocks to end of PAGE_SIZE.
+                    * last_init_lblock is the last in-use block, so it is
+                    * the minimum expected file size, but +1 because it is
+                    * the base-zero block number and not the block count. */
                    (size < (__u64)pb.last_init_lblock * fs->blocksize) &&
-                   (pb.last_init_lblock / blkpg * blkpg != pb.last_init_lblock ||
-                    size < (__u64)(pb.last_init_lblock & ~(blkpg-1)) *
+                   ((pb.last_init_lblock + 1) / blkpg * blkpg !=
+                    (pb.last_init_lblock + 1) ||
+                    size < (__u64)(pb.last_init_lblock & ~(blkpg - 1)) *
                     fs->blocksize))
                        bad_size = 3;
                else if (!(extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) &&