}
#undef NEXT_DIRENT
+static errcode_t fix_inline_dir_size(e2fsck_t ctx, ext2_ino_t ino,
+ size_t *inline_data_size,
+ struct problem_context *pctx,
+ char *buf)
+{
+ ext2_filsys fs = ctx->fs;
+ struct ext2_inode inode;
+ size_t new_size, old_size;
+ errcode_t retval;
+
+ old_size = *inline_data_size;
+ new_size = old_size + (4 - (old_size & 3));
+ memset(buf + old_size, 0, new_size - old_size);
+ retval = ext2fs_inline_data_set(fs, ino, 0, buf, new_size);
+ if (retval == EXT2_ET_INLINE_DATA_NO_SPACE) {
+ new_size -= 4;
+ retval = ext2fs_inline_data_set(fs, ino, 0, buf, new_size);
+ if (retval) {
+ if (fix_problem(ctx, PR_2_FIX_INLINE_DIR_FAILED,
+ pctx)) {
+ new_size = 0;
+ goto write_inode;
+ }
+ goto err;
+ }
+ } else if (retval) {
+ if (fix_problem(ctx, PR_2_FIX_INLINE_DIR_FAILED,
+ pctx)) {
+ new_size = 0;
+ goto write_inode;
+ }
+ goto err;
+ }
+
+write_inode:
+ retval = ext2fs_read_inode(fs, ino, &inode);
+ if (retval)
+ goto err;
+
+ retval = ext2fs_inode_size_set(fs, &inode, new_size);
+ if (retval)
+ goto err;
+ if (new_size == 0)
+ inode.i_flags &= ~EXT4_INLINE_DATA_FL;
+ retval = ext2fs_write_inode(fs, ino, &inode);
+ if (retval)
+ goto err;
+ *inline_data_size = new_size;
+
+err:
+ return retval;
+}
+
static int check_dir_block(ext2_filsys fs,
struct ext2_db_entry2 *db,
void *priv_data)
cd->pctx.errcode = ext2fs_read_dir_block4(fs, block_nr,
buf, 0, ino);
inline_read_fail:
+ pctx.ino = ino;
+ pctx.num = inline_data_size;
+ if ((inline_data_size & 3) &&
+ fix_problem(ctx, PR_2_BAD_INLINE_DIR_SIZE, &pctx)) {
+ errcode_t err = fix_inline_dir_size(ctx, ino,
+ &inline_data_size, &pctx,
+ buf);
+ if (err)
+ return DIRENT_ABORT;
+
+ }
ehandler_operation(0);
if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
cd->pctx.errcode = 0; /* We'll handle this ourselves */
N_("@d @i %i, %B, offset %N: @d passes checks but fails checksum.\n"),
PROMPT_FIX, PR_PREEN_OK },
+ /* inline directory inode size must be a multiple of 4 */
+ { PR_2_BAD_INLINE_DIR_SIZE,
+ N_("Inline @d @i %i size (%N) must be a multiple of 4.\n"),
+ PROMPT_FIX, 0 },
+
+ /* fixing size of inline directory inode failed */
+ { PR_2_FIX_INLINE_DIR_FAILED,
+ N_("Fixing size of inline @d @i %i failed.\n"),
+ PROMPT_TRUNCATE, 0 },
+
/* Pass 3 errors */
/* Pass 3: Checking directory connectivity */