diff options
-rw-r--r-- | debugfs/htree.c | 22 | ||||
-rw-r--r-- | e2fsck/pass1.c | 18 | ||||
-rw-r--r-- | e2fsck/pass2.c | 60 | ||||
-rw-r--r-- | e2fsck/problem.c | 2 | ||||
-rw-r--r-- | e2fsck/rehash.c | 14 | ||||
-rw-r--r-- | lib/ext2fs/dir_iterate.c | 41 | ||||
-rw-r--r-- | lib/ext2fs/dirblock.c | 15 | ||||
-rw-r--r-- | lib/ext2fs/link.c | 20 | ||||
-rw-r--r-- | lib/ext2fs/newdir.c | 2 | ||||
-rw-r--r-- | misc/e2image.c | 2 |
10 files changed, 121 insertions, 75 deletions
diff --git a/debugfs/htree.c b/debugfs/htree.c index bee78d7e..1659b63f 100644 --- a/debugfs/htree.c +++ b/debugfs/htree.c @@ -39,7 +39,7 @@ 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 hash_alg; + int rec_len, hash_alg; errcode = ext2fs_bmap(fs, ino, inode, buf, 0, blk, &pblk); if (errcode) { @@ -62,10 +62,12 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino, while (offset < fs->blocksize) { dirent = (struct ext2_dir_entry *) (buf + offset); - if (((offset + dirent->rec_len) > fs->blocksize) || - (dirent->rec_len < 8) || - ((dirent->rec_len % 4) != 0) || - (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) { + rec_len = (dirent->rec_len || fs->blocksize < 65536) ? + dirent->rec_len : 65536; + if (((offset + rec_len) > fs->blocksize) || + (rec_len < 8) || + ((rec_len % 4) != 0) || + (((dirent->name_len & 0xFF)+8) > rec_len)) { fprintf(pager, "Corrupted directory block (%u)!\n", blk); break; } @@ -80,7 +82,7 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino, com_err("htree_dump_leaf_node", errcode, "while calculating hash"); sprintf(tmp, "%u 0x%08x-%08x (%d) %s ", dirent->inode, - hash, minor_hash, dirent->rec_len, name); + hash, minor_hash, rec_len, name); thislen = strlen(tmp); if (col + thislen > 80) { fprintf(pager, "\n"); @@ -88,7 +90,7 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino, } fprintf(pager, "%s", tmp); col += thislen; - offset += dirent->rec_len; + offset += rec_len; } fprintf(pager, "\n"); } @@ -373,6 +375,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; if (blockcnt < 0) return 0; @@ -388,7 +391,8 @@ 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; if (dirent->inode && p->len == (dirent->name_len & 0xFF) && strncmp(p->search_name, dirent->name, @@ -399,7 +403,7 @@ static int search_dir_block(ext2_filsys fs, blk_t *blocknr, printf("offset %u\n", offset); return BLOCK_ABORT; } - offset += dirent->rec_len; + offset += rec_len; } return 0; } diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index 0e245dd0..f2f72edd 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -404,7 +404,7 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx, const char *old_op; errcode_t retval; blk_t blk; - int i, not_device = 0; + int i, rec_len, not_device = 0; if (LINUX_S_ISDIR(inode->i_mode) || LINUX_S_ISREG(inode->i_mode) || LINUX_S_ISLNK(inode->i_mode) || inode->i_block[0] == 0) @@ -434,20 +434,24 @@ 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; if (((dirent->name_len & 0xFF) != 1) || (dirent->name[0] != '.') || (dirent->inode != pctx->ino) || - (dirent->rec_len < 12) || - (dirent->rec_len % 4) || - (dirent->rec_len >= ctx->fs->blocksize - 12)) + (rec_len < 12) || + (rec_len % 4) || + (rec_len >= ctx->fs->blocksize - 12)) return; - dirent = (struct ext2_dir_entry *) (buf + dirent->rec_len); + dirent = (struct ext2_dir_entry *) (buf + rec_len); + rec_len = (dirent->rec_len || ctx->fs->blocksize < 65536) ? + dirent->rec_len : 65536; if (((dirent->name_len & 0xFF) != 2) || (dirent->name[0] != '.') || (dirent->name[1] != '.') || - (dirent->rec_len < 12) || - (dirent->rec_len % 4)) + (rec_len < 12) || + (rec_len % 4)) return; if (fix_problem(ctx, PR_1_TREAT_AS_DIRECTORY, pctx)) { diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c index f4fa93e5..1992479b 100644 --- a/e2fsck/pass2.c +++ b/e2fsck/pass2.c @@ -355,7 +355,7 @@ static int check_dot(e2fsck_t ctx, struct ext2_dir_entry *nextdir; int status = 0; int created = 0; - int new_len; + int rec_len, new_len; int problem = 0; if (!dirent->inode) @@ -365,11 +365,13 @@ static int check_dot(e2fsck_t ctx, problem = PR_2_1ST_NOT_DOT; 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; if (problem) { if (fix_problem(ctx, problem, pctx)) { - if (dirent->rec_len < 12) - dirent->rec_len = 12; + if (rec_len < 12) + rec_len = dirent->rec_len = 12; dirent->inode = ino; dirent->name_len = 1; dirent->name[0] = '.'; @@ -384,8 +386,8 @@ static int check_dot(e2fsck_t ctx, status = 1; } } - if (dirent->rec_len > 12) { - new_len = dirent->rec_len - 12; + if (rec_len > 12) { + new_len = rec_len - 12; if (new_len > 12) { if (created || fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) { @@ -411,7 +413,7 @@ static int check_dotdot(e2fsck_t ctx, struct ext2_dir_entry *dirent, ext2_ino_t ino, struct problem_context *pctx) { - int problem = 0; + int rec_len, problem = 0; if (!dirent->inode) problem = PR_2_MISSING_DOT_DOT; @@ -422,9 +424,11 @@ 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; if (problem) { if (fix_problem(ctx, problem, pctx)) { - if (dirent->rec_len < 12) + if (rec_len < 12) dirent->rec_len = 12; /* * Note: we don't have the parent inode just @@ -644,14 +648,18 @@ static void salvage_directory(ext2_filsys fs, unsigned int *offset) { char *cp = (char *) dirent; - int left = fs->blocksize - *offset - dirent->rec_len; + int left, rec_len; unsigned int name_len = dirent->name_len & 0xFF; + rec_len = (dirent->rec_len || fs->blocksize < 65536) ? + dirent->rec_len : 65536; + left = fs->blocksize - *offset - rec_len; + /* * Special case of directory entry of size 8: copy what's left * of the directory block up to cover up the invalid hole. */ - if ((left >= 12) && (dirent->rec_len == 8)) { + if ((left >= 12) && (rec_len == 8)) { memmove(cp, cp+8, left); memset(cp + left, 0, 8); return; @@ -662,7 +670,7 @@ static void salvage_directory(ext2_filsys fs, * record length. */ if ((left < 0) && - (name_len + 8 <= dirent->rec_len + (unsigned) left) && + (name_len + 8 <= rec_len + (unsigned) left) && dirent->inode <= fs->super->s_inodes_count && strnlen(dirent->name, name_len) == name_len) { dirent->rec_len += left; @@ -673,10 +681,10 @@ static void salvage_directory(ext2_filsys fs, * of four, and not too big, such that it is valid, let the * previous directory entry absorb the invalid one. */ - if (prev && dirent->rec_len && (dirent->rec_len % 4) == 0 && - (*offset + dirent->rec_len <= fs->blocksize)) { - prev->rec_len += dirent->rec_len; - *offset += dirent->rec_len; + if (prev && rec_len && (rec_len % 4) == 0 && + (*offset + rec_len <= fs->blocksize)) { + prev->rec_len += rec_len; + *offset += rec_len; return; } /* @@ -709,6 +717,7 @@ static int check_dir_block(ext2_filsys fs, const char * old_op; int dir_modified = 0; int dot_state; + int rec_len; blk_t block_nr = db->blk; ext2_ino_t ino = db->ino; ext2_ino_t subdir_parent; @@ -800,6 +809,8 @@ 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; limit = (struct ext2_dx_countlimit *) (buf+8); if (db->blockcnt == 0) { root = (struct ext2_dx_root_info *) (buf + 24); @@ -819,7 +830,7 @@ static int check_dir_block(ext2_filsys fs, dx_dir->hashversion += 3; dx_dir->depth = root->indirect_levels + 1; } else if ((dirent->inode == 0) && - (dirent->rec_len == fs->blocksize) && + (rec_len == fs->blocksize) && (dirent->name_len == 0) && (ext2fs_le16_to_cpu(limit->limit) == ((fs->blocksize-8) / @@ -837,12 +848,14 @@ out_htree: problem = 0; dirent = (struct ext2_dir_entry *) (buf + offset); + rec_len = (dirent->rec_len || fs->blocksize < 65536) ? + dirent->rec_len : 65536; cd->pctx.dirent = dirent; cd->pctx.num = offset; - if (((offset + dirent->rec_len) > fs->blocksize) || - (dirent->rec_len < 12) || - ((dirent->rec_len % 4) != 0) || - (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) { + if (((offset + rec_len) > fs->blocksize) || + (rec_len < 12) || + ((rec_len % 4) != 0) || + (((dirent->name_len & 0xFF)+8) > rec_len)) { if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) { salvage_directory(fs, dirent, prev, &offset); dir_modified++; @@ -1092,7 +1105,10 @@ out_htree: ctx->fs_total_count++; next: prev = dirent; - offset += dirent->rec_len; + if (dir_modified) + rec_len = (dirent->rec_len || fs->blocksize < 65536) ? + dirent->rec_len : 65536; + offset += rec_len; dot_state++; } while (offset < fs->blocksize); #if 0 @@ -1112,7 +1128,7 @@ out_htree: } #endif /* ENABLE_HTREE */ if (offset != fs->blocksize) { - cd->pctx.num = dirent->rec_len - fs->blocksize + offset; + cd->pctx.num = rec_len - fs->blocksize + offset; if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) { dirent->rec_len = cd->pctx.num; dir_modified++; diff --git a/e2fsck/problem.c b/e2fsck/problem.c index 9d4c4e86..27e2bf0f 100644 --- a/e2fsck/problem.c +++ b/e2fsck/problem.c @@ -1136,7 +1136,7 @@ static struct e2fsck_problem problem_table[] = { /* Directory entry for '.' is big. Split? */ { PR_2_SPLIT_DOT, - N_("@d @e for '.' is big. "), + N_("@d @e for '.' in %p (%i) is big.\n"), PROMPT_SPLIT, PR_NO_OK }, /* Illegal FIFO inode */ diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c index e75774a1..6c7d0510 100644 --- a/e2fsck/rehash.c +++ b/e2fsck/rehash.c @@ -89,7 +89,7 @@ static int fill_dir_block(ext2_filsys fs, struct ext2_dir_entry *dirent; char *dir; unsigned int offset, dir_offset; - int hash_alg; + int rec_len, hash_alg; if (blockcnt < 0) return 0; @@ -117,14 +117,16 @@ static int fill_dir_block(ext2_filsys fs, dir_offset = 0; while (dir_offset < fs->blocksize) { dirent = (struct ext2_dir_entry *) (dir + dir_offset); - if (((dir_offset + dirent->rec_len) > fs->blocksize) || - (dirent->rec_len < 8) || - ((dirent->rec_len % 4) != 0) || - (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) { + rec_len = (dirent->rec_len || fs->blocksize < 65536) ? + dirent->rec_len : 65536; + if (((dir_offset + rec_len) > fs->blocksize) || + (rec_len < 8) || + ((rec_len % 4) != 0) || + (((dirent->name_len & 0xFF)+8) > rec_len)) { fd->err = EXT2_ET_DIR_CORRUPTED; return BLOCK_ABORT; } - dir_offset += dirent->rec_len; + dir_offset += rec_len; if (dirent->inode == 0) continue; if (!fd->compress && ((dirent->name_len&0xFF) == 1) && diff --git a/lib/ext2fs/dir_iterate.c b/lib/ext2fs/dir_iterate.c index 3e7b7b06..6bb536b0 100644 --- a/lib/ext2fs/dir_iterate.c +++ b/lib/ext2fs/dir_iterate.c @@ -29,16 +29,20 @@ * undeleted entry. Returns 1 if the deleted entry looks valid, zero * if not valid. */ -static int ext2fs_validate_entry(char *buf, int offset, int final_offset) +static int ext2fs_validate_entry(ext2_filsys fs, char *buf, int offset, + int final_offset) { struct ext2_dir_entry *dirent; + int rec_len; while (offset < final_offset) { dirent = (struct ext2_dir_entry *)(buf + offset); - offset += dirent->rec_len; - if ((dirent->rec_len < 8) || - ((dirent->rec_len % 4) != 0) || - (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) + rec_len = (dirent->rec_len || fs->blocksize < 65536) ? + dirent->rec_len : 65536; + offset += rec_len; + if ((rec_len < 8) || + ((rec_len % 4) != 0) || + (((dirent->name_len & 0xFF)+8) > rec_len)) return 0; } return (offset == final_offset); @@ -144,7 +148,7 @@ int ext2fs_process_dir_block(ext2_filsys fs, int ret = 0; int changed = 0; int do_abort = 0; - int entry, size; + int rec_len, entry, size; struct ext2_dir_entry *dirent; if (blockcnt < 0) @@ -158,10 +162,12 @@ int ext2fs_process_dir_block(ext2_filsys fs, while (offset < fs->blocksize) { dirent = (struct ext2_dir_entry *) (ctx->buf + offset); - if (((offset + dirent->rec_len) > fs->blocksize) || - (dirent->rec_len < 8) || - ((dirent->rec_len % 4) != 0) || - (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) { + rec_len = (dirent->rec_len || fs->blocksize < 65536) ? + dirent->rec_len : 65536; + if (((offset + rec_len) > fs->blocksize) || + (rec_len < 8) || + ((rec_len % 4) != 0) || + (((dirent->name_len & 0xFF)+8) > rec_len)) { ctx->errcode = EXT2_ET_DIR_CORRUPTED; return BLOCK_ABORT; } @@ -178,33 +184,36 @@ int ext2fs_process_dir_block(ext2_filsys fs, if (entry < DIRENT_OTHER_FILE) entry++; - if (ret & DIRENT_CHANGED) + if (ret & DIRENT_CHANGED) { + rec_len = (dirent->rec_len || fs->blocksize < 65536) ? + dirent->rec_len : 65536; changed++; + } if (ret & DIRENT_ABORT) { do_abort++; break; } next: if (next_real_entry == offset) - next_real_entry += dirent->rec_len; + next_real_entry += rec_len; if (ctx->flags & DIRENT_FLAG_INCLUDE_REMOVED) { size = ((dirent->name_len & 0xFF) + 11) & ~3; - if (dirent->rec_len != size) { + if (rec_len != size) { unsigned int final_offset; - final_offset = offset + dirent->rec_len; + final_offset = offset + rec_len; offset += size; while (offset < final_offset && - !ext2fs_validate_entry(ctx->buf, + !ext2fs_validate_entry(fs, ctx->buf, offset, final_offset)) offset += 4; continue; } } - offset += dirent->rec_len; + offset += rec_len; } if (changed) { diff --git a/lib/ext2fs/dirblock.c b/lib/ext2fs/dirblock.c index fb20fa0e..c61e001c 100644 --- a/lib/ext2fs/dirblock.c +++ b/lib/ext2fs/dirblock.c @@ -46,12 +46,12 @@ 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; + rec_len = (dirent->rec_len || fs->blocksize < 65536) ? + dirent->rec_len : 65536; if ((rec_len < 8) || (rec_len % 4)) { rec_len = 8; retval = EXT2_ET_DIR_CORRUPTED; - } - if (((name_len & 0xFF) + 8) > dirent->rec_len) + } else if (((name_len & 0xFF) + 8) > rec_len) retval = EXT2_ET_DIR_CORRUPTED; p += rec_len; } @@ -72,6 +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; struct ext2_dir_entry *dirent; retval = ext2fs_get_mem(fs->blocksize, &buf); @@ -82,12 +83,14 @@ 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; - if ((dirent->rec_len < 8) || - (dirent->rec_len % 4)) { + rec_len = (dirent->rec_len || fs->blocksize < 65536) ? + dirent->rec_len : 65536; + if ((rec_len < 8) || + (rec_len % 4)) { ext2fs_free_mem(&buf); return (EXT2_ET_DIR_CORRUPTED); } - p += dirent->rec_len; + 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); diff --git a/lib/ext2fs/link.c b/lib/ext2fs/link.c index 5e0f4f3c..b2834889 100644 --- a/lib/ext2fs/link.c +++ b/lib/ext2fs/link.c @@ -24,6 +24,7 @@ struct link_struct { ext2_ino_t inode; int flags; int done; + unsigned int blocksize; struct ext2_super_block *sb; }; @@ -35,20 +36,24 @@ 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; + 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; + /* * See if the following directory entry (if any) is unused; * if so, absorb it into this one. */ - next = (struct ext2_dir_entry *) (buf + offset + dirent->rec_len); - if ((offset + dirent->rec_len < blocksize - 8) && + next = (struct ext2_dir_entry *) (buf + offset + curr_rec_len); + if ((offset + curr_rec_len < blocksize - 8) && (next->inode == 0) && - (offset + dirent->rec_len + next->rec_len <= blocksize)) { + (offset + curr_rec_len + next->rec_len <= blocksize)) { dirent->rec_len += next->rec_len; + curr_rec_len = dirent->rec_len; ret = DIRENT_CHANGED; } @@ -59,9 +64,9 @@ static int link_proc(struct ext2_dir_entry *dirent, */ if (dirent->inode) { min_rec_len = EXT2_DIR_REC_LEN(dirent->name_len & 0xFF); - if (dirent->rec_len < (min_rec_len + rec_len)) + if (curr_rec_len < (min_rec_len + rec_len)) return ret; - rec_len = dirent->rec_len - min_rec_len; + rec_len = curr_rec_len - min_rec_len; dirent->rec_len = min_rec_len; next = (struct ext2_dir_entry *) (buf + offset + dirent->rec_len); @@ -75,7 +80,7 @@ static int link_proc(struct ext2_dir_entry *dirent, * If we get this far, then the directory entry is not used. * See if we can fit the request entry in. If so, do it. */ - if (dirent->rec_len < rec_len) + if (curr_rec_len < rec_len) return ret; dirent->inode = ls->inode; dirent->name_len = ls->namelen; @@ -112,6 +117,7 @@ errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name, ls.flags = flags; ls.done = 0; ls.sb = fs->super; + ls.blocksize = fs->blocksize; retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY, 0, link_proc, &ls); diff --git a/lib/ext2fs/newdir.c b/lib/ext2fs/newdir.c index 3904d911..c2ca9034 100644 --- a/lib/ext2fs/newdir.c +++ b/lib/ext2fs/newdir.c @@ -53,7 +53,7 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino, dir->inode = dir_ino; dir->name_len = 1 | filetype; dir->name[0] = '.'; - rec_len = dir->rec_len - EXT2_DIR_REC_LEN(1); + rec_len = fs->blocksize - EXT2_DIR_REC_LEN(1); dir->rec_len = EXT2_DIR_REC_LEN(1); /* diff --git a/misc/e2image.c b/misc/e2image.c index 081c66f7..358b3614 100644 --- a/misc/e2image.c +++ b/misc/e2image.c @@ -350,6 +350,8 @@ 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 0 printf("rec_len = %d, name_len = %d\n", rec_len, dirent->name_len); #endif |