#include "e2fsck.h"
#include "problem.h"
+/* Schedule a dir to be rebuilt during pass 3A. */
+void e2fsck_rehash_dir_later(e2fsck_t ctx, ext2_ino_t ino)
+{
+ 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);
+}
+
+/* Ask if a dir will be rebuilt during pass 3A. */
+int e2fsck_dir_will_be_rehashed(e2fsck_t ctx, ext2_ino_t ino)
+{
+ if (ctx->options & E2F_OPT_COMPRESS_DIRS)
+ return 1;
+ if (!ctx->dirs_to_hash)
+ return 0;
+ return ext2fs_u32_list_test(ctx->dirs_to_hash, ino);
+}
+
struct fill_dir_struct {
char *buf;
struct ext2_inode *inode;
e2fsck_t ctx;
struct hash_entry *harray;
int max_array, num_array;
- int dir_size;
+ unsigned int dir_size;
int compress;
ino_t parent;
+ ext2_ino_t dir;
};
struct hash_entry {
dirent = (struct ext2_dir_entry *) dir;
(void) ext2fs_set_rec_len(fs, fs->blocksize, dirent);
} else {
- fd->err = ext2fs_read_dir_block3(fs, *block_nr, dir, 0);
+ fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+ fd->err = ext2fs_read_dir_block4(fs, *block_nr, dir, 0,
+ fd->dir);
+ fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
if (fd->err)
return BLOCK_ABORT;
}
if (((dir_offset + rec_len) > fs->blocksize) ||
(rec_len < 8) ||
((rec_len % 4) != 0) ||
- (((dirent->name_len & 0xFF)+8) > rec_len)) {
+ (((dirent->name_len & 0xFF)+8U) > rec_len)) {
fd->err = EXT2_ET_DIR_CORRUPTED;
return BLOCK_ABORT;
}
char *block_start;
struct hash_entry *ent;
struct ext2_dir_entry *dirent;
- unsigned int rec_len, prev_rec_len;
- int i, left;
+ unsigned int rec_len, prev_rec_len, left, slack, offset;
+ int i;
ext2_dirhash_t prev_hash;
- int offset, slack;
+ int csum_size = 0;
+ struct ext2_dir_entry_tail *t;
if (ctx->htree_slack_percentage == 255) {
profile_get_uint(ctx->profile, "options",
ctx->htree_slack_percentage = 20;
}
+ if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ csum_size = sizeof(struct ext2_dir_entry_tail);
+
outdir->max = 0;
retval = alloc_size_dir(fs, outdir,
(fd->dir_size / fs->blocksize) + 2);
dirent = (struct ext2_dir_entry *) block_start;
prev_rec_len = 0;
rec_len = 0;
- left = fs->blocksize;
+ left = fs->blocksize - csum_size;
slack = fd->compress ? 12 :
- (fs->blocksize * ctx->htree_slack_percentage)/100;
+ ((fs->blocksize - csum_size) * ctx->htree_slack_percentage)/100;
if (slack < 12)
slack = 12;
for (i = 0; i < fd->num_array; i++) {
if (retval)
return retval;
}
+ if (csum_size) {
+ t = EXT2_DIRENT_TAIL(block_start,
+ fs->blocksize);
+ ext2fs_initialize_dirent_tail(fs, t);
+ }
if ((retval = get_next_block(fs, outdir,
&block_start)))
return retval;
offset = 0;
}
- left = fs->blocksize - offset;
+ left = (fs->blocksize - csum_size) - offset;
dirent = (struct ext2_dir_entry *) (block_start + offset);
if (offset == 0) {
if (ent->hash == prev_hash)
}
if (left)
retval = ext2fs_set_rec_len(fs, rec_len + left, dirent);
+ if (csum_size) {
+ t = EXT2_DIRENT_TAIL(block_start, fs->blocksize);
+ ext2fs_initialize_dirent_tail(fs, t);
+ }
return retval;
}
struct ext2_dx_root_info *root;
struct ext2_dx_countlimit *limits;
int filetype = 0;
+ int csum_size = 0;
if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
filetype = EXT2_FT_DIR << 8;
root->indirect_levels = 0;
root->unused_flags = 0;
+ if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ csum_size = sizeof(struct ext2_dx_tail);
+
limits = (struct ext2_dx_countlimit *) (buf+32);
- limits->limit = (fs->blocksize - 32) / sizeof(struct ext2_dx_entry);
+ limits->limit = (fs->blocksize - (32 + csum_size)) /
+ sizeof(struct ext2_dx_entry);
limits->count = 0;
return root;
{
struct ext2_dir_entry *dir;
struct ext2_dx_countlimit *limits;
+ int csum_size = 0;
memset(buf, 0, fs->blocksize);
dir = (struct ext2_dir_entry *) buf;
dir->inode = 0;
(void) 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_dx_tail);
+
limits = (struct ext2_dx_countlimit *) (buf+8);
- limits->limit = (fs->blocksize - 8) / sizeof(struct ext2_dx_entry);
+ limits->limit = (fs->blocksize - (8 + csum_size)) /
+ sizeof(struct ext2_dx_entry);
limits->count = 0;
return (struct ext2_dx_entry *) limits;
errcode_t err;
e2fsck_t ctx;
int cleared;
+ ext2_ino_t dir;
};
/*
{
struct write_dir_struct *wd = (struct write_dir_struct *) priv_data;
blk64_t blk;
- char *dir;
+ char *dir, *buf = 0;
if (*block_nr == 0)
return 0;
- if (blockcnt >= wd->outdir->num) {
+ if (blockcnt < 0)
+ return 0;
+ if (blockcnt < wd->outdir->num)
+ dir = wd->outdir->buf + (blockcnt * fs->blocksize);
+ else if (wd->ctx->lost_and_found == wd->dir) {
+ /* Don't release any extra directory blocks for lost+found */
+ wd->err = ext2fs_new_dir_block(fs, 0, 0, &buf);
+ if (wd->err)
+ return BLOCK_ABORT;
+ dir = buf;
+ wd->outdir->num++;
+ } else {
+ /* We don't need this block, so release it */
e2fsck_read_bitmaps(wd->ctx);
blk = *block_nr;
ext2fs_unmark_block_bitmap2(wd->ctx->block_found_map, blk);
wd->cleared++;
return BLOCK_CHANGED;
}
- if (blockcnt < 0)
- return 0;
- dir = wd->outdir->buf + (blockcnt * fs->blocksize);
- wd->err = ext2fs_write_dir_block3(fs, *block_nr, dir, 0);
+ wd->err = ext2fs_write_dir_block4(fs, *block_nr, dir, 0, wd->dir);
+ if (buf)
+ ext2fs_free_mem(&buf);
+
if (wd->err)
return BLOCK_ABORT;
return 0;
wd.err = 0;
wd.ctx = ctx;
wd.cleared = 0;
+ wd.dir = ino;
retval = ext2fs_block_iterate3(fs, ino, 0, 0,
write_dir_block, &wd);
fd.err = 0;
fd.dir_size = 0;
fd.compress = 0;
+ fd.dir = ino;
if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ||
(inode.i_size / fs->blocksize) < 2)
fd.compress = 1;
if (!ctx->dirs_to_hash && !all_dirs)
return;
- e2fsck_get_lost_and_found(ctx, 0);
+ (void) e2fsck_get_lost_and_found(ctx, 0);
clear_problem_context(&pctx);
if (!ext2fs_u32_list_iterate(iter, &ino))
break;
}
- if (ino == ctx->lost_and_found)
- continue;
+
pctx.dir = ino;
if (first) {
fix_problem(ctx, PR_3A_PASS_HEADER, &pctx);