return;
break;
case 's':
- superblock = parse_ulong(optarg, argv[0],
- "superblock number", &err);
+ err = strtoblk(argv[0], optarg, &superblock);
if (err)
return;
break;
struct ext2_super_block param;
errcode_t retval;
int err;
+ blk64_t blocks;
if (common_args_process(argc, argv, 3, 3, "initialize",
- "<device> <blocksize>", CHECK_FS_NOTOPEN))
+ "<device> <blocks>", CHECK_FS_NOTOPEN))
return;
memset(¶m, 0, sizeof(struct ext2_super_block));
- ext2fs_blocks_count_set(¶m, parse_ulong(argv[2], argv[0],
- "blocks count", &err));
+ err = strtoblk(argv[0], argv[2], &blocks);
+ if (err)
+ return;
+ ext2fs_blocks_count_set(¶m, blocks);
if (err)
return;
retval = ext2fs_initialize(argv[1], 0, ¶m,
return;
}
- gdt_csum = EXT2_HAS_RO_COMPAT_FEATURE(current_fs->super,
- EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
+ gdt_csum = ext2fs_has_group_desc_csum(current_fs);
for (i = 0; i < current_fs->group_desc_count; i++) {
fprintf(out, " Group %2d: block bitmap at %llu, "
"inode bitmap at %llu, "
if (EXT2_INODE_SIZE(current_fs->super) > EXT2_GOOD_OLD_INODE_SIZE)
internal_dump_inode_extra(out, prefix, inode_num,
(struct ext2_inode_large *) inode);
+ if (current_fs->super->s_creator_os == EXT2_OS_LINUX &&
+ current_fs->super->s_feature_ro_compat &
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) {
+ __u32 crc = inode->i_checksum_lo;
+ if (is_large_inode &&
+ large_inode->i_extra_isize >=
+ (offsetof(struct ext2_inode_large,
+ i_checksum_hi) -
+ EXT2_GOOD_OLD_INODE_SIZE))
+ crc |= ((__u32)large_inode->i_checksum_hi) << 16;
+ fprintf(out, "Inode checksum: 0x%08x\n", crc);
+ }
+
if (LINUX_S_ISLNK(inode->i_mode) && ext2fs_inode_data_blocks(current_fs,inode) == 0)
fprintf(out, "%sFast_link_dest: %.*s\n", prefix,
(int) inode->i_size, (char *)inode->i_block);
if (retval)
return retval;
- if (!(buf = (char *) malloc(bufsize))){
- com_err("copy_file", errno, "can't allocate buffer\n");
- return;
+ retval = ext2fs_get_mem(bufsize, &buf);
+ if (retval) {
+ com_err("copy_file", retval, "can't allocate buffer\n");
+ return retval;
}
/* This is used for checking whether the whole block is zero */
retval = ext2fs_get_memzero(bufsize, &zero_buf);
if (retval) {
com_err("copy_file", retval, "can't allocate buffer\n");
- free(buf);
+ ext2fs_free_mem(&buf);
return retval;
}
ptr += written;
}
}
- free(buf);
+ ext2fs_free_mem(&buf);
ext2fs_free_mem(&zero_buf);
retval = ext2fs_file_close(e2_file);
return retval;
fail:
- free(buf);
+ ext2fs_free_mem(&buf);
ext2fs_free_mem(&zero_buf);
(void) ext2fs_file_close(e2_file);
return retval;
if (dirent->inode == 0)
return 0;
- if (((dirent->name_len&0xFF) == 1) && (dirent->name[0] == '.'))
+ if ((ext2fs_dirent_name_len(dirent) == 1) && (dirent->name[0] == '.'))
return 0;
- if (((dirent->name_len&0xFF) == 2) && (dirent->name[0] == '.') &&
+ if ((ext2fs_dirent_name_len(dirent) == 2) && (dirent->name[0] == '.') &&
(dirent->name[1] == '.')) {
rds->parent = dirent->inode;
return 0;
ino = string_to_inode(argv[1]);
if (!ino)
return;
- blk = parse_ulong(argv[2], argv[0], "logical_block", &err);
+ err = strtoblk(argv[0], argv[2], &blk);
+ if (err)
+ return;
errcode = ext2fs_bmap2(current_fs, ino, 0, 0, 0, blk, 0, &pblk);
if (errcode) {
- com_err("argv[0]", errcode,
+ com_err(argv[0], errcode,
"while mapping logical block %llu\n", blk);
return;
}
ino = string_to_inode(argv[1]);
if (!ino)
return;
- start = parse_ulong(argv[2], argv[0], "logical_block", &err);
- if (argc == 4)
- end = parse_ulong(argv[3], argv[0], "logical_block", &err);
- else
+ err = strtoblk(argv[0], argv[2], &start);
+ if (err)
+ return;
+ if (argc == 4) {
+ err = strtoblk(argv[0], argv[3], &end);
+ if (err)
+ return;
+ } else
end = ~0;
errcode = ext2fs_punch(current_fs, ino, 0, 0, start, end);
void do_dump_mmp(int argc EXT2FS_ATTR((unused)), char *argv[])
{
+#if CONFIG_MMP
struct ext2_super_block *sb;
struct mmp_struct *mmp_s;
time_t t;
fprintf(stdout, "node_name: %s\n", mmp_s->mmp_nodename);
fprintf(stdout, "device_name: %s\n", mmp_s->mmp_bdevname);
fprintf(stdout, "magic: 0x%x\n", mmp_s->mmp_magic);
+ fprintf(stdout, "checksum: 0x%08x\n", mmp_s->mmp_checksum);
+#else
+ fprintf(stdout, "MMP is unsupported, please recompile with "
+ "--enable-mmp\n");
+#endif
}
static int source_file(const char *cmd_file, int ss_idx)
int catastrophic = 0;
char *data_filename = 0;
#ifdef READ_ONLY
- const char *opt_string = "icR:f:b:s:Vd:D";
+ const char *opt_string = "nicR:f:b:s:Vd:D";
#else
- const char *opt_string = "iwcR:f:b:s:Vd:D";
+ const char *opt_string = "niwcR:f:b:s:Vd:D";
#endif
if (debug_prog_name == 0)
case 'i':
open_flags |= EXT2_FLAG_IMAGE_FILE;
break;
+ case 'n':
+ open_flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+ break;
#ifndef READ_ONLY
case 'w':
open_flags |= EXT2_FLAG_RW;
"block size", 0);
break;
case 's':
- superblock = parse_ulong(optarg, argv[0],
- "superblock number", 0);
+ retval = strtoblk(argv[0], optarg, &superblock);
+ if (retval) {
+ com_err(argv[0], retval, 0, debug_prog_name);
+ return 1;
+ }
break;
case 'c':
catastrophic = 1;
if (preserve)
fix_perms("dump_file", &inode, fd, outname);
- else if (fd != 1)
- close(fd);
return;
}
}
dump_file(argv[0], inode, fd, preserve, out_fn);
+ if (close(fd) != 0) {
+ com_err(argv[0], errno, "while closing %s for dump_inode",
+ out_fn);
+ return;
+ }
return;
}
goto errout;
}
dump_file("rdump", ino, fd, 1, fullname);
+ if (close(fd) != 0) {
+ com_err("rdump", errno, "while dumping %s", fullname);
+ goto errout;
+ }
}
else if (LINUX_S_ISDIR(inode->i_mode) && strcmp(name, ".") && strcmp(name, "..")) {
errcode_t retval;
const char *dumproot = private;
struct ext2_inode inode;
- thislen = dirent->name_len & 0xFF;
+ thislen = ext2fs_dirent_name_len(dirent);
strncpy(name, dirent->name, thislen);
name[thislen] = 0;
{ "grp_quota_inum", &set_sb.s_grp_quota_inum, NULL, 4, parse_uint },
{ "overhead_blocks", &set_sb.s_overhead_blocks, NULL, 4, parse_uint },
{ "checksum", &set_sb.s_checksum, NULL, 4, parse_uint },
+ { "checksum_type", &set_sb.s_checksum_type, NULL, 1, parse_uint },
{ 0, 0, 0, 0 }
};
{ "bdevname", &set_mmp.mmp_bdevname, NULL, sizeof(set_mmp.mmp_bdevname),
parse_string },
{ "check_interval", &set_mmp.mmp_check_interval, NULL, 2, parse_uint },
+ { "checksum", &set_mmp.mmp_checksum, NULL, 4, parse_uint },
};
static int check_suffix(const char *field)
void do_set_mmp_value(int argc, char *argv[])
{
+#ifdef CONFIG_MMP
const char *usage = "<field> <value>\n"
"\t\"set_mmp_value -l\" will list the names of "
"MMP fields\n\twhich can be set.";
if (retval) {
com_err(argv[0], retval, "reading MMP block %llu.\n",
(long long)current_fs->super->s_mmp_block);
- ext2fs_free_mem(mmp_s);
+ ext2fs_free_mem(&mmp_s);
return;
}
current_fs->mmp_buf = mmp_s;
&set_mmp);
*mmp_s = set_mmp;
}
+#else
+ fprintf(stdout, "MMP is unsupported, please recompile with "
+ "--enable-mmp\n");
+#endif
}
*/
#undef USE_INODE_IO
+/* Checksumming functions */
+static int e2fsck_journal_verify_csum_type(journal_t *j,
+ journal_superblock_t *jsb)
+{
+ if (!JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V2))
+ return 1;
+
+ return jsb->s_checksum_type == JBD2_CRC32C_CHKSUM;
+}
+
+static __u32 e2fsck_journal_sb_csum(journal_superblock_t *jsb)
+{
+ __u32 crc, old_crc;
+
+ old_crc = jsb->s_checksum;
+ jsb->s_checksum = 0;
+ crc = ext2fs_crc32c_le(~0, (unsigned char *)jsb,
+ sizeof(journal_superblock_t));
+ jsb->s_checksum = old_crc;
+
+ return crc;
+}
+
+static int e2fsck_journal_sb_csum_verify(journal_t *j,
+ journal_superblock_t *jsb)
+{
+ __u32 provided, calculated;
+
+ if (!JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V2))
+ return 1;
+
+ provided = ext2fs_be32_to_cpu(jsb->s_checksum);
+ calculated = e2fsck_journal_sb_csum(jsb);
+
+ return provided == calculated;
+}
+
+static errcode_t e2fsck_journal_sb_csum_set(journal_t *j,
+ journal_superblock_t *jsb)
+{
+ __u32 crc;
+
+ if (!JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V2))
+ return 0;
+
+ crc = e2fsck_journal_sb_csum(jsb);
+ jsb->s_checksum = ext2fs_cpu_to_be32(crc);
+ return 0;
+}
+
/* Kernel compatibility functions for handling the journal. These allow us
* to use the recovery.c file virtually unchanged from the kernel, so we
* don't have to do much to keep kernel and user recovery in sync.
if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES))
return EXT2_ET_RO_UNSUPP_FEATURE;
+ /* Checksum v1 and v2 are mutually exclusive features. */
+ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2) &&
+ JFS_HAS_COMPAT_FEATURE(journal, JFS_FEATURE_COMPAT_CHECKSUM))
+ return EXT2_ET_CORRUPT_SUPERBLOCK;
+
+ if (!e2fsck_journal_verify_csum_type(journal, jsb) ||
+ !e2fsck_journal_sb_csum_verify(journal, jsb))
+ return EXT2_ET_CORRUPT_SUPERBLOCK;
+
/* We have now checked whether we know enough about the journal
* format to be able to proceed safely, so any other checks that
* fail we should attempt to recover from. */
for (i = 0; i < 4; i ++)
new_seq ^= u.val[i];
jsb->s_sequence = htonl(new_seq);
+ e2fsck_journal_sb_csum_set(journal, jsb);
mark_buffer_dirty(journal->j_sb_buffer);
ll_rw_block(WRITE, 1, &journal->j_sb_buffer);
jsb->s_sequence = htonl(journal->j_transaction_sequence);
if (reset)
jsb->s_start = 0; /* this marks the journal as empty */
+ e2fsck_journal_sb_csum_set(journal, jsb);
mark_buffer_dirty(journal->j_sb_buffer);
}
brelse(journal->j_sb_buffer);
ctx->fs->super->s_state |= EXT2_ERROR_FS;
ext2fs_mark_super_dirty(ctx->fs);
journal->j_superblock->s_errno = 0;
+ e2fsck_journal_sb_csum_set(journal, journal->j_superblock);
mark_buffer_dirty(journal->j_sb_buffer);
}
if (!journal_name)
return 0;
- if (stat(journal_name, &st) < 0)
+ if (stat(journal_name, &st) < 0) {
+ free(journal_name);
return 0;
+ }
if (st.st_rdev != sb->s_journal_dev) {
clear_problem_context(&pctx);
/* read the first block */
ehandler_operation(_("reading directory block"));
- retval = ext2fs_read_dir_block3(ctx->fs, blk, buf, 0);
+ retval = ext2fs_read_dir_block4(ctx->fs, blk, buf, 0, pctx->ino);
ehandler_operation(0);
if (retval)
return;
retval = ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
if (retval)
return;
- if (((dirent->name_len & 0xFF) != 1) ||
+ if ((ext2fs_dirent_name_len(dirent) != 1) ||
(dirent->name[0] != '.') ||
(dirent->inode != pctx->ino) ||
(rec_len < 12) ||
retval = ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
if (retval)
return;
- if (((dirent->name_len & 0xFF) != 2) ||
+ if ((ext2fs_dirent_name_len(dirent) != 2) ||
(dirent->name[0] != '.') ||
(dirent->name[1] != '.') ||
(rec_len < 12) ||
*ret = 0;
}
+static errcode_t recheck_bad_inode_checksum(ext2_filsys fs, ext2_ino_t ino,
+ e2fsck_t ctx,
+ struct problem_context *pctx)
+{
+ errcode_t retval;
+ struct ext2_inode_large inode;
+
+ /*
+ * Reread inode. If we don't see checksum error, then this inode
+ * has been fixed elsewhere.
+ */
+ retval = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
+ sizeof(inode));
+ if (retval && retval != EXT2_ET_INODE_CSUM_INVALID)
+ return retval;
+ if (!retval)
+ return 0;
+
+ /*
+ * Checksum still doesn't match. That implies that the inode passes
+ * all the sanity checks, so maybe the checksum is simply corrupt.
+ * See if the user will go for fixing that.
+ */
+ if (!fix_problem(ctx, PR_1_INODE_ONLY_CSUM_INVALID, pctx))
+ return 0;
+
+ retval = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
+ sizeof(inode));
+ if (retval)
+ return retval;
+
+ return 0;
+}
+
void e2fsck_pass1(e2fsck_t ctx)
{
int i;
int imagic_fs, extent_fs;
int busted_fs_time = 0;
int inode_size;
+ int failed_csum = 0;
init_resource_track(&rtrack, ctx->fs->io);
clear_problem_context(&pctx);
}
block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3,
"block interate buffer");
- e2fsck_use_inode_shortcuts(ctx, 1);
+ if (EXT2_INODE_SIZE(fs->super) == EXT2_GOOD_OLD_INODE_SIZE)
+ e2fsck_use_inode_shortcuts(ctx, 1);
old_op = ehandler_operation(_("opening inode scan"));
pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
&scan);
ext2fs_mark_block_bitmap2(ctx->block_found_map,
fs->super->s_mmp_block);
+ /* Set up ctx->lost_and_found if possible */
+ (void) e2fsck_get_lost_and_found(ctx, 0);
+
while (1) {
if (ino % (fs->super->s_inodes_per_group * 4) == 1) {
if (e2fsck_mmp_update(fs))
ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino);
continue;
}
- if (pctx.errcode) {
+ if (pctx.errcode &&
+ pctx.errcode != EXT2_ET_INODE_CSUM_INVALID) {
fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
ctx->flags |= E2F_FLAG_ABORT;
return;
pctx.ino = ino;
pctx.inode = inode;
ctx->stashed_ino = ino;
+
+ /* Clear corrupt inode? */
+ if (pctx.errcode == EXT2_ET_INODE_CSUM_INVALID) {
+ if (fix_problem(ctx, PR_1_INODE_CSUM_INVALID, &pctx))
+ goto clear_inode;
+ failed_csum = 1;
+ }
+
if (inode->i_links_count) {
pctx.errcode = ext2fs_icount_store(ctx->inode_link_info,
ino, inode->i_links_count);
} else
check_blocks(ctx, &pctx, block_buf);
+ /*
+ * If the inode failed the checksum and the user didn't
+ * clear the inode, test the checksum again -- if it still
+ * fails, ask the user if the checksum should be corrected.
+ */
+ if (failed_csum) {
+ pctx.errcode = recheck_bad_inode_checksum(fs, ino, ctx,
+ &pctx);
+ if (pctx.errcode) {
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ }
+
if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
return;
ext2fs_free_mem(&block_buf);
ext2fs_free_mem(&inode);
+ /*
+ * The l+f inode may have been cleared, so zap it now and
+ * later passes will recalculate it if necessary
+ */
+ ctx->lost_and_found = 0;
+
print_resource_track(ctx, _("Pass 1"), &rtrack, ctx->fs->io);
}
if ((blk = ea_refcount_intr_next(refcount, &count)) == 0)
break;
pctx.blk = blk;
- pctx.errcode = ext2fs_read_ext_attr2(fs, blk, block_buf);
+ pctx.errcode = ext2fs_read_ext_attr3(fs, blk, block_buf,
+ pctx.ino);
if (pctx.errcode) {
fix_problem(ctx, PR_1_EXTATTR_READ_ABORT, &pctx);
return;
pctx.num = should_be;
if (fix_problem(ctx, PR_1_EXTATTR_REFCOUNT, &pctx)) {
header->h_refcount = should_be;
- pctx.errcode = ext2fs_write_ext_attr2(fs, blk,
- block_buf);
+ pctx.errcode = ext2fs_write_ext_attr3(fs, blk,
+ block_buf,
+ pctx.ino);
if (pctx.errcode) {
fix_problem(ctx, PR_1_EXTATTR_WRITE_ABORT,
&pctx);
struct ext2_ext_attr_entry *entry;
int count;
region_t region = 0;
+ int failed_csum = 0;
blk = ext2fs_file_acl_block(fs, inode);
if (blk == 0)
* validate it
*/
pctx->blk = blk;
- pctx->errcode = ext2fs_read_ext_attr2(fs, blk, block_buf);
+ pctx->errcode = ext2fs_read_ext_attr3(fs, blk, block_buf, pctx->ino);
+ if (pctx->errcode == EXT2_ET_EXT_ATTR_CSUM_INVALID) {
+ if (fix_problem(ctx, PR_1_EA_BLOCK_CSUM_INVALID, pctx))
+ goto clear_extattr;
+ failed_csum = 1;
+ }
if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx))
goto clear_extattr;
header = (struct ext2_ext_attr_header *) block_buf;
}
region_free(region);
+ /*
+ * We only get here if there was no other errors that were fixed.
+ * If there was a checksum fail, ask to correct it.
+ */
+ if (failed_csum &&
+ fix_problem(ctx, PR_1_EA_BLOCK_ONLY_CSUM_INVALID, pctx)) {
+ pctx->errcode = ext2fs_write_ext_attr3(fs, blk, block_buf,
+ pctx->ino);
+ if (pctx->errcode)
+ return 0;
+ }
+
count = header->h_refcount - 1;
if (count)
ea_refcount_store(ctx->refcount, blk, count);
int is_dir, is_leaf;
problem_t problem;
struct ext2_extent_info info;
+ int failed_csum;
pctx->errcode = ext2fs_extent_get_info(ehandle, &info);
if (pctx->errcode)
pctx->errcode = ext2fs_extent_get(ehandle, EXT2_EXTENT_FIRST_SIB,
&extent);
- while (!pctx->errcode && info.num_entries-- > 0) {
+ while ((pctx->errcode == 0 ||
+ pctx->errcode == EXT2_ET_EXTENT_CSUM_INVALID) &&
+ info.num_entries-- > 0) {
+ failed_csum = 0;
is_leaf = extent.e_flags & EXT2_EXTENT_FLAGS_LEAF;
is_dir = LINUX_S_ISDIR(pctx->inode->i_mode);
last_lblk = extent.e_lblk + extent.e_len - 1;
problem = 0;
+ /* Ask to clear a corrupt extent block */
+ if (pctx->errcode == EXT2_ET_EXTENT_CSUM_INVALID) {
+ pctx->blk = extent.e_pblk;
+ pctx->blk2 = extent.e_lblk;
+ pctx->num = extent.e_len;
+ problem = PR_1_EXTENT_CSUM_INVALID;
+ if (fix_problem(ctx, problem, pctx))
+ goto fix_problem_now;
+ failed_csum = 1;
+ }
+
if (extent.e_pblk == 0 ||
extent.e_pblk < ctx->fs->super->s_first_data_block ||
extent.e_pblk >= ext2fs_blocks_count(ctx->fs->super))
(1 << (21 - ctx->fs->super->s_log_block_size))))
problem = PR_1_TOOBIG_DIR;
+ /* Corrupt but passes checks? Ask to fix checksum. */
+ if (failed_csum) {
+ pctx->blk = extent.e_pblk;
+ pctx->blk2 = extent.e_lblk;
+ pctx->num = extent.e_len;
+ problem = 0;
+ if (fix_problem(ctx, PR_1_EXTENT_ONLY_CSUM_INVALID,
+ pctx))
+ ext2fs_extent_replace(ehandle, 0, &extent);
+ }
+
if (problem) {
report_problem:
pctx->blk = extent.e_pblk;
pctx->num = extent.e_len;
pctx->blkcount = extent.e_lblk + extent.e_len;
if (fix_problem(ctx, problem, pctx)) {
+fix_problem_now:
e2fsck_read_bitmaps(ctx);
pctx->errcode =
ext2fs_extent_delete(ehandle, 0);
if (pctx->errcode) {
pctx->str = "EXT2_EXTENT_DOWN";
problem = PR_1_EXTENT_HEADER_INVALID;
- if (pctx->errcode == EXT2_ET_EXTENT_HEADER_BAD)
+ if (pctx->errcode ==
+ EXT2_ET_EXTENT_HEADER_BAD ||
+ pctx->errcode ==
+ EXT2_ET_EXTENT_CSUM_INVALID)
goto report_problem;
return;
}
}
pctx->num = 0;
}
- if (LINUX_S_ISREG(inode->i_mode) && EXT2_I_SIZE(inode) >= 0x80000000UL)
+ if (LINUX_S_ISREG(inode->i_mode) &&
+ ext2fs_needs_large_file_feature(EXT2_I_SIZE(inode)))
ctx->large_files++;
if ((pb.num_blocks != ext2fs_inode_i_blocks(fs, inode)) ||
((fs->super->s_feature_ro_compat &
}
if (ctx->dirs_to_hash && pb.is_dir &&
+ !(ctx->lost_and_found && ctx->lost_and_found == ino) &&
!(inode->i_flags & EXT2_INDEX_FL) &&
((inode->i_size / fs->blocksize) >= 3))
- ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
+ e2fsck_rehash_dir_later(ctx, ino);
out:
if (dirty_inode)
int a_len, b_len;
de_a = (const struct ext2_dir_entry *) a;
- a_len = de_a->name_len & 0xFF;
+ a_len = ext2fs_dirent_name_len(de_a);
de_b = (const struct ext2_dir_entry *) b;
- b_len = de_b->name_len & 0xFF;
+ b_len = ext2fs_dirent_name_len(de_b);
if (a_len != b_len)
return (a_len - b_len);
if (!dirent->inode)
problem = PR_2_MISSING_DOT;
- else if (((dirent->name_len & 0xFF) != 1) ||
+ else if ((ext2fs_dirent_name_len(dirent) != 1) ||
(dirent->name[0] != '.'))
problem = PR_2_1ST_NOT_DOT;
else if (dirent->name[1] != '\0')
if (rec_len < 12)
rec_len = dirent->rec_len = 12;
dirent->inode = ino;
- dirent->name_len = 1;
+ ext2fs_dirent_set_name_len(dirent, 1);
+ ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
dirent->name[0] = '.';
dirent->name[1] = '\0';
status = 1;
(void) ext2fs_set_rec_len(ctx->fs, new_len,
nextdir);
nextdir->inode = 0;
- nextdir->name_len = 0;
+ ext2fs_dirent_set_name_len(nextdir, 0);
+ ext2fs_dirent_set_file_type(nextdir,
+ EXT2_FT_UNKNOWN);
status = 1;
}
}
if (!dirent->inode)
problem = PR_2_MISSING_DOT_DOT;
- else if (((dirent->name_len & 0xFF) != 2) ||
+ else if ((ext2fs_dirent_name_len(dirent) != 2) ||
(dirent->name[0] != '.') ||
(dirent->name[1] != '.'))
problem = PR_2_2ND_NOT_DOT_DOT;
* inode. This will get fixed in pass 3.
*/
dirent->inode = EXT2_ROOT_INO;
- dirent->name_len = 2;
+ ext2fs_dirent_set_name_len(dirent, 2);
+ ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
dirent->name[0] = '.';
dirent->name[1] = '.';
dirent->name[2] = '\0';
int fixup = -1;
int ret = 0;
- for ( i = 0; i < (dirent->name_len & 0xFF); i++) {
+ for ( i = 0; i < ext2fs_dirent_name_len(dirent); i++) {
if (dirent->name[i] == '/' || dirent->name[i] == '\0') {
if (fixup < 0) {
fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx);
ext2_ino_t dir_ino EXT2FS_ATTR((unused)),
struct problem_context *pctx)
{
- int filetype = dirent->name_len >> 8;
+ int filetype = ext2fs_dirent_file_type(dirent);
int should_be = EXT2_FT_UNKNOWN;
struct ext2_inode inode;
if (filetype == 0 ||
!fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx))
return 0;
- dirent->name_len = dirent->name_len & 0xFF;
+ ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
return 1;
}
pctx) == 0)
return 0;
- dirent->name_len = (dirent->name_len & 0xFF) | should_be << 8;
+ ext2fs_dirent_set_file_type(dirent, should_be);
return 1;
}
struct ext2_db_entry2 *db,
struct check_dir_struct *cd,
struct dx_dir_info *dx_dir,
- char *block_buf)
+ char *block_buf, int failed_csum)
{
struct ext2_dx_root_info *root;
struct ext2_dx_entry *ent;
ext2_dirhash_t min_hash = 0xffffffff;
ext2_dirhash_t max_hash = 0;
ext2_dirhash_t hash = 0, prev_hash;
+ int csum_size = 0;
if (db->blockcnt == 0) {
root = (struct ext2_dx_root_info *) (block_buf + 24);
#endif
ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
+
+ if (failed_csum &&
+ (e2fsck_dir_will_be_rehashed(cd->ctx, cd->pctx.ino) ||
+ fix_problem(cd->ctx, PR_2_HTREE_ROOT_CSUM_INVALID,
+ &cd->pctx)))
+ goto clear_and_exit;
} else {
ent = (struct ext2_dx_entry *) (block_buf+8);
+
+ if (failed_csum &&
+ (e2fsck_dir_will_be_rehashed(cd->ctx, cd->pctx.ino) ||
+ fix_problem(cd->ctx, PR_2_HTREE_NODE_CSUM_INVALID,
+ &cd->pctx)))
+ goto clear_and_exit;
}
+
limit = (struct ext2_dx_countlimit *) ent;
#ifdef DX_DEBUG
#endif
count = ext2fs_le16_to_cpu(limit->count);
- expect_limit = (fs->blocksize - ((char *) ent - block_buf)) /
- sizeof(struct ext2_dx_entry);
+ if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ csum_size = sizeof(struct ext2_dx_tail);
+ expect_limit = (fs->blocksize -
+ (csum_size + ((char *) ent - block_buf))) /
+ sizeof(struct ext2_dx_entry);
if (ext2fs_le16_to_cpu(limit->limit) != expect_limit) {
cd->pctx.num = ext2fs_le16_to_cpu(limit->limit);
if (fix_problem(cd->ctx, PR_2_HTREE_BAD_LIMIT, &cd->pctx))
clear_and_exit:
clear_htree(cd->ctx, cd->pctx.ino);
dx_dir->numblocks = 0;
+ e2fsck_rehash_dir_later(cd->ctx, cd->pctx.ino);
}
#endif /* ENABLE_HTREE */
char *cp = (char *) dirent;
int left;
unsigned int rec_len, prev_rec_len;
- unsigned int name_len = dirent->name_len & 0xFF;
+ unsigned int name_len = ext2fs_dirent_name_len(dirent);
(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
left = fs->blocksize - *offset - rec_len;
} else {
rec_len = fs->blocksize - *offset;
(void) ext2fs_set_rec_len(fs, rec_len, dirent);
- dirent->name_len = 0;
+ ext2fs_dirent_set_name_len(dirent, 0);
+ ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
dirent->inode = 0;
}
}
struct problem_context pctx;
int dups_found = 0;
int ret;
+ int dx_csum_size = 0, de_csum_size = 0;
+ int failed_csum = 0;
+ int is_leaf = 1;
cd = (struct check_dir_struct *) priv_data;
buf = cd->buf;
if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
return DIRENT_ABORT;
+ if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+ dx_csum_size = sizeof(struct ext2_dx_tail);
+ de_csum_size = sizeof(struct ext2_dir_entry_tail);
+ }
+
/*
* Make sure the inode is still in use (could have been
* deleted in the duplicate/bad blocks pass.
#endif
ehandler_operation(_("reading directory block"));
- cd->pctx.errcode = ext2fs_read_dir_block3(fs, block_nr, buf, 0);
+ cd->pctx.errcode = ext2fs_read_dir_block4(fs, block_nr, buf, 0, ino);
ehandler_operation(0);
if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
cd->pctx.errcode = 0; /* We'll handle this ourselves */
+ else if (cd->pctx.errcode == EXT2_ET_DIR_CSUM_INVALID) {
+ cd->pctx.errcode = 0; /* We'll handle this ourselves */
+ failed_csum = 1;
+ }
if (cd->pctx.errcode) {
+ char *buf2;
if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
ctx->flags |= E2F_FLAG_ABORT;
return DIRENT_ABORT;
}
- memset(buf, 0, fs->blocksize);
+ ext2fs_new_dir_block(fs, db->blockcnt == 0 ? ino : 0,
+ EXT2_ROOT_INO, &buf2);
+ memcpy(buf, buf2, fs->blocksize);
+ ext2fs_free_mem(&buf2);
}
#ifdef ENABLE_HTREE
dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
dx_dir->depth = root->indirect_levels + 1;
} else if ((dirent->inode == 0) &&
(rec_len == fs->blocksize) &&
- (dirent->name_len == 0) &&
+ (ext2fs_dirent_name_len(dirent) == 0) &&
(ext2fs_le16_to_cpu(limit->limit) ==
- ((fs->blocksize-8) /
+ ((fs->blocksize - (8 + dx_csum_size)) /
sizeof(struct ext2_dx_entry))))
dx_db->type = DX_DIRBLOCK_NODE;
+ is_leaf = 0;
}
out_htree:
#endif /* ENABLE_HTREE */
+ /* Verify checksum. */
+ if (is_leaf && de_csum_size) {
+ /* No space for csum? Rebuild dirs in pass 3A. */
+ if (!ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf)) {
+ de_csum_size = 0;
+ if (e2fsck_dir_will_be_rehashed(ctx, ino))
+ goto skip_checksum;
+ if (!fix_problem(cd->ctx, PR_2_LEAF_NODE_MISSING_CSUM,
+ &cd->pctx))
+ goto skip_checksum;
+ e2fsck_rehash_dir_later(ctx, ino);
+ goto skip_checksum;
+ }
+ if (failed_csum) {
+ char *buf2;
+ if (!fix_problem(cd->ctx, PR_2_LEAF_NODE_CSUM_INVALID,
+ &cd->pctx))
+ goto skip_checksum;
+ ext2fs_new_dir_block(fs,
+ db->blockcnt == 0 ? ino : 0,
+ EXT2_ROOT_INO, &buf2);
+ memcpy(buf, buf2, fs->blocksize);
+ ext2fs_free_mem(&buf2);
+ dir_modified++;
+ failed_csum = 0;
+ }
+ }
+ /* htree nodes don't use fake dirents to store checksums */
+ if (!is_leaf)
+ de_csum_size = 0;
+
+skip_checksum:
dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
prev = 0;
do {
dgrp_t group;
ext2_ino_t first_unused_inode;
+ unsigned int name_len;
problem = 0;
dirent = (struct ext2_dir_entry *) (buf + offset);
if (((offset + rec_len) > fs->blocksize) ||
(rec_len < 12) ||
((rec_len % 4) != 0) ||
- (((dirent->name_len & (unsigned) 0xFF)+8) > rec_len)) {
+ ((ext2fs_dirent_name_len(dirent) + 8) > rec_len)) {
if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
salvage_directory(fs, dirent, prev, &offset);
dir_modified++;
/*
* Make sure the inode listed is a legal one.
*/
+ name_len = ext2fs_dirent_name_len(dirent);
if (((dirent->inode != EXT2_ROOT_INO) &&
(dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
(dirent->inode > fs->super->s_inodes_count)) {
* clear it.
*/
problem = PR_2_BB_INODE;
- } else if ((dot_state > 1) &&
- ((dirent->name_len & 0xFF) == 1) &&
+ } else if ((dot_state > 1) && (name_len == 1) &&
(dirent->name[0] == '.')) {
/*
* If there's a '.' entry in anything other
* duplicate entry that should be removed.
*/
problem = PR_2_DUP_DOT;
- } else if ((dot_state > 1) &&
- ((dirent->name_len & 0xFF) == 2) &&
+ } else if ((dot_state > 1) && (name_len == 2) &&
(dirent->name[0] == '.') &&
(dirent->name[1] == '.')) {
/*
* directory hasn't been created yet.
*/
problem = PR_2_LINK_ROOT;
- } else if ((dot_state > 1) &&
- (dirent->name_len & 0xFF) == 0) {
+ } else if ((dot_state > 1) && (name_len == 0)) {
/*
* Don't allow zero-length directory names.
*/
#ifdef ENABLE_HTREE
if (dx_db) {
ext2fs_dirhash(dx_dir->hashversion, dirent->name,
- (dirent->name_len & 0xFF),
+ ext2fs_dirent_name_len(dirent),
fs->super->s_hash_seed, &hash, 0);
if (hash < dx_db->min_hash)
dx_db->min_hash = hash;
pctx.ino = ino;
pctx.dirent = dirent;
fix_problem(ctx, PR_2_REPORT_DUP_DIRENT, &pctx);
- if (!ctx->dirs_to_hash)
- ext2fs_u32_list_create(&ctx->dirs_to_hash, 50);
- if (ctx->dirs_to_hash)
- ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
+ e2fsck_rehash_dir_later(ctx, ino);
dups_found++;
} else
dict_alloc_insert(&de_dict, dirent, dirent);
(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
offset += rec_len;
dot_state++;
- } while (offset < fs->blocksize);
+ } while (offset < fs->blocksize - de_csum_size);
#if 0
printf("\n");
#endif
cd->pctx.dir = cd->pctx.ino;
if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
(dx_db->type == DX_DIRBLOCK_NODE))
- parse_int_node(fs, db, cd, dx_dir, buf);
+ parse_int_node(fs, db, cd, dx_dir, buf, failed_csum);
}
#endif /* ENABLE_HTREE */
- if (offset != fs->blocksize) {
- cd->pctx.num = rec_len - fs->blocksize + offset;
+
+ if (offset != fs->blocksize - de_csum_size) {
+ cd->pctx.num = rec_len - (fs->blocksize - de_csum_size) +
+ offset;
if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
dirent->rec_len = cd->pctx.num;
dir_modified++;
}
}
if (dir_modified) {
- cd->pctx.errcode = ext2fs_write_dir_block3(fs, block_nr, buf, 0);
+ /* leaf block with no tail? Rehash dirs later. */
+ if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+ is_leaf &&
+ !ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf))
+ e2fsck_rehash_dir_later(ctx, ino);
+
+write_and_fix:
+ if (e2fsck_dir_will_be_rehashed(ctx, ino))
+ ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+ cd->pctx.errcode = ext2fs_write_dir_block4(fs, block_nr, buf,
+ 0, ino);
+ if (e2fsck_dir_will_be_rehashed(ctx, ino))
+ ctx->fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
if (cd->pctx.errcode) {
if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
&cd->pctx))
goto abort_free_dict;
}
ext2fs_mark_changed(fs);
+ } else if (is_leaf && failed_csum && !dir_modified) {
+ /*
+ * If a leaf node that fails csum makes it this far without
+ * alteration, ask the user if the checksum should be fixed.
+ */
+ if (fix_problem(ctx, PR_2_LEAF_NODE_ONLY_CSUM_INVALID,
+ &cd->pctx))
+ goto write_and_fix;
}
dict_free_nodes(&de_dict);
return 0;
if (ext2fs_file_acl_block(fs, &inode) &&
(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
- pctx.errcode = ext2fs_adjust_ea_refcount2(fs,
- ext2fs_file_acl_block(fs, &inode),
- block_buf, -1, &count);
+ pctx.errcode = ext2fs_adjust_ea_refcount3(fs,
+ ext2fs_file_acl_block(fs, &inode),
+ block_buf, -1, &count, ino);
if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
pctx.errcode = 0;
count = 1;
if (!ext2fs_inode_has_valid_blocks2(fs, &inode))
goto clear_inode;
- if (LINUX_S_ISREG(inode.i_mode) && EXT2_I_SIZE(&inode) >= 0x80000000UL)
+ if (LINUX_S_ISREG(inode.i_mode) &&
+ ext2fs_needs_large_file_feature(EXT2_I_SIZE(&inode)))
ctx->large_files--;
del_block.ctx = ctx;
return 1;
}
- pctx->errcode = ext2fs_write_dir_block3(fs, blk, block, 0);
+ pctx->errcode = ext2fs_write_dir_block4(fs, blk, block, 0, db->ino);
ext2fs_free_mem(&block);
if (pctx->errcode) {
pctx->str = "ext2fs_write_dir_block";
void e2fsck_pass3(e2fsck_t ctx)
{
ext2_filsys fs = ctx->fs;
- struct dir_info_iter *iter;
+ struct dir_info_iter *iter = NULL;
#ifdef RESOURCE_TRACK
struct resource_track rtrack;
#endif
if (check_directory(ctx, dir->ino, &pctx))
goto abort_exit;
}
- e2fsck_dir_info_iter_end(ctx, iter);
/*
* Force the creation of /lost+found if not present
e2fsck_rehash_directories(ctx);
abort_exit:
+ if (iter)
+ e2fsck_dir_info_iter_end(ctx, iter);
e2fsck_free_dir_info(ctx);
if (inode_loop_detect) {
ext2fs_free_inode_bitmap(inode_loop_detect);
return;
}
- pctx.errcode = ext2fs_write_dir_block3(fs, blk, block, 0);
+ pctx.errcode = ext2fs_write_dir_block4(fs, blk, block, 0,
+ EXT2_ROOT_INO);
if (pctx.errcode) {
- pctx.str = "ext2fs_write_dir_block3";
+ pctx.str = "ext2fs_write_dir_block4";
fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
ctx->flags |= E2F_FLAG_ABORT;
return;
if (retval && !fix)
return 0;
if (!retval) {
- if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, ino)) {
+ if (ext2fs_check_directory(fs, ino) == 0) {
ctx->lost_and_found = ino;
return ino;
}
return 0;
}
- retval = ext2fs_write_dir_block3(fs, blk, block, 0);
+ retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino);
ext2fs_free_mem(&block);
if (retval) {
pctx.errcode = retval;
errcode_t retval;
struct problem_context pctx;
- if ((dirent->name_len & 0xFF) != 2)
+ if (ext2fs_dirent_name_len(dirent) != 2)
return 0;
if (strncmp(dirent->name, "..", 2))
return 0;
dirent->inode = fp->parent;
if (fp->ctx->fs->super->s_feature_incompat &
EXT2_FEATURE_INCOMPAT_FILETYPE)
- dirent->name_len = (dirent->name_len & 0xFF) |
- (EXT2_FT_DIR << 8);
+ ext2fs_dirent_set_file_type(dirent, EXT2_FT_DIR);
else
- dirent->name_len = dirent->name_len & 0xFF;
+ ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
fp->done++;
return DIRENT_ABORT | DIRENT_CHANGED;
clear_problem_context(&pctx);
pctx.ino = ino;
+ if (e2fsck_dir_will_be_rehashed(ctx, ino))
+ ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
retval = ext2fs_dir_iterate(fs, ino, DIRENT_FLAG_INCLUDE_EMPTY,
0, fix_dotdot_proc, &fp);
+ if (e2fsck_dir_will_be_rehashed(ctx, ino))
+ ctx->fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
if (retval || !fp.done) {
pctx.errcode = retval;
fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR :
blk64_t last_block;
errcode_t err;
e2fsck_t ctx;
+ ext2_ino_t dir;
};
static int expand_dir_proc(ext2_filsys fs,
return BLOCK_ABORT;
}
es->num--;
- retval = ext2fs_write_dir_block3(fs, new_blk, block, 0);
+ retval = ext2fs_write_dir_block4(fs, new_blk, block, 0,
+ es->dir);
} else {
retval = ext2fs_get_mem(fs->blocksize, &block);
if (retval) {
return BLOCK_CHANGED;
}
+ /*
+ * Ensure that all blocks are marked in the block_found_map, since it's
+ * possible that the library allocated an extent node block or a block map
+ * block during the directory rebuilding; these new allocations are not
+ * captured in block_found_map. This is bad since we could later use
+ * block_found_map to allocate more blocks.
+ */
+ static int find_new_blocks_proc(ext2_filsys fs,
+ blk64_t *blocknr,
+ e2_blkcnt_t blockcnt,
+ blk64_t ref_block EXT2FS_ATTR((unused)),
+ int ref_offset EXT2FS_ATTR((unused)),
+ void *priv_data)
+ {
+ struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
+ e2fsck_t ctx = es->ctx;
+
+ ext2fs_mark_block_bitmap2(ctx->block_found_map, *blocknr);
+ return 0;
+ }
+
errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
int num, int guaranteed_size)
{
errcode_t retval;
struct expand_dir_struct es;
struct ext2_inode inode;
- blk64_t sz;
+ blk64_t sz, before, after;
if (!(fs->flags & EXT2_FLAG_RW))
return EXT2_ET_RO_FILSYS;
es.err = 0;
es.newblocks = 0;
es.ctx = ctx;
+ es.dir = dir;
+ before = ext2fs_free_blocks_count(fs->super);
retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
0, expand_dir_proc, &es);
if (es.err)
return es.err;
+ after = ext2fs_free_blocks_count(fs->super);
+
+ /*
+ * If the free block count has dropped by more than the blocks we
+ * allocated ourselves, then we must've allocated some extent/map
+ * blocks. Therefore, we must iterate this dir's blocks again to
+ * ensure that all newly allocated blocks are captured in
+ * block_found_map.
+ */
+ if ((before - after) > es.newblocks) {
+ retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_READ_ONLY,
+ 0, find_new_blocks_proc, &es);
+ if (es.err)
+ return es.err;
+ }
/*
* Update the size and block count fields in the inode.
N_("ext2fs_check_desc: %m\n"),
PROMPT_NONE, 0 },
+ /*
+ * metadata_csum implies uninit_bg; both feature bits cannot
+ * be set simultaneously.
+ */
+ { PR_0_META_AND_GDT_CSUM_SET,
+ N_("@S metadata_csum supersedes uninit_bg; both feature "
+ "bits cannot be set simultaneously."),
+ PROMPT_FIX, PR_PREEN_OK | PR_NO_OK},
+
+ /* Superblock has invalid MMP checksum. */
+ { PR_0_MMP_CSUM_INVALID,
+ N_("@S MMP block checksum does not match MMP block. "),
+ PROMPT_FIX, PR_PREEN_OK | PR_NO_OK},
+
/* 64bit is set but extents is unset. */
{ PR_0_64BIT_WITHOUT_EXTENTS,
N_("@S 64bit filesystems needs extents to access the whole disk. "),
N_("@i %i has zero length extent\n\t(@n logical @b %c, physical @b %b)\n"),
PROMPT_CLEAR, 0 },
+ /* inode checksum does not match inode */
+ { PR_1_INODE_CSUM_INVALID,
+ N_("@i %i checksum does not match @i. "),
+ PROMPT_CLEAR, PR_PREEN_OK },
+
+ /* inode passes checks, but checksum does not match inode */
+ { PR_1_INODE_ONLY_CSUM_INVALID,
+ N_("@i %i passes checks, but checksum does not match @i. "),
+ PROMPT_FIX, PR_PREEN_OK },
+
+ /* Inode extent block checksum does not match extent */
+ { PR_1_EXTENT_CSUM_INVALID,
+ N_("@i %i extent block checksum does not match extent\n\t(logical @b "
+ "%c, @n physical @b %b, len %N)\n"),
+ PROMPT_CLEAR, 0 },
+
+ /*
+ * Inode extent block passes checks, but checksum does not match
+ * extent
+ */
+ { PR_1_EXTENT_ONLY_CSUM_INVALID,
+ N_("@i %i extent block passes checks, but checksum does not match "
+ "extent\n\t(logical @b %c, @n physical @b %b, len %N)\n"),
+ PROMPT_FIX, 0 },
+
+ /* Extended attribute block checksum for inode does not match. */
+ { PR_1_EA_BLOCK_CSUM_INVALID,
+ N_("Extended attribute @a @b %b checksum for @i %i does not "
+ "match. "),
+ PROMPT_CLEAR, 0 },
+
+ /*
+ * Extended attribute block passes checks, but checksum for inode does
+ * not match.
+ */
+ { PR_1_EA_BLOCK_ONLY_CSUM_INVALID,
+ N_("Extended attribute @a @b %b passes checks, but checksum for "
+ "@i %i does not match. "),
+ PROMPT_FIX, 0 },
+
/*
* Interior extent node logical offset doesn't match first node below it
*/
N_("@n @i number for '.' in @d @i %i.\n"),
PROMPT_FIX, 0 },
- /* Directory entry has bad inode number */
+ /* Entry 'xxxx' in /a/b/c has bad inode number.*/
{ PR_2_BAD_INO,
N_("@E has @n @i #: %Di.\n"),
PROMPT_CLEAR, 0 },
- /* Directory entry has deleted or unused inode */
+ /* Entry 'xxxx' in /a/b/c has deleted/unused inode nnnnn.*/
{ PR_2_UNUSED_INODE,
N_("@E has @D/unused @i %Di. "),
PROMPT_CLEAR, PR_PREEN_OK },
N_("i_file_acl_hi @F %N, @s zero.\n"),
PROMPT_CLEAR, PR_PREEN_OK },
+ /* htree root node fails checksum */
+ { PR_2_HTREE_ROOT_CSUM_INVALID,
+ N_("@p @h %d: root node fails checksum\n"),
+ PROMPT_CLEAR_HTREE, PR_PREEN_OK },
+
+ /* htree internal node fails checksum */
+ { PR_2_HTREE_NODE_CSUM_INVALID,
+ N_("@p @h %d: internal node fails checksum\n"),
+ PROMPT_CLEAR_HTREE, PR_PREEN_OK },
+
+ /* leaf node fails checksum */
+ { PR_2_LEAF_NODE_CSUM_INVALID,
+ N_("@d @i %i, %B, offset %N: @d fails checksum\n"),
+ PROMPT_SALVAGE, PR_PREEN_OK },
+
+ /* leaf node has no checksum */
+ { PR_2_LEAF_NODE_MISSING_CSUM,
+ N_("@d @i %i, %B, offset %N: @d has no checksum\n"),
+ PROMPT_FIX, PR_PREEN_OK },
+
+ /* leaf node passes checks but fails checksum */
+ { PR_2_LEAF_NODE_ONLY_CSUM_INVALID,
+ N_("@d @i %i, %B, offset %N: @d passes checks but fails checksum\n"),
+ PROMPT_FIX, PR_PREEN_OK },
+
/* Pass 3 errors */
/* Pass 3: Checking directory connectivity */
N_("@g %g @i(s) in use but @g is marked INODE_UNINIT\n"),
PROMPT_FIX, PR_PREEN_OK },
+ /* Group N inode bitmap does not match checksum */
+ { PR_5_INODE_BITMAP_CSUM_INVALID,
+ N_("@g %g @i bitmap does not match checksum\n"),
+ PROMPT_FIX, PR_LATCH_IBITMAP | PR_PREEN_OK },
+
+ /* Group N block bitmap does not match checksum */
+ { PR_5_BLOCK_BITMAP_CSUM_INVALID,
+ N_("@g %g @b bitmap does not match checksum\n"),
+ PROMPT_FIX, PR_LATCH_BBITMAP | PR_PREEN_OK },
+
/* Post-Pass 5 errors */
/* Recreate journal if E2F_FLAG_JOURNAL_INODE flag is set */
case 'L':
replace_bad_blocks++;
case 'l':
+ if (bad_blocks_file)
+ free(bad_blocks_file);
bad_blocks_file = string_copy(ctx, optarg, 0);
break;
case 'd':
ext2fs_mmp_clear(fs);
retval = 0;
}
+ } else if (retval == EXT2_ET_MMP_CSUM_INVALID) {
+ if (fix_problem(ctx, PR_0_MMP_CSUM_INVALID, &pctx)) {
+ ext2fs_mmp_clear(fs);
+ retval = 0;
+ }
}
return retval;
}
if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) &&
!(ctx->flags & E2F_FLAG_SB_SPECIFIED) &&
((retval == EXT2_ET_BAD_MAGIC) ||
+ (retval == EXT2_ET_SB_CSUM_INVALID) ||
(retval == EXT2_ET_CORRUPT_SUPERBLOCK) ||
((retval == 0) && (retval2 = ext2fs_check_desc(fs))))) {
if (retval) {
}
if ((run_result & E2F_FLAG_CANCEL) == 0 &&
- sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM &&
+ ext2fs_has_group_desc_csum(ctx->fs) &&
!(ctx->options & E2F_OPT_READONLY)) {
retval = ext2fs_set_gdt_csum(ctx->fs);
if (retval) {
"Can't write a block bitmap"
ec EXT2_ET_BLOCK_BITMAP_READ,
- "Can't read an block bitmap"
+ "Can't read a block bitmap"
ec EXT2_ET_INODE_TABLE_WRITE,
"Can't write an inode table"
ec EXT2_ET_FILE_EXISTS,
"Ext2 file already exists"
+ec EXT2_ET_BLOCK_BITMAP_CSUM_INVALID,
+ "Block bitmap checksum does not match bitmap"
+
+ec EXT2_ET_INLINE_DATA_CANT_ITERATE,
+ "Cannot block iterate on an inode containing inline data"
+
end
#define EXT2_FLAG_PRINT_PROGRESS 0x40000
#define EXT2_FLAG_DIRECT_IO 0x80000
#define EXT2_FLAG_SKIP_MMP 0x100000
+#define EXT2_FLAG_IGNORE_CSUM_ERRORS 0x200000
/*
* Special flag in the ext2 inode i_flag field that means that this is
* Time at which e2fsck last updated the MMP block.
*/
long mmp_last_written;
+
+ /* progress operation functions */
+ struct ext2fs_progress_ops *progress_ops;
+
+ /* Precomputed FS UUID checksum for seeding other checksums */
+ __u32 csum_seed;
};
#if EXT2_FLAT_INCLUDES
#define DIRENT_FLAG_INCLUDE_EMPTY 1
#define DIRENT_FLAG_INCLUDE_REMOVED 2
+#define DIRENT_FLAG_INCLUDE_CSUM 4
#define DIRENT_DOT_FILE 1
#define DIRENT_DOT_DOT_FILE 2
#define DIRENT_OTHER_FILE 3
#define DIRENT_DELETED_FILE 4
+#define DIRENT_CHECKSUM 5
/*
* Inode scan definitions
environment at configure time. */
#warning "Compression support is experimental"
#endif
-#define EXT2_LIB_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE|\
- EXT2_FEATURE_INCOMPAT_COMPRESSION|\
- EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
- EXT2_FEATURE_INCOMPAT_META_BG|\
- EXT3_FEATURE_INCOMPAT_RECOVER|\
- EXT3_FEATURE_INCOMPAT_EXTENTS|\
- EXT4_FEATURE_INCOMPAT_FLEX_BG|\
- EXT4_FEATURE_INCOMPAT_MMP|\
- EXT4_FEATURE_INCOMPAT_64BIT)
+#define EXT2_LIB_INCOMPAT_COMPRESSION EXT2_FEATURE_INCOMPAT_COMPRESSION
+#else
+#define EXT2_LIB_INCOMPAT_COMPRESSION (0)
+#endif
+
+#ifdef CONFIG_MMP
+#define EXT4_LIB_INCOMPAT_MMP EXT4_FEATURE_INCOMPAT_MMP
+#else
+#define EXT4_LIB_INCOMPAT_MMP (0)
+#endif
+
+#ifdef CONFIG_QUOTA
+#define EXT4_LIB_RO_COMPAT_QUOTA EXT4_FEATURE_RO_COMPAT_QUOTA
#else
+#define EXT4_LIB_RO_COMPAT_QUOTA (0)
+#endif
+
#define EXT2_LIB_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE|\
+ EXT2_LIB_INCOMPAT_COMPRESSION|\
EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
EXT2_FEATURE_INCOMPAT_META_BG|\
EXT3_FEATURE_INCOMPAT_RECOVER|\
EXT3_FEATURE_INCOMPAT_EXTENTS|\
EXT4_FEATURE_INCOMPAT_FLEX_BG|\
- EXT4_FEATURE_INCOMPAT_MMP|\
+ EXT4_LIB_INCOMPAT_MMP|\
EXT4_FEATURE_INCOMPAT_64BIT)
-#endif
-#ifdef CONFIG_QUOTA
+
#define EXT2_LIB_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\
EXT4_FEATURE_RO_COMPAT_HUGE_FILE|\
EXT2_FEATURE_RO_COMPAT_LARGE_FILE|\
EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|\
EXT4_FEATURE_RO_COMPAT_GDT_CSUM|\
EXT4_FEATURE_RO_COMPAT_BIGALLOC|\
- EXT4_FEATURE_RO_COMPAT_QUOTA)
-#else
-#define EXT2_LIB_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\
- EXT4_FEATURE_RO_COMPAT_HUGE_FILE|\
- EXT2_FEATURE_RO_COMPAT_LARGE_FILE|\
- EXT4_FEATURE_RO_COMPAT_DIR_NLINK|\
- EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|\
- EXT4_FEATURE_RO_COMPAT_GDT_CSUM|\
- EXT4_FEATURE_RO_COMPAT_BIGALLOC)
-#endif
+ EXT4_LIB_RO_COMPAT_QUOTA|\
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
/*
* These features are only allowed if EXT2_FLAG_SOFTSUPP_FEATURES is passed
* to ext2fs_openfs()
*/
-#define EXT2_LIB_SOFTSUPP_INCOMPAT (0)
+#define EXT2_LIB_SOFTSUPP_INCOMPAT (EXT4_FEATURE_INCOMPAT_INLINE_DATA)
#define EXT2_LIB_SOFTSUPP_RO_COMPAT (EXT4_FEATURE_RO_COMPAT_REPLICA)
/*
* function prototypes
*/
+static inline int ext2fs_has_group_desc_csum(ext2_filsys fs)
+{
+ return EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM);
+}
+ /* The LARGE_FILE feature should be set if we have stored files 2GB+ in size */
+ static inline int ext2fs_needs_large_file_feature(unsigned long long file_size)
+ {
+ return file_size >= 0x80000000ULL;
+ }
+
/* alloc.c */
extern errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir, int mode,
ext2fs_inode_bitmap map, ext2_ino_t *ret);
void *out);
/* blknum.c */
+extern __u32 ext2fs_inode_bitmap_checksum(ext2_filsys fs, dgrp_t group);
+extern __u32 ext2fs_block_bitmap_checksum(ext2_filsys fs, dgrp_t group);
extern dgrp_t ext2fs_group_of_blk2(ext2_filsys fs, blk64_t);
extern blk64_t ext2fs_group_first_block2(ext2_filsys fs, dgrp_t group);
extern blk64_t ext2fs_group_last_block2(ext2_filsys fs, dgrp_t group);
extern struct ext2_group_desc *ext2fs_group_desc(ext2_filsys fs,
struct opaque_ext2_group_desc *gdp,
dgrp_t group);
+extern blk64_t ext2fs_block_bitmap_csum(ext2_filsys fs, dgrp_t group);
extern blk64_t ext2fs_block_bitmap_loc(ext2_filsys fs, dgrp_t group);
extern void ext2fs_block_bitmap_loc_set(ext2_filsys fs, dgrp_t group,
blk64_t blk);
+extern __u32 ext2fs_inode_bitmap_csum(ext2_filsys fs, dgrp_t group);
extern blk64_t ext2fs_inode_bitmap_loc(ext2_filsys fs, dgrp_t group);
extern void ext2fs_inode_bitmap_loc_set(ext2_filsys fs, dgrp_t group,
blk64_t blk);
extern void ext2fs_update_dynamic_rev(ext2_filsys fs);
/* crc32c.c */
-extern __u32 ext2fs_crc32c_be(__u32 crc, unsigned char const *p, size_t len);
+extern __u32 ext2fs_crc32_be(__u32 crc, unsigned char const *p, size_t len);
extern __u32 ext2fs_crc32c_le(__u32 crc, unsigned char const *p, size_t len);
/* csum.c */
+extern errcode_t ext2fs_mmp_csum_set(ext2_filsys fs, struct mmp_struct *mmp);
+extern int ext2fs_mmp_csum_verify(ext2_filsys, struct mmp_struct *mmp);
+extern int ext2fs_verify_csum_type(ext2_filsys fs, struct ext2_super_block *sb);
+extern errcode_t ext2fs_superblock_csum_set(ext2_filsys fs,
+ struct ext2_super_block *sb);
+extern int ext2fs_superblock_csum_verify(ext2_filsys fs,
+ struct ext2_super_block *sb);
+extern errcode_t ext2fs_ext_attr_block_csum_set(ext2_filsys fs,
+ ext2_ino_t inum, blk64_t block,
+ struct ext2_ext_attr_header *hdr);
+extern int ext2fs_ext_attr_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+ blk64_t block,
+ struct ext2_ext_attr_header *hdr);
+#define EXT2_DIRENT_TAIL(block, blocksize) \
+ ((struct ext2_dir_entry_tail *)(((char *)(block)) + \
+ (blocksize) - sizeof(struct ext2_dir_entry_tail)))
+
+extern void ext2fs_initialize_dirent_tail(ext2_filsys fs,
+ struct ext2_dir_entry_tail *t);
+extern int ext2fs_dirent_has_tail(ext2_filsys fs,
+ struct ext2_dir_entry *dirent);
+extern int ext2fs_dirent_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+ struct ext2_dir_entry *dirent);
+extern int ext2fs_dir_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+ struct ext2_dir_entry *dirent);
+extern errcode_t ext2fs_dir_block_csum_set(ext2_filsys fs, ext2_ino_t inum,
+ struct ext2_dir_entry *dirent);
+extern errcode_t ext2fs_get_dx_countlimit(ext2_filsys fs,
+ struct ext2_dir_entry *dirent,
+ struct ext2_dx_countlimit **cc,
+ int *offset);
+extern errcode_t ext2fs_extent_block_csum_set(ext2_filsys fs,
+ ext2_ino_t inum,
+ struct ext3_extent_header *eh);
+extern int ext2fs_extent_block_csum_verify(ext2_filsys fs,
+ ext2_ino_t inum,
+ struct ext3_extent_header *eh);
+extern errcode_t ext2fs_block_bitmap_csum_set(ext2_filsys fs, dgrp_t group,
+ char *bitmap, int size);
+extern int ext2fs_block_bitmap_csum_verify(ext2_filsys fs, dgrp_t group,
+ char *bitmap, int size);
+extern errcode_t ext2fs_inode_bitmap_csum_set(ext2_filsys fs, dgrp_t group,
+ char *bitmap, int size);
+extern int ext2fs_inode_bitmap_csum_verify(ext2_filsys fs, dgrp_t group,
+ char *bitmap, int size);
+extern errcode_t ext2fs_inode_csum_set(ext2_filsys fs, ext2_ino_t inum,
+ struct ext2_inode_large *inode);
+extern int ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+ struct ext2_inode_large *inode);
extern void ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group);
extern int ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group);
extern errcode_t ext2fs_set_gdt_csum(ext2_filsys fs);
extern __u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group);
/* dblist.c */
-
-extern errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs);
extern errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist);
extern errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino,
blk_t blk, int blockcnt);
void *buf, int flags);
extern errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block,
void *buf, int flags);
+extern errcode_t ext2fs_read_dir_block4(ext2_filsys fs, blk64_t block,
+ void *buf, int flags, ext2_ino_t ino);
extern errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block,
void *buf);
extern errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
void *buf, int flags);
extern errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block,
void *buf, int flags);
+extern errcode_t ext2fs_write_dir_block4(ext2_filsys fs, blk64_t block,
+ void *buf, int flags, ext2_ino_t ino);
/* dirhash.c */
extern errcode_t ext2fs_dirhash(int version, const char *name, int len,
extern errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf);
extern errcode_t ext2fs_read_ext_attr2(ext2_filsys fs, blk64_t block,
void *buf);
+extern errcode_t ext2fs_read_ext_attr3(ext2_filsys fs, blk64_t block,
+ void *buf, ext2_ino_t inum);
extern errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block,
void *buf);
extern errcode_t ext2fs_write_ext_attr2(ext2_filsys fs, blk64_t block,
void *buf);
+extern errcode_t ext2fs_write_ext_attr3(ext2_filsys fs, blk64_t block,
+ void *buf, ext2_ino_t inum);
extern errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
char *block_buf,
int adjust, __u32 *newcount);
extern errcode_t ext2fs_adjust_ea_refcount2(ext2_filsys fs, blk64_t blk,
char *block_buf,
int adjust, __u32 *newcount);
+extern errcode_t ext2fs_adjust_ea_refcount3(ext2_filsys fs, blk64_t blk,
+ char *block_buf,
+ int adjust, __u32 *newcount,
+ ext2_ino_t inum);
/* extent.c */
extern errcode_t ext2fs_extent_header_verify(void *ptr, int size);
__u32 *out);
/* gen_bitmap64.c */
-
-/* Generate and print bitmap usage statistics */
-#define BMAP_STATS
-
void ext2fs_free_generic_bmap(ext2fs_generic_bitmap bmap);
errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic,
int type, __u64 start, __u64 end,
errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs,
ext2fs_block_bitmap *bitmap);
+/* get_num_dirs.c */
+extern errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs);
+
/* getsize.c */
extern errcode_t ext2fs_get_device_size(const char *file, int blocksize,
blk_t *retblocks);
unsigned long align, void *ptr);
/* inode.c */
+extern void ext2fs_free_inode_cache(struct ext2_inode_cache *icache);
extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
extern errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan,
ext2_ino_t *ino,
errcode_t ext2fs_mmp_init(ext2_filsys fs);
errcode_t ext2fs_mmp_start(ext2_filsys fs);
errcode_t ext2fs_mmp_update(ext2_filsys fs);
+errcode_t ext2fs_mmp_update2(ext2_filsys fs, int immediately);
errcode_t ext2fs_mmp_stop(ext2_filsys fs);
unsigned ext2fs_mmp_new_seq(void);
extern errcode_t ext2fs_create_resize_inode(ext2_filsys fs);
/* swapfs.c */
+extern errcode_t ext2fs_dirent_swab_in(ext2_filsys fs, char *buf, int flags);
+extern errcode_t ext2fs_dirent_swab_out(ext2_filsys fs, char *buf, int flags);
extern void ext2fs_swap_ext_attr(char *to, char *from, int bufsize,
int has_header);
extern void ext2fs_swap_ext_attr_header(struct ext2_ext_attr_header *to_header,
/* inline functions */
#ifdef NO_INLINE_FUNCS
+extern void ext2fs_init_csum_seed(ext2_filsys fs);
extern errcode_t ext2fs_get_mem(unsigned long size, void *ptr);
extern errcode_t ext2fs_get_memzero(unsigned long size, void *ptr);
extern errcode_t ext2fs_get_array(unsigned long count,
#endif /* __STDC_VERSION__ >= 199901L */
#endif
+_INLINE_ void ext2fs_init_csum_seed(ext2_filsys fs)
+{
+ if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ return;
+
+ fs->csum_seed = ext2fs_crc32c_le(~0, fs->super->s_uuid,
+ sizeof(fs->super->s_uuid));
+}
+
#ifndef EXT2_CUSTOM_MEMORY_ROUTINES
#include <string.h>
/*
- * Allocate memory
+ * Allocate memory. The 'ptr' arg must point to a pointer.
*/
_INLINE_ errcode_t ext2fs_get_mem(unsigned long size, void *ptr)
{
}
/*
- * Free memory
+ * Free memory. The 'ptr' arg must point to a pointer.
*/
_INLINE_ errcode_t ext2fs_free_mem(void *ptr)
{
}
/*
- * Resize memory
+ * Resize memory. The 'ptr' arg must point to a pointer.
*/
_INLINE_ errcode_t ext2fs_resize_mem(unsigned long EXT2FS_ATTR((unused)) old_size,
unsigned long size, void *ptr)
return ((a - 1) / b) + 1;
}
+_INLINE_ int ext2fs_dirent_name_len(const struct ext2_dir_entry *entry)
+{
+ return entry->name_len & 0xff;
+}
+
+_INLINE_ void ext2fs_dirent_set_name_len(struct ext2_dir_entry *entry, int len)
+{
+ entry->name_len = (entry->name_len & 0xff00) | (len & 0xff);
+}
+
+_INLINE_ int ext2fs_dirent_file_type(const struct ext2_dir_entry *entry)
+{
+ return entry->name_len >> 8;
+}
+
+_INLINE_ void ext2fs_dirent_set_file_type(struct ext2_dir_entry *entry, int type)
+{
+ entry->name_len = (entry->name_len & 0xff) | (type << 8);
+}
+
#undef _INLINE_
#endif
struct ext2_inode_cache_ent {
ext2_ino_t ino;
- struct ext2_inode inode;
+ struct ext2_inode *inode;
};
/* Function prototypes */
int skip_progress;
};
+/*
+ * progress callback functions
+ */
+struct ext2fs_progress_ops {
+ void (*init)(ext2_filsys fs,
+ struct ext2fs_numeric_progress_struct * progress,
+ const char *label, __u64 max);
+ void (*update)(ext2_filsys fs,
+ struct ext2fs_numeric_progress_struct * progress,
+ __u64 val);
+ void (*close)(ext2_filsys fs,
+ struct ext2fs_numeric_progress_struct * progress,
+ const char *message);
+};
+
+extern struct ext2fs_progress_ops ext2fs_numeric_progress_ops;
+
extern void ext2fs_numeric_progress_init(ext2_filsys fs,
struct ext2fs_numeric_progress_struct * progress,
const char *label, __u64 max);
extern void ext2fs_warn_bitmap32(ext2fs_generic_bitmap bitmap,const char *func);
extern int ext2fs_mem_is_zero(const char *mem, size_t len);
+
+ int ext2fs_file_block_offset_too_big(ext2_filsys fs,
+ struct ext2_inode *inode,
+ blk64_t offset);
#endif
}
-#ifdef BMAP_STATS_OPS
+#ifdef ENABLE_BMAP_STATS_OPS
#define INC_STAT(map, name) map->stats.name
#else
#define INC_STAT(map, name) ;;
if (retval)
return retval;
-#ifdef BMAP_STATS
+#ifdef ENABLE_BMAP_STATS
if (gettimeofday(&bitmap->stats.created,
(struct timezone *) NULL) == -1) {
perror("gettimeofday");
+ ext2fs_free_mem(&bitmap);
return 1;
}
bitmap->stats.type = type;
return 0;
}
-#ifdef BMAP_STATS
+#ifdef ENABLE_BMAP_STATS
static void ext2fs_print_bmap_statistics(ext2fs_generic_bitmap bitmap)
{
struct ext2_bmap_statistics *stats = &bitmap->stats;
-#ifdef BMAP_STATS_OPS
+#ifdef ENABLE_BMAP_STATS_OPS
float mark_seq_perc = 0.0, test_seq_perc = 0.0;
float mark_back_perc = 0.0, test_back_perc = 0.0;
#endif
double inuse;
struct timeval now;
-#ifdef BMAP_STATS_OPS
+#ifdef ENABLE_BMAP_STATS_OPS
if (stats->test_count) {
test_seq_perc = ((float)stats->test_seq /
stats->test_count) * 100;
fprintf(stderr, "\n[+] %s bitmap (type %d)\n", bitmap->description,
stats->type);
fprintf(stderr, "=================================================\n");
-#ifdef BMAP_STATS_OPS
+#ifdef ENABLE_BMAP_STATS_OPS
fprintf(stderr, "%16llu bits long\n",
bitmap->real_end - bitmap->start);
fprintf(stderr, "%16lu copy_bmap\n%16lu resize_bmap\n",
fprintf(stderr, "%16llu bits marked backwards (%.2f%%)\n"
"%16.2f seconds in use\n",
stats->mark_back, mark_back_perc, inuse);
-#endif /* BMAP_STATS_OPS */
+#endif /* ENABLE_BMAP_STATS_OPS */
}
#endif
if (!EXT2FS_IS_64_BITMAP(bmap))
return;
-#ifdef BMAP_STATS
+#ifdef ENABLE_BMAP_STATS
if (getenv("E2FSPROGS_BITMAP_STATS")) {
ext2fs_print_bmap_statistics(bmap);
bmap->bitmap_ops->print_stats(bmap);
return retval;
-#ifdef BMAP_STATS_OPS
+#ifdef ENABLE_BMAP_STATS_OPS
src->stats.copy_count++;
#endif
-#ifdef BMAP_STATS
+#ifdef ENABLE_BMAP_STATS
if (gettimeofday(&new_bmap->stats.created,
(struct timezone *) NULL) == -1) {
perror("gettimeofday");
+ ext2fs_free_mem(&new_bmap);
return 1;
}
new_bmap->stats.type = src->stats.type;
ext2fs_free_mem(&new_bmap);
return retval;
}
- sprintf(new_descr, "copy of %s", descr);
+ strcpy(new_descr, "copy of ");
+ strcat(new_descr, descr);
new_bmap->description = new_descr;
}
arg >>= bitmap->cluster_bits;
-#ifdef BMAP_STATS_OPS
+#ifdef ENABLE_BMAP_STATS_OPS
if (arg == bitmap->stats.last_marked + 1)
bitmap->stats.mark_seq++;
if (arg < bitmap->stats.last_marked)
arg >>= bitmap->cluster_bits;
-#ifdef BMAP_STATS_OPS
+#ifdef ENABLE_BMAP_STATS_OPS
bitmap->stats.test_count++;
if (arg == bitmap->stats.last_tested + 1)
bitmap->stats.test_seq++;
char *buf;
int rec_len;
int filetype = 0;
+ struct ext2_dir_entry_tail *t;
+ int csum_size = 0;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
memset(buf, 0, fs->blocksize);
dir = (struct ext2_dir_entry *) buf;
- retval = ext2fs_set_rec_len(fs, fs->blocksize, dir);
+ if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ csum_size = sizeof(struct ext2_dir_entry_tail);
+
+ retval = ext2fs_set_rec_len(fs, fs->blocksize - csum_size, dir);
- if (retval)
+ if (retval) {
+ ext2fs_free_mem(&buf);
return retval;
+ }
if (dir_ino) {
if (fs->super->s_feature_incompat &
EXT2_FEATURE_INCOMPAT_FILETYPE)
- filetype = EXT2_FT_DIR << 8;
+ filetype = EXT2_FT_DIR;
/*
* Set up entry for '.'
*/
dir->inode = dir_ino;
- dir->name_len = 1 | filetype;
+ ext2fs_dirent_set_name_len(dir, 1);
+ ext2fs_dirent_set_file_type(dir, filetype);
dir->name[0] = '.';
- rec_len = fs->blocksize - EXT2_DIR_REC_LEN(1);
+ rec_len = (fs->blocksize - csum_size) - EXT2_DIR_REC_LEN(1);
dir->rec_len = EXT2_DIR_REC_LEN(1);
/*
*/
dir = (struct ext2_dir_entry *) (buf + dir->rec_len);
retval = ext2fs_set_rec_len(fs, rec_len, dir);
- if (retval)
+ if (retval) {
+ ext2fs_free_mem(&buf);
return retval;
+ }
dir->inode = parent_ino;
- dir->name_len = 2 | filetype;
+ ext2fs_dirent_set_name_len(dir, 2);
+ ext2fs_dirent_set_file_type(dir, filetype);
dir->name[0] = '.';
dir->name[1] = '.';
}
+
+ if (csum_size) {
+ t = EXT2_DIRENT_TAIL(buf, fs->blocksize);
+ ext2fs_initialize_dirent_tail(fs, t);
+ }
*block = buf;
return 0;
}
{
int first = 1, bg_flags = 0;
- if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM)
+ if (ext2fs_has_group_desc_csum(fs))
bg_flags = ext2fs_bg_flags(fs, i);
print_bg_opt(bg_flags, EXT2_BG_INODE_UNINIT, "INODE_UNINIT",
int has_super;
blk64_t blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block);
ext2_ino_t ino_itr = 1;
+ errcode_t retval;
if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
EXT4_FEATURE_RO_COMPAT_BIGALLOC))
print_range(first_block, last_block);
fputs(")", stdout);
print_bg_opts(fs, i);
- if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
+ if (ext2fs_has_group_desc_csum(fs)) {
unsigned csum = ext2fs_bg_checksum(fs, i);
unsigned exp_csum = ext2fs_group_desc_csum(fs, i);
print_number(ext2fs_block_bitmap_loc(fs, i));
print_bg_rel_offset(fs, ext2fs_block_bitmap_loc(fs, i), 0,
first_block, last_block);
+ if (fs->super->s_feature_ro_compat &
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
+ printf(_(", csum 0x%08x"),
+ ext2fs_block_bitmap_checksum(fs, i));
fputs(_(", Inode bitmap at "), stdout);
print_number(ext2fs_inode_bitmap_loc(fs, i));
print_bg_rel_offset(fs, ext2fs_inode_bitmap_loc(fs, i), 0,
first_block, last_block);
+ if (fs->super->s_feature_ro_compat &
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
+ printf(_(", csum 0x%08x"),
+ ext2fs_inode_bitmap_checksum(fs, i));
fputs(_("\n Inode table at "), stdout);
print_range(ext2fs_inode_table_loc(fs, i),
ext2fs_inode_table_loc(fs, i) +
ext2fs_bg_itable_unused(fs, i));
if (block_bitmap) {
fputs(_(" Free blocks: "), stdout);
- ext2fs_get_block_bitmap_range2(fs->block_map,
+ retval = ext2fs_get_block_bitmap_range2(fs->block_map,
blk_itr, block_nbytes << 3, block_bitmap);
- print_free(i, block_bitmap,
- fs->super->s_clusters_per_group,
- fs->super->s_first_data_block,
- EXT2FS_CLUSTER_RATIO(fs));
+ if (retval)
+ com_err("list_desc", retval,
+ "while reading block bitmap");
+ else
+ print_free(i, block_bitmap,
+ fs->super->s_clusters_per_group,
+ fs->super->s_first_data_block,
+ EXT2FS_CLUSTER_RATIO(fs));
fputc('\n', stdout);
blk_itr += fs->super->s_clusters_per_group;
}
if (inode_bitmap) {
fputs(_(" Free inodes: "), stdout);
- ext2fs_get_inode_bitmap_range2(fs->inode_map,
+ retval = ext2fs_get_inode_bitmap_range2(fs->inode_map,
ino_itr, inode_nbytes << 3, inode_bitmap);
- print_free(i, inode_bitmap,
- fs->super->s_inodes_per_group, 1, 1);
+ if (retval)
+ com_err("list_desc", retval,
+ "while reading inode bitmap");
+ else
+ print_free(i, inode_bitmap,
+ fs->super->s_inodes_per_group,
+ 1, 1);
fputc('\n', stdout);
ino_itr += fs->super->s_inodes_per_group;
}
ext2fs_badblocks_list_free(bb_list);
}
+static const char *journal_checksum_type_str(__u8 type)
+{
+ switch (type) {
+ case JBD2_CRC32C_CHKSUM:
+ return "crc32c";
+ default:
+ return "unknown";
+ }
+}
+
static void print_inline_journal_information(ext2_filsys fs)
{
journal_superblock_t *jsb;
(unsigned int)ntohl(jsb->s_maxlen),
(unsigned int)ntohl(jsb->s_sequence),
(unsigned int)ntohl(jsb->s_start));
+ if (jsb->s_feature_compat &
+ ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_CHECKSUM))
+ printf(_("Journal checksum type: crc32\n"));
+ if (jsb->s_feature_incompat &
+ ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V2))
+ printf(_("Journal checksum type: %s\n"
+ "Journal checksum: 0x%08x\n"),
+ journal_checksum_type_str(jsb->s_checksum_type),
+ ext2fs_be32_to_cpu(jsb->s_checksum));
if (jsb->s_errno != 0)
printf(_("Journal errno: %d\n"),
(int) ntohl(jsb->s_errno));
exit(1);
}
+ if (jsb->s_feature_compat &
+ ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_CHECKSUM))
+ printf(_("Journal checksum type: crc32\n"));
+ if (jsb->s_feature_incompat &
+ ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V2))
+ printf(_("Journal checksum type: %s\n"
+ "Journal checksum: 0x%08x\n"),
+ journal_checksum_type_str(jsb->s_checksum_type),
+ ext2fs_be32_to_cpu(jsb->s_checksum));
+
printf(_("\nJournal block size: %u\n"
"Journal length: %u\n"
"Journal first block: %u\n"
int journal_size;
int journal_flags;
int lazy_itable_init;
- char *bad_blocks_filename;
+ char *bad_blocks_filename = NULL;
__u32 fs_stride;
int quotatype = -1; /* Initialize both user and group quotas by default */
ext2fs_badblocks_list_iterate_end(bb_iter);
}
+static void write_reserved_inodes(ext2_filsys fs)
+{
+ errcode_t retval;
+ ext2_ino_t ino;
+ struct ext2_inode *inode;
+
+ retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ if (retval) {
+ com_err("inode_init", retval,
+ "while allocating memory");
+ exit(1);
+ }
+ bzero(inode, EXT2_INODE_SIZE(fs->super));
+
+ for (ino = 1; ino < EXT2_FIRST_INO(fs->super); ino++)
+ ext2fs_write_inode_full(fs, ino, inode,
+ EXT2_INODE_SIZE(fs->super));
+
+ ext2fs_free_mem(&inode);
+}
+
static void write_inode_tables(ext2_filsys fs, int lazy_flag, int itable_zeroed)
{
errcode_t retval;
ext2fs_zero_blocks2(0, 0, 0, 0, 0);
ext2fs_numeric_progress_close(fs, &progress,
_("done \n"));
+
+ /* Reserved inodes must always have correct checksums */
+ if (fs->super->s_creator_os == EXT2_OS_LINUX &&
+ fs->super->s_feature_ro_compat &
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
+ write_reserved_inodes(fs);
}
static void create_root_dir(ext2_filsys fs)
printf("\n\n");
}
+/*
+ * Returns true if making a file system for the Hurd, else 0
+ */
+static int for_hurd(const char *os)
+{
+ if (!os) {
+#ifdef __GNU__
+ return 1;
+#else
+ return 0;
+#endif
+ }
+ if (isdigit(*os))
+ return (atoi(os) == EXT2_OS_HURD);
+ return (strcasecmp(os, "GNU") == 0 || strcasecmp(os, "hurd") == 0);
+}
+
/*
* Set the S_CREATOR_OS field. Return true if OS is known,
* otherwise, 0.
#ifdef CONFIG_QUOTA
EXT4_FEATURE_RO_COMPAT_QUOTA|
#endif
- 0
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM
};
const char *size_type;
struct str_list list;
unsigned long long meg;
- int is_hurd = 0;
+ int is_hurd = for_hurd(creator_os);
if (init_list(&list))
return 0;
- if (creator_os && (!strcasecmp(creator_os, "GNU") ||
- !strcasecmp(creator_os, "hurd")))
- is_hurd = 1;
-
if (fs_type)
ext_type = fs_type;
else if (is_hurd)
parse_str = malloc(strlen(usage_types)+1);
if (!parse_str) {
+ free(profile_type);
free(list.list);
return 0;
}
char * fs_type = 0;
char * usage_types = 0;
blk64_t dev_size;
+ /*
+ * NOTE: A few words about fs_blocks_count and blocksize:
+ *
+ * Initially, blocksize is set to zero, which implies 1024.
+ * If -b is specified, blocksize is updated to the user's value.
+ *
+ * Next, the device size or the user's "blocks" command line argument
+ * is used to set fs_blocks_count; the units are blocksize.
+ *
+ * Later, if blocksize hasn't been set and the profile specifies a
+ * blocksize, then blocksize is updated and fs_blocks_count is scaled
+ * appropriately. Note the change in units!
+ *
+ * Finally, we complain about fs_blocks_count > 2^32 on a non-64bit fs.
+ */
blk64_t fs_blocks_count = 0;
#ifdef __linux__
struct utsname ut;
discard = 0;
break;
case 'l':
- bad_blocks_filename = malloc(strlen(optarg)+1);
+ bad_blocks_filename = realloc(bad_blocks_filename,
+ strlen(optarg) + 1);
if (!bad_blocks_filename) {
com_err(program_name, ENOMEM,
_("in malloc for bad_blocks_filename"));
tmp = get_string_from_profile(fs_types, "default_features",
"");
}
+ /* Mask off features which aren't supported by the Hurd */
+ if (for_hurd(creator_os)) {
+ fs_param.s_feature_incompat &= ~EXT2_FEATURE_INCOMPAT_FILETYPE;
+ fs_param.s_feature_ro_compat &=
+ ~(EXT4_FEATURE_RO_COMPAT_HUGE_FILE |
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM);
+ }
edit_feature(fs_features ? fs_features : tmp,
&fs_param.s_feature_compat);
if (tmp)
free(tmp);
+ /*
+ * If the user specified features incompatible with the Hurd, complain
+ */
+ if (for_hurd(creator_os)) {
+ if (fs_param.s_feature_incompat &
+ EXT2_FEATURE_INCOMPAT_FILETYPE) {
+ fprintf(stderr, _("The HURD does not support the "
+ "filetype feature.\n"));
+ exit(1);
+ }
+ if (fs_param.s_feature_ro_compat &
+ EXT4_FEATURE_RO_COMPAT_HUGE_FILE) {
+ fprintf(stderr, _("The HURD does not support the "
+ "huge_file feature.\n"));
+ exit(1);
+ }
+ if (fs_param.s_feature_ro_compat &
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) {
+ fprintf(stderr, _("The HURD does not support the "
+ "metadata_csum feature.\n"));
+ exit(1);
+ }
+ }
+ /* Get the hardware sector sizes, if available */
+ retval = ext2fs_get_device_sectsize(device_name, &lsector_size);
+ if (retval) {
+ com_err(program_name, retval,
+ _("while trying to determine hardware sector size"));
+ exit(1);
+ }
+ retval = ext2fs_get_device_phys_sectsize(device_name, &psector_size);
+ if (retval) {
+ com_err(program_name, retval,
+ _("while trying to determine physical sector size"));
+ exit(1);
+ }
+
+ tmp = getenv("MKE2FS_DEVICE_SECTSIZE");
+ if (tmp != NULL)
+ lsector_size = atoi(tmp);
+ tmp = getenv("MKE2FS_DEVICE_PHYS_SECTSIZE");
+ if (tmp != NULL)
+ psector_size = atoi(tmp);
+
+ /* Older kernels may not have physical/logical distinction */
+ if (!psector_size)
+ psector_size = lsector_size;
+
+ if (blocksize <= 0) {
+ use_bsize = get_int_from_profile(fs_types, "blocksize", 4096);
+
+ if (use_bsize == -1) {
+ use_bsize = sys_page_size;
+ if ((linux_version_code < (2*65536 + 6*256)) &&
+ (use_bsize > 4096))
+ use_bsize = 4096;
+ }
+ if (lsector_size && use_bsize < lsector_size)
+ use_bsize = lsector_size;
+ if ((blocksize < 0) && (use_bsize < (-blocksize)))
+ use_bsize = -blocksize;
+ blocksize = use_bsize;
+ fs_blocks_count /= (blocksize / 1024);
+ } else {
+ if (blocksize < lsector_size) { /* Impossible */
+ com_err(program_name, EINVAL,
+ _("while setting blocksize; too small "
+ "for device\n"));
+ exit(1);
+ } else if ((blocksize < psector_size) &&
+ (psector_size <= sys_page_size)) { /* Suboptimal */
+ fprintf(stderr, _("Warning: specified blocksize %d is "
+ "less than device physical sectorsize %d\n"),
+ blocksize, psector_size);
+ }
+ }
+
+ fs_param.s_log_block_size =
+ int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE);
+
/*
* We now need to do a sanity check of fs_blocks_count for
* 32-bit vs 64-bit block number support.
*/
- if ((fs_blocks_count > MAX_32_NUM) && (blocksize == 0)) {
- fs_blocks_count /= 4; /* Try using a 4k blocksize */
- blocksize = 4096;
- fs_param.s_log_block_size = 2;
- }
if ((fs_blocks_count > MAX_32_NUM) &&
!(fs_param.s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) &&
get_bool_from_profile(fs_types, "auto_64-bit_support", 0)) {
if ((fs_param.s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) &&
((tmp = getenv("MKE2FS_FIRST_META_BG"))))
fs_param.s_first_meta_bg = atoi(tmp);
-
- /* Get the hardware sector sizes, if available */
- retval = ext2fs_get_device_sectsize(device_name, &lsector_size);
- if (retval) {
- com_err(program_name, retval,
- _("while trying to determine hardware sector size"));
- exit(1);
- }
- retval = ext2fs_get_device_phys_sectsize(device_name, &psector_size);
- if (retval) {
- com_err(program_name, retval,
- _("while trying to determine physical sector size"));
- exit(1);
- }
-
- if ((tmp = getenv("MKE2FS_DEVICE_SECTSIZE")) != NULL)
- lsector_size = atoi(tmp);
- if ((tmp = getenv("MKE2FS_DEVICE_PHYS_SECTSIZE")) != NULL)
- psector_size = atoi(tmp);
-
- /* Older kernels may not have physical/logical distinction */
- if (!psector_size)
- psector_size = lsector_size;
-
- if (blocksize <= 0) {
- use_bsize = get_int_from_profile(fs_types, "blocksize", 4096);
-
- if (use_bsize == -1) {
- use_bsize = sys_page_size;
- if ((linux_version_code < (2*65536 + 6*256)) &&
- (use_bsize > 4096))
- use_bsize = 4096;
- }
- if (lsector_size && use_bsize < lsector_size)
- use_bsize = lsector_size;
- if ((blocksize < 0) && (use_bsize < (-blocksize)))
- use_bsize = -blocksize;
- blocksize = use_bsize;
- ext2fs_blocks_count_set(&fs_param,
- ext2fs_blocks_count(&fs_param) /
- (blocksize / 1024));
- } else {
- if (blocksize < lsector_size) { /* Impossible */
- com_err(program_name, EINVAL,
- _("while setting blocksize; too small "
- "for device\n"));
- exit(1);
- } else if ((blocksize < psector_size) &&
- (psector_size <= sys_page_size)) { /* Suboptimal */
- fprintf(stderr, _("Warning: specified blocksize %d is "
- "less than device physical sectorsize %d\n"),
- blocksize, psector_size);
- }
- }
-
- fs_param.s_log_block_size =
- int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE);
if (fs_param.s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_BIGALLOC) {
if (!cluster_size)
cluster_size = get_int_from_profile(fs_types,
if (extended_opts)
parse_extended_opts(&fs_param, extended_opts);
+ /* Don't allow user to set both metadata_csum and uninit_bg bits. */
+ if ((fs_param.s_feature_ro_compat &
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+ (fs_param.s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+ fs_param.s_feature_ro_compat &=
+ ~EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
+
/* Can't support bigalloc feature without extents feature */
if ((fs_param.s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_BIGALLOC) &&
!(fs_param.s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS)) {
int csum_flag, force_undo;
csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(&fs_param,
- EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM);
force_undo = get_int_from_profile(fs_types, "force_undo", 0);
if (!force_undo && (!csum_flag || !lazy_itable_init))
return 0;
}
if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) ||
- access(tdb_dir, W_OK))
+ access(tdb_dir, W_OK)) {
+ if (free_tdb_dir)
+ free(tdb_dir);
return 0;
+ }
tmp_name = strdup(name);
if (!tmp_name)
com_err(device_name, retval, _("while setting up superblock"));
exit(1);
}
+ fs->progress_ops = &ext2fs_numeric_progress_ops;
+
+ /* Check the user's mkfs options for metadata checksumming */
+ if (!quiet &&
+ EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+ if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+ EXT3_FEATURE_INCOMPAT_EXTENTS))
+ printf(_("Extents are not enabled. The file extent "
+ "tree can be checksummed, whereas block maps "
+ "cannot. Not enabling extents reduces the "
+ "coverage of metadata checksumming. "
+ "Pass -O extents to rectify.\n"));
+ if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_INCOMPAT_64BIT))
+ printf(_("64-bit filesystem support is not "
+ "enabled. The larger fields afforded by "
+ "this feature enable full-strength "
+ "checksumming. Pass -O 64bit to rectify.\n"));
+ }
/* Calculate journal blocks */
if (!journal_device && ((journal_size) ||
(fs_param.s_feature_ro_compat &
(EXT4_FEATURE_RO_COMPAT_HUGE_FILE|EXT4_FEATURE_RO_COMPAT_GDT_CSUM|
EXT4_FEATURE_RO_COMPAT_DIR_NLINK|
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM|
EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)))
fs->super->s_kbytes_written = 1;
}
} else
uuid_generate(fs->super->s_uuid);
+ ext2fs_init_csum_seed(fs);
/*
* Initialize the directory index variables
sizeof(fs->super->s_last_mounted));
}
+ if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ fs->super->s_checksum_type = EXT2_CRC32C_CHKSUM;
+
if (!quiet || noaction)
show_stats(fs);
* inodes as unused; we want e2fsck to consider all
* inodes as potentially containing recoverable data.
*/
- if (fs->super->s_feature_ro_compat &
- EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
+ if (ext2fs_has_group_desc_csum(fs)) {
for (i = 0; i < fs->group_desc_count; i++)
ext2fs_bg_itable_unused_set(fs, i, 0);
}