mirror of https://github.com/vitalif/e2fsprogs
libext2fs: add checksums to the end of directory leaf nodes
Introduce small structures for recording directory tree checksums, and some API changes to support writing out directory blocks with checksums. Signed-off-by: Darrick J. Wong <djwong@us.ibm.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>pu
parent
07307114de
commit
81683c6a32
|
@ -44,6 +44,11 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
|
||||||
ext2_dirhash_t hash, minor_hash;
|
ext2_dirhash_t hash, minor_hash;
|
||||||
unsigned int rec_len;
|
unsigned int rec_len;
|
||||||
int hash_alg;
|
int hash_alg;
|
||||||
|
int csum_size = 0;
|
||||||
|
|
||||||
|
if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
|
||||||
|
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
|
||||||
|
csum_size = sizeof(struct ext2_dir_entry_tail);
|
||||||
|
|
||||||
errcode = ext2fs_bmap2(fs, ino, inode, buf, 0, blk, 0, &pblk);
|
errcode = ext2fs_bmap2(fs, ino, inode, buf, 0, blk, 0, &pblk);
|
||||||
if (errcode) {
|
if (errcode) {
|
||||||
|
@ -53,7 +58,7 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Reading directory block %llu, phys %llu\n", blk, pblk);
|
printf("Reading directory block %llu, phys %llu\n", blk, pblk);
|
||||||
errcode = ext2fs_read_dir_block2(current_fs, pblk, buf, 0);
|
errcode = ext2fs_read_dir_block4(current_fs, pblk, buf, 0, ino);
|
||||||
if (errcode) {
|
if (errcode) {
|
||||||
com_err("htree_dump_leaf_node", errcode,
|
com_err("htree_dump_leaf_node", errcode,
|
||||||
"while reading block %llu (%llu)\n",
|
"while reading block %llu (%llu)\n",
|
||||||
|
@ -65,7 +70,7 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
|
||||||
(fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH))
|
(fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH))
|
||||||
hash_alg += 3;
|
hash_alg += 3;
|
||||||
|
|
||||||
while (offset < fs->blocksize) {
|
while (offset < (fs->blocksize - csum_size)) {
|
||||||
dirent = (struct ext2_dir_entry *) (buf + offset);
|
dirent = (struct ext2_dir_entry *) (buf + offset);
|
||||||
errcode = ext2fs_get_rec_len(fs, dirent, &rec_len);
|
errcode = ext2fs_get_rec_len(fs, dirent, &rec_len);
|
||||||
if (errcode) {
|
if (errcode) {
|
||||||
|
|
|
@ -474,7 +474,7 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
|
||||||
|
|
||||||
/* read the first block */
|
/* read the first block */
|
||||||
ehandler_operation(_("reading directory 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);
|
ehandler_operation(0);
|
||||||
if (retval)
|
if (retval)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -754,6 +754,7 @@ static int check_dir_block(ext2_filsys fs,
|
||||||
int dups_found = 0;
|
int dups_found = 0;
|
||||||
int ret;
|
int ret;
|
||||||
int dx_csum_size = 0;
|
int dx_csum_size = 0;
|
||||||
|
int failed_csum = 0;
|
||||||
|
|
||||||
cd = (struct check_dir_struct *) priv_data;
|
cd = (struct check_dir_struct *) priv_data;
|
||||||
buf = cd->buf;
|
buf = cd->buf;
|
||||||
|
@ -804,10 +805,14 @@ static int check_dir_block(ext2_filsys fs,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ehandler_operation(_("reading directory block"));
|
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);
|
ehandler_operation(0);
|
||||||
if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
|
if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
|
||||||
cd->pctx.errcode = 0; /* We'll handle this ourselves */
|
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) {
|
if (cd->pctx.errcode) {
|
||||||
if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
|
if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
|
||||||
ctx->flags |= E2F_FLAG_ABORT;
|
ctx->flags |= E2F_FLAG_ABORT;
|
||||||
|
@ -1145,7 +1150,7 @@ out_htree:
|
||||||
cd->pctx.dir = cd->pctx.ino;
|
cd->pctx.dir = cd->pctx.ino;
|
||||||
if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
|
if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
|
||||||
(dx_db->type == DX_DIRBLOCK_NODE))
|
(dx_db->type == DX_DIRBLOCK_NODE))
|
||||||
parse_int_node(fs, db, cd, dx_dir, buf, 0);
|
parse_int_node(fs, db, cd, dx_dir, buf, failed_csum);
|
||||||
}
|
}
|
||||||
#endif /* ENABLE_HTREE */
|
#endif /* ENABLE_HTREE */
|
||||||
if (offset != fs->blocksize) {
|
if (offset != fs->blocksize) {
|
||||||
|
@ -1156,7 +1161,8 @@ out_htree:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dir_modified) {
|
if (dir_modified) {
|
||||||
cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf);
|
cd->pctx.errcode = ext2fs_write_dir_block4(fs, block_nr, buf,
|
||||||
|
0, ino);
|
||||||
if (cd->pctx.errcode) {
|
if (cd->pctx.errcode) {
|
||||||
if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
|
if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
|
||||||
&cd->pctx))
|
&cd->pctx))
|
||||||
|
@ -1476,7 +1482,7 @@ static int allocate_dir_block(e2fsck_t ctx,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pctx->errcode = ext2fs_write_dir_block(fs, blk, block);
|
pctx->errcode = ext2fs_write_dir_block4(fs, blk, block, 0, db->ino);
|
||||||
ext2fs_free_mem(&block);
|
ext2fs_free_mem(&block);
|
||||||
if (pctx->errcode) {
|
if (pctx->errcode) {
|
||||||
pctx->str = "ext2fs_write_dir_block";
|
pctx->str = "ext2fs_write_dir_block";
|
||||||
|
|
|
@ -198,7 +198,8 @@ static void check_root(e2fsck_t ctx)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pctx.errcode = ext2fs_write_dir_block(fs, blk, block);
|
pctx.errcode = ext2fs_write_dir_block4(fs, blk, block, 0,
|
||||||
|
EXT2_ROOT_INO);
|
||||||
if (pctx.errcode) {
|
if (pctx.errcode) {
|
||||||
pctx.str = "ext2fs_write_dir_block";
|
pctx.str = "ext2fs_write_dir_block";
|
||||||
fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
|
fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
|
||||||
|
@ -444,7 +445,7 @@ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = ext2fs_write_dir_block(fs, blk, block);
|
retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino);
|
||||||
ext2fs_free_mem(&block);
|
ext2fs_free_mem(&block);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
pctx.errcode = retval;
|
pctx.errcode = retval;
|
||||||
|
@ -685,6 +686,7 @@ struct expand_dir_struct {
|
||||||
blk64_t last_block;
|
blk64_t last_block;
|
||||||
errcode_t err;
|
errcode_t err;
|
||||||
e2fsck_t ctx;
|
e2fsck_t ctx;
|
||||||
|
ext2_ino_t dir;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int expand_dir_proc(ext2_filsys fs,
|
static int expand_dir_proc(ext2_filsys fs,
|
||||||
|
@ -725,7 +727,8 @@ static int expand_dir_proc(ext2_filsys fs,
|
||||||
return BLOCK_ABORT;
|
return BLOCK_ABORT;
|
||||||
}
|
}
|
||||||
es->num--;
|
es->num--;
|
||||||
retval = ext2fs_write_dir_block(fs, new_blk, block);
|
retval = ext2fs_write_dir_block4(fs, new_blk, block, 0,
|
||||||
|
es->dir);
|
||||||
} else {
|
} else {
|
||||||
retval = ext2fs_get_mem(fs->blocksize, &block);
|
retval = ext2fs_get_mem(fs->blocksize, &block);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
|
@ -778,6 +781,7 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
|
||||||
es.err = 0;
|
es.err = 0;
|
||||||
es.newblocks = 0;
|
es.newblocks = 0;
|
||||||
es.ctx = ctx;
|
es.ctx = ctx;
|
||||||
|
es.dir = dir;
|
||||||
|
|
||||||
retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
|
retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
|
||||||
0, expand_dir_proc, &es);
|
0, expand_dir_proc, &es);
|
||||||
|
|
|
@ -81,6 +81,7 @@ struct fill_dir_struct {
|
||||||
int dir_size;
|
int dir_size;
|
||||||
int compress;
|
int compress;
|
||||||
ino_t parent;
|
ino_t parent;
|
||||||
|
ext2_ino_t dir;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hash_entry {
|
struct hash_entry {
|
||||||
|
@ -125,7 +126,10 @@ static int fill_dir_block(ext2_filsys fs,
|
||||||
dirent = (struct ext2_dir_entry *) dir;
|
dirent = (struct ext2_dir_entry *) dir;
|
||||||
(void) ext2fs_set_rec_len(fs, fs->blocksize, dirent);
|
(void) ext2fs_set_rec_len(fs, fs->blocksize, dirent);
|
||||||
} else {
|
} 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)
|
if (fd->err)
|
||||||
return BLOCK_ABORT;
|
return BLOCK_ABORT;
|
||||||
}
|
}
|
||||||
|
@ -416,7 +420,8 @@ static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs,
|
||||||
|
|
||||||
static errcode_t copy_dir_entries(e2fsck_t ctx,
|
static errcode_t copy_dir_entries(e2fsck_t ctx,
|
||||||
struct fill_dir_struct *fd,
|
struct fill_dir_struct *fd,
|
||||||
struct out_dir *outdir)
|
struct out_dir *outdir,
|
||||||
|
ext2_ino_t ino)
|
||||||
{
|
{
|
||||||
ext2_filsys fs = ctx->fs;
|
ext2_filsys fs = ctx->fs;
|
||||||
errcode_t retval;
|
errcode_t retval;
|
||||||
|
@ -427,6 +432,8 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
|
||||||
int i, left;
|
int i, left;
|
||||||
ext2_dirhash_t prev_hash;
|
ext2_dirhash_t prev_hash;
|
||||||
int offset, slack;
|
int offset, slack;
|
||||||
|
int csum_size = 0;
|
||||||
|
struct ext2_dir_entry_tail *t;
|
||||||
|
|
||||||
if (ctx->htree_slack_percentage == 255) {
|
if (ctx->htree_slack_percentage == 255) {
|
||||||
profile_get_uint(ctx->profile, "options",
|
profile_get_uint(ctx->profile, "options",
|
||||||
|
@ -437,6 +444,10 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
|
||||||
ctx->htree_slack_percentage = 20;
|
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;
|
outdir->max = 0;
|
||||||
retval = alloc_size_dir(fs, outdir,
|
retval = alloc_size_dir(fs, outdir,
|
||||||
(fd->dir_size / fs->blocksize) + 2);
|
(fd->dir_size / fs->blocksize) + 2);
|
||||||
|
@ -451,9 +462,9 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
|
||||||
dirent = (struct ext2_dir_entry *) block_start;
|
dirent = (struct ext2_dir_entry *) block_start;
|
||||||
prev_rec_len = 0;
|
prev_rec_len = 0;
|
||||||
rec_len = 0;
|
rec_len = 0;
|
||||||
left = fs->blocksize;
|
left = fs->blocksize - csum_size;
|
||||||
slack = fd->compress ? 12 :
|
slack = fd->compress ? 12 :
|
||||||
(fs->blocksize * ctx->htree_slack_percentage)/100;
|
((fs->blocksize - csum_size) * ctx->htree_slack_percentage)/100;
|
||||||
if (slack < 12)
|
if (slack < 12)
|
||||||
slack = 12;
|
slack = 12;
|
||||||
for (i = 0; i < fd->num_array; i++) {
|
for (i = 0; i < fd->num_array; i++) {
|
||||||
|
@ -468,12 +479,17 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
|
||||||
if (retval)
|
if (retval)
|
||||||
return 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,
|
if ((retval = get_next_block(fs, outdir,
|
||||||
&block_start)))
|
&block_start)))
|
||||||
return retval;
|
return retval;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
left = fs->blocksize - offset;
|
left = (fs->blocksize - csum_size) - offset;
|
||||||
dirent = (struct ext2_dir_entry *) (block_start + offset);
|
dirent = (struct ext2_dir_entry *) (block_start + offset);
|
||||||
if (offset == 0) {
|
if (offset == 0) {
|
||||||
if (ent->hash == prev_hash)
|
if (ent->hash == prev_hash)
|
||||||
|
@ -502,6 +518,10 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
|
||||||
}
|
}
|
||||||
if (left)
|
if (left)
|
||||||
retval = ext2fs_set_rec_len(fs, rec_len + left, dirent);
|
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;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -659,6 +679,7 @@ struct write_dir_struct {
|
||||||
errcode_t err;
|
errcode_t err;
|
||||||
e2fsck_t ctx;
|
e2fsck_t ctx;
|
||||||
int cleared;
|
int cleared;
|
||||||
|
ext2_ino_t dir;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -690,7 +711,7 @@ static int write_dir_block(ext2_filsys fs,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
dir = wd->outdir->buf + (blockcnt * fs->blocksize);
|
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 (wd->err)
|
if (wd->err)
|
||||||
return BLOCK_ABORT;
|
return BLOCK_ABORT;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -712,6 +733,7 @@ static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs,
|
||||||
wd.err = 0;
|
wd.err = 0;
|
||||||
wd.ctx = ctx;
|
wd.ctx = ctx;
|
||||||
wd.cleared = 0;
|
wd.cleared = 0;
|
||||||
|
wd.dir = ino;
|
||||||
|
|
||||||
retval = ext2fs_block_iterate3(fs, ino, 0, 0,
|
retval = ext2fs_block_iterate3(fs, ino, 0, 0,
|
||||||
write_dir_block, &wd);
|
write_dir_block, &wd);
|
||||||
|
@ -764,6 +786,7 @@ errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
|
||||||
fd.err = 0;
|
fd.err = 0;
|
||||||
fd.dir_size = 0;
|
fd.dir_size = 0;
|
||||||
fd.compress = 0;
|
fd.compress = 0;
|
||||||
|
fd.dir = ino;
|
||||||
if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ||
|
if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ||
|
||||||
(inode.i_size / fs->blocksize) < 2)
|
(inode.i_size / fs->blocksize) < 2)
|
||||||
fd.compress = 1;
|
fd.compress = 1;
|
||||||
|
@ -823,7 +846,7 @@ resort:
|
||||||
* Copy the directory entries. In a htree directory these
|
* Copy the directory entries. In a htree directory these
|
||||||
* will become the leaf nodes.
|
* will become the leaf nodes.
|
||||||
*/
|
*/
|
||||||
retval = copy_dir_entries(ctx, &fd, &outdir);
|
retval = copy_dir_entries(ctx, &fd, &outdir, ino);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto errout;
|
goto errout;
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,122 @@ errcode_t ext2fs_get_dx_countlimit(ext2_filsys fs,
|
||||||
return __get_dx_countlimit(fs, dirent, cc, offset, 0);
|
return __get_dx_countlimit(fs, dirent, cc, offset, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ext2fs_initialize_dirent_tail(ext2_filsys fs,
|
||||||
|
struct ext2_dir_entry_tail *t)
|
||||||
|
{
|
||||||
|
memset(t, 0, sizeof(struct ext2_dir_entry_tail));
|
||||||
|
ext2fs_set_rec_len(fs, sizeof(struct ext2_dir_entry_tail),
|
||||||
|
(struct ext2_dir_entry *)t);
|
||||||
|
t->det_reserved_name_len = EXT2_DIR_NAME_LEN_CSUM;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcode_t __get_dirent_tail(ext2_filsys fs,
|
||||||
|
struct ext2_dir_entry *dirent,
|
||||||
|
struct ext2_dir_entry_tail **tt,
|
||||||
|
int need_swab)
|
||||||
|
{
|
||||||
|
struct ext2_dir_entry *d;
|
||||||
|
void *top;
|
||||||
|
struct ext2_dir_entry_tail *t;
|
||||||
|
unsigned int rec_len;
|
||||||
|
errcode_t retval = 0;
|
||||||
|
__u16 (*translate)(__u16) = (need_swab ? disk_to_host16 : do_nothing16);
|
||||||
|
|
||||||
|
d = dirent;
|
||||||
|
top = EXT2_DIRENT_TAIL(dirent, fs->blocksize);
|
||||||
|
|
||||||
|
rec_len = translate(d->rec_len);
|
||||||
|
while (rec_len && !(rec_len & 0x3)) {
|
||||||
|
d = (struct ext2_dir_entry *)(((void *)d) + rec_len);
|
||||||
|
if ((void *)d >= top)
|
||||||
|
break;
|
||||||
|
rec_len = translate(d->rec_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d != top)
|
||||||
|
return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
|
||||||
|
|
||||||
|
t = (struct ext2_dir_entry_tail *)d;
|
||||||
|
if (t->det_reserved_zero1 ||
|
||||||
|
translate(t->det_rec_len) != sizeof(struct ext2_dir_entry_tail) ||
|
||||||
|
translate(t->det_reserved_name_len) != EXT2_DIR_NAME_LEN_CSUM)
|
||||||
|
return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
|
||||||
|
|
||||||
|
if (tt)
|
||||||
|
*tt = t;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ext2fs_dirent_has_tail(ext2_filsys fs, struct ext2_dir_entry *dirent)
|
||||||
|
{
|
||||||
|
return __get_dirent_tail(fs, dirent, NULL, 0) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcode_t ext2fs_dirent_csum(ext2_filsys fs, ext2_ino_t inum,
|
||||||
|
struct ext2_dir_entry *dirent, __u32 *crc,
|
||||||
|
int size)
|
||||||
|
{
|
||||||
|
errcode_t retval;
|
||||||
|
char *buf = (char *)dirent;
|
||||||
|
__u32 gen;
|
||||||
|
struct ext2_inode inode;
|
||||||
|
|
||||||
|
retval = ext2fs_read_inode(fs, inum, &inode);
|
||||||
|
if (retval)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
inum = ext2fs_cpu_to_le32(inum);
|
||||||
|
gen = ext2fs_cpu_to_le32(inode.i_generation);
|
||||||
|
*crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum,
|
||||||
|
sizeof(inum));
|
||||||
|
*crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen));
|
||||||
|
*crc = ext2fs_crc32c_le(*crc, (unsigned char *)buf, size);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ext2fs_dirent_csum_verify(ext2_filsys fs, ext2_ino_t inum,
|
||||||
|
struct ext2_dir_entry *dirent)
|
||||||
|
{
|
||||||
|
errcode_t retval;
|
||||||
|
__u32 calculated;
|
||||||
|
struct ext2_dir_entry_tail *t;
|
||||||
|
|
||||||
|
retval = __get_dirent_tail(fs, dirent, &t, 1);
|
||||||
|
if (retval)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The checksum field is overlaid with the dirent->name field
|
||||||
|
* so the swapfs.c functions won't change the endianness.
|
||||||
|
*/
|
||||||
|
retval = ext2fs_dirent_csum(fs, inum, dirent, &calculated,
|
||||||
|
(void *)t - (void *)dirent);
|
||||||
|
if (retval)
|
||||||
|
return 0;
|
||||||
|
return ext2fs_le32_to_cpu(t->det_checksum) == calculated;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcode_t ext2fs_dirent_csum_set(ext2_filsys fs, ext2_ino_t inum,
|
||||||
|
struct ext2_dir_entry *dirent)
|
||||||
|
{
|
||||||
|
errcode_t retval;
|
||||||
|
__u32 crc;
|
||||||
|
struct ext2_dir_entry_tail *t;
|
||||||
|
|
||||||
|
retval = __get_dirent_tail(fs, dirent, &t, 1);
|
||||||
|
if (retval)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* swapfs.c functions don't change the checksum endianness */
|
||||||
|
retval = ext2fs_dirent_csum(fs, inum, dirent, &crc,
|
||||||
|
(void *)t - (void *)dirent);
|
||||||
|
if (retval)
|
||||||
|
return retval;
|
||||||
|
t->det_checksum = ext2fs_cpu_to_le32(crc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static errcode_t ext2fs_dx_csum(ext2_filsys fs, ext2_ino_t inum,
|
static errcode_t ext2fs_dx_csum(ext2_filsys fs, ext2_ino_t inum,
|
||||||
struct ext2_dir_entry *dirent,
|
struct ext2_dir_entry *dirent,
|
||||||
__u32 *crc, int count_offset, int count,
|
__u32 *crc, int count_offset, int count,
|
||||||
|
@ -179,6 +295,38 @@ static errcode_t ext2fs_dx_csum_set(ext2_filsys fs, ext2_ino_t inum,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ext2fs_dir_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
|
||||||
|
struct ext2_dir_entry *dirent)
|
||||||
|
{
|
||||||
|
if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
|
||||||
|
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (__get_dirent_tail(fs, dirent, NULL, 1) == 0)
|
||||||
|
return ext2fs_dirent_csum_verify(fs, inum, dirent);
|
||||||
|
if (__get_dx_countlimit(fs, dirent, NULL, NULL, 1) == 0)
|
||||||
|
return ext2fs_dx_csum_verify(fs, inum, dirent);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
errcode_t ext2fs_dir_block_csum_set(ext2_filsys fs, ext2_ino_t inum,
|
||||||
|
struct ext2_dir_entry *dirent)
|
||||||
|
{
|
||||||
|
if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
|
||||||
|
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (__get_dirent_tail(fs, dirent, NULL, 1) == 0)
|
||||||
|
return ext2fs_dirent_csum_set(fs, inum, dirent);
|
||||||
|
if (__get_dx_countlimit(fs, dirent, NULL, NULL, 1) == 0)
|
||||||
|
return ext2fs_dx_csum_set(fs, inum, dirent);
|
||||||
|
|
||||||
|
if (fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS)
|
||||||
|
return 0;
|
||||||
|
return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
|
||||||
|
}
|
||||||
|
|
||||||
#define EXT3_EXTENT_TAIL_OFFSET(hdr) (sizeof(struct ext3_extent_header) + \
|
#define EXT3_EXTENT_TAIL_OFFSET(hdr) (sizeof(struct ext3_extent_header) + \
|
||||||
(sizeof(struct ext3_extent) * ext2fs_le16_to_cpu((hdr)->eh_max)))
|
(sizeof(struct ext3_extent) * ext2fs_le16_to_cpu((hdr)->eh_max)))
|
||||||
|
|
||||||
|
|
|
@ -192,17 +192,23 @@ int ext2fs_process_dir_block(ext2_filsys fs,
|
||||||
unsigned int rec_len, size;
|
unsigned int rec_len, size;
|
||||||
int entry;
|
int entry;
|
||||||
struct ext2_dir_entry *dirent;
|
struct ext2_dir_entry *dirent;
|
||||||
|
int csum_size = 0;
|
||||||
|
|
||||||
if (blockcnt < 0)
|
if (blockcnt < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE;
|
entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE;
|
||||||
|
|
||||||
ctx->errcode = ext2fs_read_dir_block3(fs, *blocknr, ctx->buf, 0);
|
ctx->errcode = ext2fs_read_dir_block4(fs, *blocknr, ctx->buf, 0,
|
||||||
|
ctx->dir);
|
||||||
if (ctx->errcode)
|
if (ctx->errcode)
|
||||||
return BLOCK_ABORT;
|
return BLOCK_ABORT;
|
||||||
|
|
||||||
while (offset < fs->blocksize) {
|
if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
|
||||||
|
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
|
||||||
|
csum_size = sizeof(struct ext2_dir_entry_tail);
|
||||||
|
|
||||||
|
while (offset < (fs->blocksize - csum_size)) {
|
||||||
dirent = (struct ext2_dir_entry *) (ctx->buf + offset);
|
dirent = (struct ext2_dir_entry *) (ctx->buf + offset);
|
||||||
if (ext2fs_get_rec_len(fs, dirent, &rec_len))
|
if (ext2fs_get_rec_len(fs, dirent, &rec_len))
|
||||||
return BLOCK_ABORT;
|
return BLOCK_ABORT;
|
||||||
|
@ -259,8 +265,8 @@ next:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
ctx->errcode = ext2fs_write_dir_block3(fs, *blocknr, ctx->buf,
|
ctx->errcode = ext2fs_write_dir_block4(fs, *blocknr, ctx->buf,
|
||||||
0);
|
0, ctx->dir);
|
||||||
if (ctx->errcode)
|
if (ctx->errcode)
|
||||||
return BLOCK_ABORT;
|
return BLOCK_ABORT;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,45 +20,36 @@
|
||||||
#include "ext2_fs.h"
|
#include "ext2_fs.h"
|
||||||
#include "ext2fs.h"
|
#include "ext2fs.h"
|
||||||
|
|
||||||
errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block,
|
errcode_t ext2fs_read_dir_block4(ext2_filsys fs, blk64_t block,
|
||||||
void *buf, int flags EXT2FS_ATTR((unused)))
|
void *buf, int flags EXT2FS_ATTR((unused)),
|
||||||
|
ext2_ino_t ino)
|
||||||
{
|
{
|
||||||
errcode_t retval;
|
errcode_t retval;
|
||||||
char *p, *end;
|
int corrupt = 0;
|
||||||
struct ext2_dir_entry *dirent;
|
|
||||||
unsigned int name_len, rec_len;
|
|
||||||
|
|
||||||
|
|
||||||
retval = io_channel_read_blk64(fs->io, block, 1, buf);
|
retval = io_channel_read_blk64(fs->io, block, 1, buf);
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
p = (char *) buf;
|
if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
|
||||||
end = (char *) buf + fs->blocksize;
|
!ext2fs_dir_block_csum_verify(fs, ino,
|
||||||
while (p < end-8) {
|
(struct ext2_dir_entry *)buf))
|
||||||
dirent = (struct ext2_dir_entry *) p;
|
corrupt = 1;
|
||||||
|
|
||||||
#ifdef WORDS_BIGENDIAN
|
#ifdef WORDS_BIGENDIAN
|
||||||
dirent->inode = ext2fs_swab32(dirent->inode);
|
retval = ext2fs_dirent_swab_in(fs, buf, flags);
|
||||||
dirent->rec_len = ext2fs_swab16(dirent->rec_len);
|
|
||||||
dirent->name_len = ext2fs_swab16(dirent->name_len);
|
|
||||||
#endif
|
#endif
|
||||||
name_len = dirent->name_len;
|
if (!retval && corrupt)
|
||||||
#ifdef WORDS_BIGENDIAN
|
retval = EXT2_ET_DIR_CSUM_INVALID;
|
||||||
if (flags & EXT2_DIRBLOCK_V2_STRUCT)
|
|
||||||
dirent->name_len = ext2fs_swab16(dirent->name_len);
|
|
||||||
#endif
|
|
||||||
if ((retval = ext2fs_get_rec_len(fs, dirent, &rec_len)) != 0)
|
|
||||||
return retval;
|
|
||||||
if ((rec_len < 8) || (rec_len % 4)) {
|
|
||||||
rec_len = 8;
|
|
||||||
retval = EXT2_ET_DIR_CORRUPTED;
|
|
||||||
} else if (((name_len & 0xFF) + 8) > rec_len)
|
|
||||||
retval = EXT2_ET_DIR_CORRUPTED;
|
|
||||||
p += rec_len;
|
|
||||||
}
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block,
|
||||||
|
void *buf, int flags EXT2FS_ATTR((unused)))
|
||||||
|
{
|
||||||
|
return ext2fs_read_dir_block4(fs, block, buf, flags, 0);
|
||||||
|
}
|
||||||
|
|
||||||
errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
|
errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
|
||||||
void *buf, int flags EXT2FS_ATTR((unused)))
|
void *buf, int flags EXT2FS_ATTR((unused)))
|
||||||
{
|
{
|
||||||
|
@ -72,45 +63,40 @@ errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block,
|
errcode_t ext2fs_write_dir_block4(ext2_filsys fs, blk64_t block,
|
||||||
void *inbuf, int flags EXT2FS_ATTR((unused)))
|
void *inbuf, int flags EXT2FS_ATTR((unused)),
|
||||||
|
ext2_ino_t ino)
|
||||||
{
|
{
|
||||||
#ifdef WORDS_BIGENDIAN
|
|
||||||
errcode_t retval;
|
errcode_t retval;
|
||||||
char *p, *end;
|
char *buf = inbuf;
|
||||||
char *buf = 0;
|
|
||||||
unsigned int rec_len;
|
|
||||||
struct ext2_dir_entry *dirent;
|
|
||||||
|
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
retval = ext2fs_get_mem(fs->blocksize, &buf);
|
retval = ext2fs_get_mem(fs->blocksize, &buf);
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
memcpy(buf, inbuf, fs->blocksize);
|
memcpy(buf, inbuf, fs->blocksize);
|
||||||
p = buf;
|
retval = ext2fs_dirent_swab_out(fs, buf, flags);
|
||||||
end = buf + fs->blocksize;
|
if (retval)
|
||||||
while (p < end) {
|
return retval;
|
||||||
dirent = (struct ext2_dir_entry *) p;
|
|
||||||
if ((retval = ext2fs_get_rec_len(fs, dirent, &rec_len)) != 0)
|
|
||||||
return retval;
|
|
||||||
if ((rec_len < 8) ||
|
|
||||||
(rec_len % 4)) {
|
|
||||||
ext2fs_free_mem(&buf);
|
|
||||||
return (EXT2_ET_DIR_CORRUPTED);
|
|
||||||
}
|
|
||||||
p += rec_len;
|
|
||||||
dirent->inode = ext2fs_swab32(dirent->inode);
|
|
||||||
dirent->rec_len = ext2fs_swab16(dirent->rec_len);
|
|
||||||
dirent->name_len = ext2fs_swab16(dirent->name_len);
|
|
||||||
|
|
||||||
if (flags & EXT2_DIRBLOCK_V2_STRUCT)
|
|
||||||
dirent->name_len = ext2fs_swab16(dirent->name_len);
|
|
||||||
}
|
|
||||||
retval = io_channel_write_blk64(fs->io, block, 1, buf);
|
|
||||||
ext2fs_free_mem(&buf);
|
|
||||||
return retval;
|
|
||||||
#else
|
|
||||||
return io_channel_write_blk64(fs->io, block, 1, (char *) inbuf);
|
|
||||||
#endif
|
#endif
|
||||||
|
retval = ext2fs_dir_block_csum_set(fs, ino,
|
||||||
|
(struct ext2_dir_entry *)buf);
|
||||||
|
if (retval)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
retval = io_channel_write_blk64(fs->io, block, 1, buf);
|
||||||
|
|
||||||
|
out:
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
ext2fs_free_mem(&buf);
|
||||||
|
#endif
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block,
|
||||||
|
void *inbuf, int flags EXT2FS_ATTR((unused)))
|
||||||
|
{
|
||||||
|
return ext2fs_write_dir_block4(fs, block, inbuf, flags, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
|
errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
|
||||||
|
|
|
@ -24,6 +24,7 @@ struct expand_dir_struct {
|
||||||
int newblocks;
|
int newblocks;
|
||||||
blk64_t goal;
|
blk64_t goal;
|
||||||
errcode_t err;
|
errcode_t err;
|
||||||
|
ext2_ino_t dir;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int expand_dir_proc(ext2_filsys fs,
|
static int expand_dir_proc(ext2_filsys fs,
|
||||||
|
@ -62,7 +63,8 @@ static int expand_dir_proc(ext2_filsys fs,
|
||||||
return BLOCK_ABORT;
|
return BLOCK_ABORT;
|
||||||
}
|
}
|
||||||
es->done = 1;
|
es->done = 1;
|
||||||
retval = ext2fs_write_dir_block(fs, new_blk, block);
|
retval = ext2fs_write_dir_block4(fs, new_blk, block, 0,
|
||||||
|
es->dir);
|
||||||
} else {
|
} else {
|
||||||
retval = ext2fs_get_mem(fs->blocksize, &block);
|
retval = ext2fs_get_mem(fs->blocksize, &block);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
|
@ -110,6 +112,7 @@ errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir)
|
||||||
es.err = 0;
|
es.err = 0;
|
||||||
es.goal = 0;
|
es.goal = 0;
|
||||||
es.newblocks = 0;
|
es.newblocks = 0;
|
||||||
|
es.dir = dir;
|
||||||
|
|
||||||
retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
|
retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
|
||||||
0, expand_dir_proc, &es);
|
0, expand_dir_proc, &es);
|
||||||
|
|
|
@ -458,4 +458,7 @@ ec EXT2_ET_EXTENT_CSUM_INVALID,
|
||||||
ec EXT2_ET_DIR_NO_SPACE_FOR_CSUM,
|
ec EXT2_ET_DIR_NO_SPACE_FOR_CSUM,
|
||||||
"Directory block does not have space for checksum"
|
"Directory block does not have space for checksum"
|
||||||
|
|
||||||
|
ec EXT2_ET_DIR_CSUM_INVALID,
|
||||||
|
"Directory block checksum does not match directory block"
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -943,6 +943,18 @@ extern __u32 ext2fs_crc32c_be(__u32 crc, unsigned char const *p, size_t len);
|
||||||
extern __u32 ext2fs_crc32c_le(__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 */
|
/* csum.c */
|
||||||
|
#define EXT2_DIRENT_TAIL(block, blocksize) \
|
||||||
|
((struct ext2_dir_entry_tail *)(((void *)(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_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,
|
extern errcode_t ext2fs_get_dx_countlimit(ext2_filsys fs,
|
||||||
struct ext2_dir_entry *dirent,
|
struct ext2_dir_entry *dirent,
|
||||||
struct ext2_dx_countlimit **cc,
|
struct ext2_dx_countlimit **cc,
|
||||||
|
@ -1025,12 +1037,16 @@ extern errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
|
||||||
void *buf, int flags);
|
void *buf, int flags);
|
||||||
extern errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block,
|
extern errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block,
|
||||||
void *buf, int flags);
|
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,
|
extern errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block,
|
||||||
void *buf);
|
void *buf);
|
||||||
extern errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
|
extern errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
|
||||||
void *buf, int flags);
|
void *buf, int flags);
|
||||||
extern errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block,
|
extern errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block,
|
||||||
void *buf, int flags);
|
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 */
|
/* dirhash.c */
|
||||||
extern errcode_t ext2fs_dirhash(int version, const char *name, int len,
|
extern errcode_t ext2fs_dirhash(int version, const char *name, int len,
|
||||||
|
@ -1427,6 +1443,8 @@ extern errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f,
|
||||||
extern errcode_t ext2fs_create_resize_inode(ext2_filsys fs);
|
extern errcode_t ext2fs_create_resize_inode(ext2_filsys fs);
|
||||||
|
|
||||||
/* swapfs.c */
|
/* 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,
|
extern void ext2fs_swap_ext_attr(char *to, char *from, int bufsize,
|
||||||
int has_header);
|
int has_header);
|
||||||
extern void ext2fs_swap_ext_attr_header(struct ext2_ext_attr_header *to_header,
|
extern void ext2fs_swap_ext_attr_header(struct ext2_ext_attr_header *to_header,
|
||||||
|
|
|
@ -41,6 +41,7 @@ static int link_proc(struct ext2_dir_entry *dirent,
|
||||||
struct ext2_dir_entry *next;
|
struct ext2_dir_entry *next;
|
||||||
unsigned int rec_len, min_rec_len, curr_rec_len;
|
unsigned int rec_len, min_rec_len, curr_rec_len;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
int csum_size = 0;
|
||||||
|
|
||||||
rec_len = EXT2_DIR_REC_LEN(ls->namelen);
|
rec_len = EXT2_DIR_REC_LEN(ls->namelen);
|
||||||
|
|
||||||
|
@ -48,12 +49,15 @@ static int link_proc(struct ext2_dir_entry *dirent,
|
||||||
if (ls->err)
|
if (ls->err)
|
||||||
return DIRENT_ABORT;
|
return DIRENT_ABORT;
|
||||||
|
|
||||||
|
if (EXT2_HAS_RO_COMPAT_FEATURE(ls->fs->super,
|
||||||
|
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
|
||||||
|
csum_size = sizeof(struct ext2_dir_entry_tail);
|
||||||
/*
|
/*
|
||||||
* See if the following directory entry (if any) is unused;
|
* See if the following directory entry (if any) is unused;
|
||||||
* if so, absorb it into this one.
|
* if so, absorb it into this one.
|
||||||
*/
|
*/
|
||||||
next = (struct ext2_dir_entry *) (buf + offset + curr_rec_len);
|
next = (struct ext2_dir_entry *) (buf + offset + curr_rec_len);
|
||||||
if ((offset + (int) curr_rec_len < blocksize - 8) &&
|
if ((offset + (int) curr_rec_len < blocksize - (8 + csum_size)) &&
|
||||||
(next->inode == 0) &&
|
(next->inode == 0) &&
|
||||||
(offset + (int) curr_rec_len + (int) next->rec_len <= blocksize)) {
|
(offset + (int) curr_rec_len + (int) next->rec_len <= blocksize)) {
|
||||||
curr_rec_len += next->rec_len;
|
curr_rec_len += next->rec_len;
|
||||||
|
|
|
@ -100,7 +100,7 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
|
||||||
retval = ext2fs_write_new_inode(fs, ino, &inode);
|
retval = ext2fs_write_new_inode(fs, ino, &inode);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
retval = ext2fs_write_dir_block(fs, blk, block);
|
retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,8 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
|
||||||
char *buf;
|
char *buf;
|
||||||
int rec_len;
|
int rec_len;
|
||||||
int filetype = 0;
|
int filetype = 0;
|
||||||
|
struct ext2_dir_entry_tail *t;
|
||||||
|
int csum_size = 0;
|
||||||
|
|
||||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||||
|
|
||||||
|
@ -43,7 +45,11 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
|
||||||
memset(buf, 0, fs->blocksize);
|
memset(buf, 0, fs->blocksize);
|
||||||
dir = (struct ext2_dir_entry *) buf;
|
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)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
@ -57,7 +63,7 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
|
||||||
dir->inode = dir_ino;
|
dir->inode = dir_ino;
|
||||||
dir->name_len = 1 | filetype;
|
dir->name_len = 1 | filetype;
|
||||||
dir->name[0] = '.';
|
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->rec_len = EXT2_DIR_REC_LEN(1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -73,6 +79,11 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
|
||||||
dir->name[1] = '.';
|
dir->name[1] = '.';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (csum_size) {
|
||||||
|
t = EXT2_DIRENT_TAIL(buf, fs->blocksize);
|
||||||
|
ext2fs_initialize_dirent_tail(fs, t);
|
||||||
|
}
|
||||||
*block = buf;
|
*block = buf;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -350,4 +350,66 @@ void ext2fs_swap_mmp(struct mmp_struct *mmp)
|
||||||
mmp->mmp_check_interval = ext2fs_swab16(mmp->mmp_check_interval);
|
mmp->mmp_check_interval = ext2fs_swab16(mmp->mmp_check_interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errcode_t ext2fs_dirent_swab_in(ext2_filsys fs, char *buf, int flags)
|
||||||
|
{
|
||||||
|
errcode_t retval;
|
||||||
|
char *p, *end;
|
||||||
|
struct ext2_dir_entry *dirent;
|
||||||
|
unsigned int name_len, rec_len;
|
||||||
|
|
||||||
|
p = (char *) buf;
|
||||||
|
end = (char *) buf + fs->blocksize;
|
||||||
|
while (p < end-8) {
|
||||||
|
dirent = (struct ext2_dir_entry *) p;
|
||||||
|
dirent->inode = ext2fs_swab32(dirent->inode);
|
||||||
|
dirent->rec_len = ext2fs_swab16(dirent->rec_len);
|
||||||
|
dirent->name_len = ext2fs_swab16(dirent->name_len);
|
||||||
|
name_len = dirent->name_len;
|
||||||
|
if (flags & EXT2_DIRBLOCK_V2_STRUCT)
|
||||||
|
dirent->name_len = ext2fs_swab16(dirent->name_len);
|
||||||
|
retval = ext2fs_get_rec_len(fs, dirent, &rec_len);
|
||||||
|
if (retval)
|
||||||
|
return retval;
|
||||||
|
if ((rec_len < 8) || (rec_len % 4)) {
|
||||||
|
rec_len = 8;
|
||||||
|
retval = EXT2_ET_DIR_CORRUPTED;
|
||||||
|
} else if (((name_len & 0xFF) + 8) > rec_len)
|
||||||
|
retval = EXT2_ET_DIR_CORRUPTED;
|
||||||
|
p += rec_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
errcode_t ext2fs_dirent_swab_out(ext2_filsys fs, char *buf, int flags)
|
||||||
|
{
|
||||||
|
errcode_t retval;
|
||||||
|
char *p, *end;
|
||||||
|
unsigned int rec_len;
|
||||||
|
struct ext2_dir_entry *dirent;
|
||||||
|
|
||||||
|
p = buf;
|
||||||
|
end = buf + fs->blocksize;
|
||||||
|
while (p < end) {
|
||||||
|
dirent = (struct ext2_dir_entry *) p;
|
||||||
|
retval = ext2fs_get_rec_len(fs, dirent, &rec_len);
|
||||||
|
if (retval)
|
||||||
|
return retval;
|
||||||
|
if ((rec_len < 8) ||
|
||||||
|
(rec_len % 4)) {
|
||||||
|
ext2fs_free_mem(&buf);
|
||||||
|
return EXT2_ET_DIR_CORRUPTED;
|
||||||
|
}
|
||||||
|
p += rec_len;
|
||||||
|
dirent->inode = ext2fs_swab32(dirent->inode);
|
||||||
|
dirent->rec_len = ext2fs_swab16(dirent->rec_len);
|
||||||
|
dirent->name_len = ext2fs_swab16(dirent->name_len);
|
||||||
|
|
||||||
|
if (flags & EXT2_DIRBLOCK_V2_STRUCT)
|
||||||
|
dirent->name_len = ext2fs_swab16(dirent->name_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue