#include "e2fsck.h"
#include "problem.h"
-#include "dict.h"
+#include "support/dict.h"
#ifdef NO_INLINE_FUNCS
#define _INLINE_
* Keeps track of how many times an inode is referenced.
*/
static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf);
+static int check_dir_block2(ext2_filsys fs,
+ struct ext2_db_entry2 *dir_blocks_info,
+ void *priv_data);
static int check_dir_block(ext2_filsys fs,
struct ext2_db_entry2 *dir_blocks_info,
void *priv_data);
struct problem_context pctx;
int count, max;
e2fsck_t ctx;
+ unsigned long long list_offset;
+ unsigned long long ra_entries;
+ unsigned long long next_ra_off;
};
void e2fsck_pass2(e2fsck_t ctx)
int i, depth;
problem_t code;
int bad_dir;
+ int (*check_dir_func)(ext2_filsys fs,
+ struct ext2_db_entry2 *dir_blocks_info,
+ void *priv_data);
init_resource_track(&rtrack, ctx->fs->io);
clear_problem_context(&cd.pctx);
cd.ctx = ctx;
cd.count = 1;
cd.max = ext2fs_dblist_count2(fs->dblist);
+ cd.list_offset = 0;
+ cd.ra_entries = ctx->readahead_kb * 1024 / ctx->fs->blocksize;
+ cd.next_ra_off = 0;
if (ctx->progress)
(void) (ctx->progress)(ctx, 2, 0, cd.max);
- if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX)
+ if (ext2fs_has_feature_dir_index(fs->super))
ext2fs_dblist_sort2(fs->dblist, special_dir_block_cmp);
- cd.pctx.errcode = ext2fs_dblist_iterate2(fs->dblist, check_dir_block,
+ check_dir_func = cd.ra_entries ? check_dir_block2 : check_dir_block;
+ cd.pctx.errcode = ext2fs_dblist_iterate2(fs->dblist, check_dir_func,
&cd);
- if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART)
- return;
-
if (ctx->flags & E2F_FLAG_RESTART_LATER) {
ctx->flags |= E2F_FLAG_RESTART;
- return;
+ ctx->flags &= ~E2F_FLAG_RESTART_LATER;
}
+ if (ctx->flags & E2F_FLAG_RUN_RETURN)
+ return;
+
if (cd.pctx.errcode) {
fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
ctx->flags |= E2F_FLAG_ABORT;
return;
}
-#ifdef ENABLE_HTREE
for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) {
if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
return;
}
}
e2fsck_free_dx_dir_info(ctx);
-#endif
+
ext2fs_free_mem(&buf);
ext2fs_free_dblist(fs->dblist);
clear_problem_context(&pctx);
if (ctx->large_files) {
- if (!(sb->s_feature_ro_compat &
- EXT2_FEATURE_RO_COMPAT_LARGE_FILE) &&
+ if (!ext2fs_has_feature_large_file(sb) &&
fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) {
- sb->s_feature_ro_compat |=
- EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
+ ext2fs_set_feature_large_file(sb);
fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
ext2fs_mark_super_dirty(fs);
}
*/
static int check_name(e2fsck_t ctx,
struct ext2_dir_entry *dirent,
- ext2_ino_t dir_ino,
struct problem_context *pctx)
{
int i;
return ret;
}
+static int encrypted_check_name(e2fsck_t ctx,
+ struct ext2_dir_entry *dirent,
+ struct problem_context *pctx)
+{
+ if (ext2fs_dirent_name_len(dirent) < EXT4_CRYPTO_BLOCK_SIZE) {
+ if (fix_problem(ctx, PR_2_BAD_ENCRYPTED_NAME, pctx)) {
+ dirent->inode = 0;
+ return 1;
+ }
+ ext2fs_unmark_valid(ctx->fs);
+ }
+ return 0;
+}
+
/*
* Check the directory filetype (if present)
*/
int should_be = EXT2_FT_UNKNOWN;
struct ext2_inode inode;
- if (!(ctx->fs->super->s_feature_incompat &
- EXT2_FEATURE_INCOMPAT_FILETYPE)) {
+ if (!ext2fs_has_feature_filetype(ctx->fs->super)) {
if (filetype == 0 ||
!fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx))
return 0;
return 1;
}
-#ifdef ENABLE_HTREE
static void parse_int_node(ext2_filsys fs,
struct ext2_db_entry2 *db,
struct check_dir_struct *cd,
#endif
count = ext2fs_le16_to_cpu(limit->count);
- if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ if (ext2fs_has_feature_metadata_csum(fs->super))
csum_size = sizeof(struct ext2_dx_tail);
expect_limit = (fs->blocksize -
(csum_size + ((char *) ent - block_buf))) /
dx_dir->numblocks = 0;
e2fsck_rehash_dir_later(cd->ctx, cd->pctx.ino);
}
-#endif /* ENABLE_HTREE */
/*
* Given a busted directory, try to salvage it somehow.
return retval;
}
-int get_filename_hash(ext2_filsys fs, int encrypted, int version,
- const char *name, int len, ext2_dirhash_t *ret_hash,
- ext2_dirhash_t *ret_minor_hash)
+static int check_dir_block2(ext2_filsys fs,
+ struct ext2_db_entry2 *db,
+ void *priv_data)
{
- char buf[2*EXT2FS_DIGEST_SIZE];
- int buf_len;
-
- if (!encrypted)
- return ext2fs_dirhash(version, name, len,
- fs->super->s_hash_seed,
- ret_hash, ret_minor_hash);
-
- if (len <= EXT2FS_DIGEST_SIZE)
- buf_len = ext2fs_digest_encode(name, len, buf);
- else {
- ext2fs_sha256(name, len, buf + EXT2FS_DIGEST_SIZE);
- buf[0] = 'I';
- buf_len = ext2fs_digest_encode(buf + EXT2FS_DIGEST_SIZE,
- EXT2FS_DIGEST_SIZE, buf + 1);
- buf_len++;
+ int err;
+ struct check_dir_struct *cd = priv_data;
+
+ if (cd->ra_entries && cd->list_offset >= cd->next_ra_off) {
+ err = e2fsck_readahead_dblist(fs,
+ E2FSCK_RA_DBLIST_IGNORE_BLOCKCNT,
+ fs->dblist,
+ cd->list_offset + cd->ra_entries / 8,
+ cd->ra_entries);
+ if (err)
+ cd->ra_entries = 0;
+ cd->next_ra_off = cd->list_offset + (cd->ra_entries * 7 / 8);
}
- return ext2fs_dirhash(version, buf, buf_len,
- fs->super->s_hash_seed,
- ret_hash, ret_minor_hash);
+
+ err = check_dir_block(fs, db, priv_data);
+ cd->list_offset++;
+ return err;
}
static int check_dir_block(ext2_filsys fs,
void *priv_data)
{
struct dx_dir_info *dx_dir;
-#ifdef ENABLE_HTREE
struct dx_dirblock_info *dx_db = 0;
-#endif /* ENABLE_HTREE */
struct ext2_dir_entry *dirent, *prev, dot, dotdot;
ext2_dirhash_t hash;
unsigned int offset = 0;
ibuf = buf = cd->buf;
ctx = cd->ctx;
- if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART)
+ if (ctx->flags & E2F_FLAG_RUN_RETURN)
return DIRENT_ABORT;
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)) {
+ if (ext2fs_has_feature_metadata_csum(fs->super)) {
dx_csum_size = sizeof(struct ext2_dx_tail);
de_csum_size = sizeof(struct ext2_dir_entry_tail);
}
- if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
- EXT2_FEATURE_INCOMPAT_FILETYPE))
+ if (ext2fs_has_feature_filetype(fs->super))
filetype = EXT2_FT_DIR << 8;
/*
cd->pctx.dirent = 0;
cd->pctx.num = 0;
- if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
- EXT4_FEATURE_INCOMPAT_INLINE_DATA)) {
+ if (ext2fs_has_feature_inline_data(fs->super)) {
errcode_t ec;
ec = ext2fs_inline_data_size(fs, ino, &inline_data_size);
memcpy(buf, buf2, fs->blocksize);
ext2fs_free_mem(&buf2);
}
-#ifdef ENABLE_HTREE
dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
if (dx_dir && dx_dir->numblocks) {
if (db->blockcnt >= dx_dir->numblocks) {
((fs->blocksize - (8 + dx_csum_size)) /
sizeof(struct ext2_dx_entry))))
dx_db->type = DX_DIRBLOCK_NODE;
- is_leaf = 0;
+ is_leaf = (dx_db->type == DX_DIRBLOCK_LEAF);
}
out_htree:
-#endif /* ENABLE_HTREE */
/* Leaf node with no space for csum? Rebuild dirs in pass 3A. */
if (is_leaf && !inline_data_size && failed_csum &&
}
}
- if (!encrypted && check_name(ctx, dirent, ino, &cd->pctx))
+ if (!encrypted && check_name(ctx, dirent, &cd->pctx))
dir_modified++;
+ if (encrypted && (dot_state) > 1 &&
+ encrypted_check_name(ctx, dirent, &cd->pctx)) {
+ dir_modified++;
+ goto next;
+ }
+
if (check_filetype(ctx, dirent, ino, &cd->pctx))
dir_modified++;
-#ifdef ENABLE_HTREE
if (dx_db) {
- get_filename_hash(fs, encrypted, dx_dir->hashversion,
- dirent->name,
- ext2fs_dirent_name_len(dirent),
- &hash, 0);
+ ext2fs_dirhash(dx_dir->hashversion, dirent->name,
+ ext2fs_dirent_name_len(dirent),
+ fs->super->s_hash_seed, &hash, 0);
if (hash < dx_db->min_hash)
dx_db->min_hash = hash;
if (hash > dx_db->max_hash)
dx_db->max_hash = hash;
}
-#endif
/*
* If this is a directory, then mark its parent in its
#if 0
printf("\n");
#endif
-#ifdef ENABLE_HTREE
if (dx_db) {
#ifdef DX_DEBUG
printf("db_block %d, type %d, min_hash 0x%0x, max_hash 0x%0x\n",
(dx_db->type == DX_DIRBLOCK_NODE))
parse_int_node(fs, db, cd, dx_dir, buf, failed_csum);
}
-#endif /* ENABLE_HTREE */
if (offset != max_block_size) {
cd->pctx.num = rec_len + offset - max_block_size;
if (dir_modified) {
int flags, will_rehash;
/* leaf block with no tail? Rehash dirs later. */
- if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+ if (ext2fs_has_feature_metadata_csum(fs->super) &&
is_leaf &&
!inline_data_size &&
!ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf)) {
{
struct del_block *p = priv_data;
- if (HOLE_BLKADDR(*block_nr))
+ if (*block_nr == 0)
return 0;
if ((*block_nr < fs->super->s_first_data_block) ||
(*block_nr >= ext2fs_blocks_count(fs->super)))
ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
if (ext2fs_file_acl_block(fs, &inode) &&
- (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
+ ext2fs_has_feature_xattr(fs->super)) {
pctx.errcode = ext2fs_adjust_ea_refcount3(fs,
ext2fs_file_acl_block(fs, &inode),
block_buf, -1, &count, ino);
pctx.inode = &inode;
if (ext2fs_file_acl_block(fs, &inode) &&
- !(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
+ !ext2fs_has_feature_xattr(fs->super)) {
if (fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) {
ext2fs_file_acl_block_set(fs, &inode, 0);
inode_modified++;
}
if ((fs->super->s_creator_os == EXT2_OS_LINUX) &&
- !(fs->super->s_feature_ro_compat &
- EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
+ !ext2fs_has_feature_huge_file(fs->super) &&
(inode.osd2.linux2.l_i_blocks_hi != 0)) {
pctx.num = inode.osd2.linux2.l_i_blocks_hi;
if (fix_problem(ctx, PR_2_BLOCKS_HI_ZERO, &pctx)) {
}
if ((fs->super->s_creator_os == EXT2_OS_LINUX) &&
- !(fs->super->s_feature_incompat &
- EXT4_FEATURE_INCOMPAT_64BIT) &&
+ !ext2fs_has_feature_64bit(fs->super) &&
inode.osd2.linux2.l_i_file_acl_high != 0) {
pctx.num = inode.osd2.linux2.l_i_file_acl_high;
if (fix_problem(ctx, PR_2_I_FILE_ACL_HI_ZERO, &pctx)) {