aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--debian/e2fslibs.symbols2
-rw-r--r--debugfs/htree.c23
-rw-r--r--e2fsck/message.c13
-rw-r--r--e2fsck/pass1.c10
-rw-r--r--e2fsck/pass2.c42
-rw-r--r--e2fsck/rehash.c37
-rw-r--r--lib/ext2fs/dir_iterate.c52
-rw-r--r--lib/ext2fs/dirblock.c10
-rw-r--r--lib/ext2fs/ext2fs.h6
-rw-r--r--lib/ext2fs/link.c27
-rw-r--r--lib/ext2fs/newdir.c9
-rw-r--r--misc/e2image.c15
-rw-r--r--tests/f_dup3/expect.14
-rw-r--r--tests/f_dupfsblks/expect.111
14 files changed, 178 insertions, 83 deletions
diff --git a/debian/e2fslibs.symbols b/debian/e2fslibs.symbols
index 4a375c9c..3ee0bca1 100644
--- a/debian/e2fslibs.symbols
+++ b/debian/e2fslibs.symbols
@@ -99,6 +99,8 @@ libext2fs.so.2 e2fslibs #MINVER#
ext2fs_dblist_sort@Base 1.37
ext2fs_default_journal_size@Base 1.40
ext2fs_descriptor_block_loc@Base 1.37
+ ext2fs_get_rec_len@Base 1.41.7
+ ext2fs_set_rec_len@Base 1.41.7
ext2fs_dir_iterate2@Base 1.37
ext2fs_dir_iterate@Base 1.37
ext2fs_dirhash@Base 1.37
diff --git a/debugfs/htree.c b/debugfs/htree.c
index afb7605d..01e4ca52 100644
--- a/debugfs/htree.c
+++ b/debugfs/htree.c
@@ -39,7 +39,8 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
char tmp[EXT2_NAME_LEN + 16];
blk_t pblk;
ext2_dirhash_t hash, minor_hash;
- int rec_len, hash_alg;
+ unsigned int rec_len;
+ int hash_alg;
errcode = ext2fs_bmap(fs, ino, inode, buf, 0, blk, &pblk);
if (errcode) {
@@ -64,8 +65,13 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
while (offset < fs->blocksize) {
dirent = (struct ext2_dir_entry *) (buf + offset);
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ errcode = ext2fs_get_rec_len(fs, dirent, &rec_len);
+ if (errcode) {
+ com_err("htree_dump_leaf_inode", errcode,
+ "while getting rec_len for block %lu",
+ (unsigned long) blk);
+ return;
+ }
if (((offset + rec_len) > fs->blocksize) ||
(rec_len < 8) ||
((rec_len % 4) != 0) ||
@@ -386,7 +392,7 @@ static int search_dir_block(ext2_filsys fs, blk_t *blocknr,
struct ext2_dir_entry *dirent;
errcode_t errcode;
unsigned int offset = 0;
- int rec_len;
+ unsigned int rec_len;
if (blockcnt < 0)
return 0;
@@ -402,8 +408,13 @@ static int search_dir_block(ext2_filsys fs, blk_t *blocknr,
while (offset < fs->blocksize) {
dirent = (struct ext2_dir_entry *) (p->buf + offset);
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ errcode = ext2fs_get_rec_len(fs, dirent, &rec_len);
+ if (errcode) {
+ com_err("htree_dump_leaf_inode", errcode,
+ "while getting rec_len for block %lu",
+ (unsigned long) *blocknr);
+ return;
+ }
if (dirent->inode &&
p->len == (dirent->name_len & 0xFF) &&
strncmp(p->search_name, dirent->name,
diff --git a/e2fsck/message.c b/e2fsck/message.c
index 5158ed64..3f859160 100644
--- a/e2fsck/message.c
+++ b/e2fsck/message.c
@@ -347,10 +347,11 @@ static _INLINE_ void expand_inode_expression(char ch,
/*
* This function expands '%dX' expressions
*/
-static _INLINE_ void expand_dirent_expression(char ch,
+static _INLINE_ void expand_dirent_expression(ext2_filsys fs, char ch,
struct problem_context *ctx)
{
struct ext2_dir_entry *dirent;
+ unsigned int rec_len;
int len;
if (!ctx || !ctx->dirent)
@@ -366,12 +367,14 @@ static _INLINE_ void expand_dirent_expression(char ch,
len = dirent->name_len & 0xFF;
if (len > EXT2_NAME_LEN)
len = EXT2_NAME_LEN;
- if (len > dirent->rec_len)
- len = dirent->rec_len;
+ if ((ext2fs_get_rec_len(fs, dirent, &rec_len) == 0) &&
+ (len > rec_len))
+ len = rec_len;
safe_print(dirent->name, len);
break;
case 'r':
- printf("%u", dirent->rec_len);
+ (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
+ printf("%u", rec_len);
break;
case 'l':
printf("%u", dirent->name_len & 0xFF);
@@ -490,7 +493,7 @@ void print_e2fsck_message(e2fsck_t ctx, const char *msg,
expand_inode_expression(*cp, pctx);
} else if (cp[0] == '%' && cp[1] == 'D') {
cp += 2;
- expand_dirent_expression(*cp, pctx);
+ expand_dirent_expression(fs, *cp, pctx);
} else if ((cp[0] == '%')) {
cp++;
expand_percent_expression(fs, *cp, pctx);
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index 46189c0d..518c2ff8 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -434,8 +434,9 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
return;
dirent = (struct ext2_dir_entry *) buf;
- rec_len = (dirent->rec_len || ctx->fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ retval = ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
+ if (retval)
+ return;
if (((dirent->name_len & 0xFF) != 1) ||
(dirent->name[0] != '.') ||
(dirent->inode != pctx->ino) ||
@@ -445,8 +446,9 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
return;
dirent = (struct ext2_dir_entry *) (buf + rec_len);
- rec_len = (dirent->rec_len || ctx->fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ retval = ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
+ if (retval)
+ return;
if (((dirent->name_len & 0xFF) != 2) ||
(dirent->name[0] != '.') ||
(dirent->name[1] != '.') ||
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index f5a326d3..bb3813cd 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -352,9 +352,9 @@ static int check_dot(e2fsck_t ctx,
ext2_ino_t ino, struct problem_context *pctx)
{
struct ext2_dir_entry *nextdir;
+ unsigned int rec_len, new_len;
int status = 0;
int created = 0;
- int rec_len, new_len;
int problem = 0;
if (!dirent->inode)
@@ -365,8 +365,7 @@ static int check_dot(e2fsck_t ctx,
else if (dirent->name[1] != '\0')
problem = PR_2_DOT_NULL_TERM;
- rec_len = (dirent->rec_len || ctx->fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ (void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
if (problem) {
if (fix_problem(ctx, problem, pctx)) {
if (rec_len < 12)
@@ -393,7 +392,8 @@ static int check_dot(e2fsck_t ctx,
nextdir = (struct ext2_dir_entry *)
((char *) dirent + 12);
dirent->rec_len = 12;
- nextdir->rec_len = new_len;
+ (void) ext2fs_set_rec_len(ctx->fs, new_len,
+ nextdir);
nextdir->inode = 0;
nextdir->name_len = 0;
status = 1;
@@ -423,8 +423,7 @@ static int check_dotdot(e2fsck_t ctx,
else if (dirent->name[2] != '\0')
problem = PR_2_DOT_DOT_NULL_TERM;
- rec_len = (dirent->rec_len || ctx->fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ (void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
if (problem) {
if (fix_problem(ctx, problem, pctx)) {
if (rec_len < 12)
@@ -647,11 +646,11 @@ static void salvage_directory(ext2_filsys fs,
unsigned int *offset)
{
char *cp = (char *) dirent;
- int left, rec_len;
+ int left;
+ unsigned int rec_len, prev_rec_len;
unsigned int name_len = dirent->name_len & 0xFF;
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
left = fs->blocksize - *offset - rec_len;
/*
@@ -669,10 +668,11 @@ static void salvage_directory(ext2_filsys fs,
* record length.
*/
if ((left < 0) &&
- (name_len + 8 <= rec_len + (unsigned) left) &&
+ ((int) rec_len + left > 8) &&
+ (name_len + 8 <= (int) rec_len + left) &&
dirent->inode <= fs->super->s_inodes_count &&
strnlen(dirent->name, name_len) == name_len) {
- dirent->rec_len += left;
+ (void) ext2fs_set_rec_len(fs, (int) rec_len + left, dirent);
return;
}
/*
@@ -682,7 +682,9 @@ static void salvage_directory(ext2_filsys fs,
*/
if (prev && rec_len && (rec_len % 4) == 0 &&
(*offset + rec_len <= fs->blocksize)) {
- prev->rec_len += rec_len;
+ (void) ext2fs_get_rec_len(fs, prev, &prev_rec_len);
+ prev_rec_len += rec_len;
+ (void) ext2fs_set_rec_len(fs, prev_rec_len, prev);
*offset += rec_len;
return;
}
@@ -693,10 +695,13 @@ static void salvage_directory(ext2_filsys fs,
* new empty directory entry the rest of the directory block.
*/
if (prev) {
- prev->rec_len += fs->blocksize - *offset;
+ (void) ext2fs_get_rec_len(fs, prev, &prev_rec_len);
+ prev_rec_len += fs->blocksize - *offset;
+ (void) ext2fs_set_rec_len(fs, prev_rec_len, prev);
*offset = fs->blocksize;
} else {
- dirent->rec_len = fs->blocksize - *offset;
+ rec_len = fs->blocksize - *offset;
+ (void) ext2fs_set_rec_len(fs, rec_len, dirent);
dirent->name_len = 0;
dirent->inode = 0;
}
@@ -808,8 +813,7 @@ static int check_dir_block(ext2_filsys fs,
dx_db->max_hash = 0;
dirent = (struct ext2_dir_entry *) buf;
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
limit = (struct ext2_dx_countlimit *) (buf+8);
if (db->blockcnt == 0) {
root = (struct ext2_dx_root_info *) (buf + 24);
@@ -847,8 +851,7 @@ out_htree:
problem = 0;
dirent = (struct ext2_dir_entry *) (buf + offset);
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
cd->pctx.dirent = dirent;
cd->pctx.num = offset;
if (((offset + rec_len) > fs->blocksize) ||
@@ -1104,8 +1107,7 @@ out_htree:
next:
prev = dirent;
if (dir_modified)
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
offset += rec_len;
dot_state++;
} while (offset < fs->blocksize);
diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
index d2dbcce1..50388f36 100644
--- a/e2fsck/rehash.c
+++ b/e2fsck/rehash.c
@@ -88,8 +88,8 @@ static int fill_dir_block(ext2_filsys fs,
struct hash_entry *new_array, *ent;
struct ext2_dir_entry *dirent;
char *dir;
- unsigned int offset, dir_offset;
- int rec_len, hash_alg;
+ unsigned int offset, dir_offset, rec_len;
+ int hash_alg;
if (blockcnt < 0)
return 0;
@@ -103,7 +103,7 @@ static int fill_dir_block(ext2_filsys fs,
if (HOLE_BLKADDR(*block_nr)) {
memset(dir, 0, fs->blocksize);
dirent = (struct ext2_dir_entry *) dir;
- dirent->rec_len = fs->blocksize;
+ (void) ext2fs_set_rec_len(fs, fs->blocksize, dirent);
} else {
fd->err = ext2fs_read_dir_block(fs, *block_nr, dir);
if (fd->err)
@@ -117,8 +117,7 @@ static int fill_dir_block(ext2_filsys fs,
dir_offset = 0;
while (dir_offset < fs->blocksize) {
dirent = (struct ext2_dir_entry *) (dir + dir_offset);
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
if (((dir_offset + rec_len) > fs->blocksize) ||
(rec_len < 8) ||
((rec_len % 4) != 0) ||
@@ -404,7 +403,8 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
char *block_start;
struct hash_entry *ent;
struct ext2_dir_entry *dirent;
- int i, rec_len, left;
+ unsigned int rec_len, prev_rec_len;
+ int i, left;
ext2_dirhash_t prev_hash;
int offset, slack;
@@ -429,6 +429,7 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
if ((retval = get_next_block(fs, outdir, &block_start)))
return retval;
dirent = (struct ext2_dir_entry *) block_start;
+ prev_rec_len = 0;
left = fs->blocksize;
slack = fd->compress ? 12 :
(fs->blocksize * ctx->htree_slack_percentage)/100;
@@ -440,8 +441,12 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
continue;
rec_len = EXT2_DIR_REC_LEN(ent->dir->name_len & 0xFF);
if (rec_len > left) {
- if (left)
- dirent->rec_len += left;
+ if (left) {
+ left += prev_rec_len;
+ retval = ext2fs_set_rec_len(fs, left, dirent);
+ if (retval)
+ return retval;
+ }
if ((retval = get_next_block(fs, outdir,
&block_start)))
return retval;
@@ -457,21 +462,27 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
}
dirent->inode = ent->dir->inode;
dirent->name_len = ent->dir->name_len;
- dirent->rec_len = rec_len;
+ retval = ext2fs_set_rec_len(fs, rec_len, dirent);
+ if (retval)
+ return retval;
+ prev_rec_len = rec_len;
memcpy(dirent->name, ent->dir->name, dirent->name_len & 0xFF);
offset += rec_len;
left -= rec_len;
if (left < slack) {
- dirent->rec_len += left;
+ prev_rec_len += left;
+ retval = ext2fs_set_rec_len(fs, prev_rec_len, dirent);
+ if (retval)
+ return retval;
offset += left;
left = 0;
}
prev_hash = ent->hash;
}
if (left)
- dirent->rec_len += left;
+ retval = ext2fs_set_rec_len(fs, rec_len + left, dirent);
- return 0;
+ return retval;
}
@@ -522,7 +533,7 @@ static struct ext2_dx_entry *set_int_node(ext2_filsys fs, char *buf)
memset(buf, 0, fs->blocksize);
dir = (struct ext2_dir_entry *) buf;
dir->inode = 0;
- dir->rec_len = fs->blocksize;
+ (void) ext2fs_set_rec_len(fs, fs->blocksize, dir);
limits = (struct ext2_dx_countlimit *) (buf+8);
limits->limit = (fs->blocksize - 8) / sizeof(struct ext2_dx_entry);
diff --git a/lib/ext2fs/dir_iterate.c b/lib/ext2fs/dir_iterate.c
index 1f8cf8ff..ac5a31e2 100644
--- a/lib/ext2fs/dir_iterate.c
+++ b/lib/ext2fs/dir_iterate.c
@@ -21,6 +21,41 @@
#include "ext2_fs.h"
#include "ext2fsP.h"
+#define EXT4_MAX_REC_LEN ((1<<16)-1)
+
+errcode_t ext2fs_get_rec_len(ext2_filsys fs,
+ struct ext2_dir_entry *dirent,
+ unsigned int *rec_len)
+{
+ unsigned int len = dirent->rec_len;
+
+ if (len == EXT4_MAX_REC_LEN || len == 0)
+ *rec_len = fs->blocksize;
+ else
+ *rec_len = (len & 65532) | ((len & 3) << 16);
+ return 0;
+}
+
+errcode_t ext2fs_set_rec_len(ext2_filsys fs,
+ unsigned int len,
+ struct ext2_dir_entry *dirent)
+{
+ if ((len > fs->blocksize) || (fs->blocksize > (1 << 18)) || (len & 3))
+ return EINVAL;
+ if (len < 65536) {
+ dirent->rec_len = len;
+ return 0;
+ }
+ if (len == fs->blocksize) {
+ if (fs->blocksize == 65536)
+ dirent->rec_len = EXT4_MAX_REC_LEN;
+ else
+ dirent->rec_len = 0;
+ } else
+ dirent->rec_len = (len & 65532) | ((len >> 16) & 3);
+ return 0;
+}
+
/*
* This function checks to see whether or not a potential deleted
* directory entry looks valid. What we do is check the deleted entry
@@ -33,12 +68,12 @@ static int ext2fs_validate_entry(ext2_filsys fs, char *buf, int offset,
int final_offset)
{
struct ext2_dir_entry *dirent;
- int rec_len;
+ unsigned int rec_len;
while (offset < final_offset) {
dirent = (struct ext2_dir_entry *)(buf + offset);
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ if (ext2fs_get_rec_len(fs, dirent, &rec_len))
+ return 0;
offset += rec_len;
if ((rec_len < 8) ||
((rec_len % 4) != 0) ||
@@ -148,7 +183,8 @@ int ext2fs_process_dir_block(ext2_filsys fs,
int ret = 0;
int changed = 0;
int do_abort = 0;
- int rec_len, entry, size;
+ unsigned int rec_len;
+ int entry, size;
struct ext2_dir_entry *dirent;
if (blockcnt < 0)
@@ -162,8 +198,8 @@ int ext2fs_process_dir_block(ext2_filsys fs,
while (offset < fs->blocksize) {
dirent = (struct ext2_dir_entry *) (ctx->buf + offset);
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ if (ext2fs_get_rec_len(fs, dirent, &rec_len))
+ return BLOCK_ABORT;
if (((offset + rec_len) > fs->blocksize) ||
(rec_len < 8) ||
((rec_len % 4) != 0) ||
@@ -185,8 +221,8 @@ int ext2fs_process_dir_block(ext2_filsys fs,
entry++;
if (ret & DIRENT_CHANGED) {
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ if (ext2fs_get_rec_len(fs, dirent, &rec_len))
+ return BLOCK_ABORT;
changed++;
}
if (ret & DIRENT_ABORT) {
diff --git a/lib/ext2fs/dirblock.c b/lib/ext2fs/dirblock.c
index 501c6560..6542a81d 100644
--- a/lib/ext2fs/dirblock.c
+++ b/lib/ext2fs/dirblock.c
@@ -46,8 +46,8 @@ errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
if (flags & EXT2_DIRBLOCK_V2_STRUCT)
dirent->name_len = ext2fs_swab16(dirent->name_len);
#endif
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ 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;
@@ -72,7 +72,7 @@ errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
errcode_t retval;
char *p, *end;
char *buf = 0;
- int rec_len;
+ unsigned int rec_len;
struct ext2_dir_entry *dirent;
retval = ext2fs_get_mem(fs->blocksize, &buf);
@@ -83,8 +83,8 @@ errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
end = buf + fs->blocksize;
while (p < end) {
dirent = (struct ext2_dir_entry *) p;
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ if ((retval = ext2fs_get_rec_len(fs, dirent, &rec_len)) != 0)
+ return retval;
if ((rec_len < 8) ||
(rec_len % 4)) {
ext2fs_free_mem(&buf);
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 08bfa03e..234fbdd2 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -796,6 +796,12 @@ extern errcode_t ext2fs_dirhash(int version, const char *name, int len,
/* dir_iterate.c */
+extern errcode_t ext2fs_get_rec_len(ext2_filsys fs,
+ struct ext2_dir_entry *dirent,
+ unsigned int *rec_len);
+extern errcode_t ext2fs_set_rec_len(ext2_filsys fs,
+ unsigned int len,
+ struct ext2_dir_entry *dirent);
extern errcode_t ext2fs_dir_iterate(ext2_filsys fs,
ext2_ino_t dir,
int flags,
diff --git a/lib/ext2fs/link.c b/lib/ext2fs/link.c
index 5ed63942..7f2cfbc6 100644
--- a/lib/ext2fs/link.c
+++ b/lib/ext2fs/link.c
@@ -19,12 +19,14 @@
#include "ext2fs.h"
struct link_struct {
+ ext2_filsys fs;
const char *name;
int namelen;
ext2_ino_t inode;
int flags;
int done;
unsigned int blocksize;
+ errcode_t err;
struct ext2_super_block *sb;
};
@@ -36,13 +38,14 @@ static int link_proc(struct ext2_dir_entry *dirent,
{
struct link_struct *ls = (struct link_struct *) priv_data;
struct ext2_dir_entry *next;
- int rec_len, min_rec_len, curr_rec_len;
+ unsigned int rec_len, min_rec_len, curr_rec_len;
int ret = 0;
rec_len = EXT2_DIR_REC_LEN(ls->namelen);
- curr_rec_len = (dirent->rec_len || ls->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ ls->err = ext2fs_get_rec_len(ls->fs, dirent, &curr_rec_len);
+ if (ls->err)
+ return DIRENT_ABORT;
/*
* See if the following directory entry (if any) is unused;
@@ -52,8 +55,10 @@ static int link_proc(struct ext2_dir_entry *dirent,
if ((offset + curr_rec_len < blocksize - 8) &&
(next->inode == 0) &&
(offset + curr_rec_len + next->rec_len <= blocksize)) {
- dirent->rec_len += next->rec_len;
- curr_rec_len = dirent->rec_len;
+ curr_rec_len += next->rec_len;
+ ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent);
+ if (ls->err)
+ return DIRENT_ABORT;
ret = DIRENT_CHANGED;
}
@@ -67,12 +72,16 @@ static int link_proc(struct ext2_dir_entry *dirent,
if (curr_rec_len < (min_rec_len + rec_len))
return ret;
rec_len = curr_rec_len - min_rec_len;
- dirent->rec_len = min_rec_len;
+ ls->err = ext2fs_set_rec_len(ls->fs, min_rec_len, dirent);
+ if (ls->err)
+ return DIRENT_ABORT;
next = (struct ext2_dir_entry *) (buf + offset +
dirent->rec_len);
next->inode = 0;
next->name_len = 0;
- next->rec_len = rec_len;
+ ls->err = ext2fs_set_rec_len(ls->fs, rec_len, next);
+ if (ls->err)
+ return DIRENT_ABORT;
return DIRENT_CHANGED;
}
@@ -111,6 +120,7 @@ errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
if (!(fs->flags & EXT2_FLAG_RW))
return EXT2_ET_RO_FILSYS;
+ ls.fs = fs;
ls.name = name;
ls.namelen = name ? strlen(name) : 0;
ls.inode = ino;
@@ -118,11 +128,14 @@ errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
ls.done = 0;
ls.sb = fs->super;
ls.blocksize = fs->blocksize;
+ ls.err = 0;
retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
0, link_proc, &ls);
if (retval)
return retval;
+ if (ls.err)
+ return ls.err;
if (!ls.done)
return EXT2_ET_DIR_NO_SPACE;
diff --git a/lib/ext2fs/newdir.c b/lib/ext2fs/newdir.c
index 4e7b40d6..7f4266a5 100644
--- a/lib/ext2fs/newdir.c
+++ b/lib/ext2fs/newdir.c
@@ -41,7 +41,10 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
return retval;
memset(buf, 0, fs->blocksize);
dir = (struct ext2_dir_entry *) buf;
- dir->rec_len = fs->blocksize;
+
+ retval = ext2fs_set_rec_len(fs, fs->blocksize, dir);
+ if (retval)
+ return retval;
if (dir_ino) {
if (fs->super->s_feature_incompat &
@@ -60,7 +63,9 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
* Set up entry for '..'
*/
dir = (struct ext2_dir_entry *) (buf + dir->rec_len);
- dir->rec_len = rec_len;
+ retval = ext2fs_set_rec_len(fs, rec_len, dir);
+ if (retval)
+ return retval;
dir->inode = parent_ino;
dir->name_len = 2 | filetype;
dir->name[0] = '.';
diff --git a/misc/e2image.c b/misc/e2image.c
index dd2a1caa..83c1cca9 100644
--- a/misc/e2image.c
+++ b/misc/e2image.c
@@ -339,11 +339,14 @@ static void write_block(int fd, char *buf, int sparse_offset,
int name_id[256];
+#define EXT4_MAX_REC_LEN ((1<<16)-1)
+
static void scramble_dir_block(ext2_filsys fs, blk_t blk, char *buf)
{
char *p, *end, *cp;
struct ext2_dir_entry_2 *dirent;
- int rec_len, id, len;
+ unsigned int rec_len;
+ int id, len;
end = buf + fs->blocksize;
for (p = buf; p < end-8; p += rec_len) {
@@ -352,8 +355,10 @@ static void scramble_dir_block(ext2_filsys fs, blk_t blk, char *buf)
#ifdef WORDS_BIGENDIAN
rec_len = ext2fs_swab16(rec_len);
#endif
- rec_len = (rec_len || fs->blocksize < 65536) ?
- rec_len : 65536;
+ if (rec_len == EXT4_MAX_REC_LEN || rec_len == 0)
+ rec_len = fs->blocksize;
+ else
+ rec_len = (rec_len & 65532) | ((rec_len & 3) << 16);
#if 0
printf("rec_len = %d, name_len = %d\n", rec_len, dirent->name_len);
#endif
@@ -363,8 +368,10 @@ static void scramble_dir_block(ext2_filsys fs, blk_t blk, char *buf)
"bad rec_len (%d)\n", (unsigned long) blk,
rec_len);
rec_len = end - p;
+ (void) ext2fs_set_rec_len(fs, rec_len,
+ (struct ext2_dir_entry *) dirent);
#ifdef WORDS_BIGENDIAN
- dirent->rec_len = ext2fs_swab16(rec_len);
+ dirent->rec_len = ext2fs_swab16(dirent->rec_len);
#endif
continue;
}
diff --git a/tests/f_dup3/expect.1 b/tests/f_dup3/expect.1
index 13934169..9b1a28fa 100644
--- a/tests/f_dup3/expect.1
+++ b/tests/f_dup3/expect.1
@@ -24,8 +24,8 @@ File /e2fsck (inode #16, mod time Tue Sep 21 04:32:22 1993)
Clone multiply-claimed blocks? yes
Pass 2: Checking directory structure
-Directory inode 11, block 12, offset 0: directory corrupted
-Salvage? yes
+Entry '' in /lost+found (11) has invalid inode #: 24.
+Clear? yes
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
diff --git a/tests/f_dupfsblks/expect.1 b/tests/f_dupfsblks/expect.1
index 32ce89bb..5003254f 100644
--- a/tests/f_dupfsblks/expect.1
+++ b/tests/f_dupfsblks/expect.1
@@ -35,14 +35,11 @@ File /quux (inode #14, mod time Thu Aug 5 07:18:09 1999)
Clone multiply-claimed blocks? yes
Pass 2: Checking directory structure
-Directory inode 12, block 1, offset 0: directory corrupted
-Salvage? yes
-
-Directory inode 12, block 2, offset 0: directory corrupted
-Salvage? yes
+Entry '' in ??? (12) has invalid inode #: 4194303.
+Clear? yes
-Directory inode 12, block 3, offset 0: directory corrupted
-Salvage? yes
+Entry 'M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?' in ??? (12) has invalid inode #: 16383.
+Clear? yes
Entry '' in ??? (12) has a zero-length name.
Clear? yes