diff options
author | Nick Dokos <nicholas.dokos@hp.com> | 2010-02-05 10:35:17 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2010-02-05 10:41:42 -0500 |
commit | 1ec42a00a5354c342f213722382a4d1987af74ca (patch) | |
tree | 3f3bbcd22bb9a0c3bd254959fbf3f6347d271423 /e2fsck | |
parent | c70674387ee0c038bca16098f7869181beeabe0a (diff) | |
download | e2fsprogs-1ec42a00a5354c342f213722382a4d1987af74ca.tar.gz |
e2fsck: Fix the check if a file is really a directory to understand extents
Pass 1 has a test to see if a special file is really a directory.
Signed-off-by: Nick Dokos <nicholas.dokos@hp.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'e2fsck')
-rw-r--r-- | e2fsck/pass1.c | 66 |
1 files changed, 55 insertions, 11 deletions
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index 0cb3fda4..695abe4c 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -405,31 +405,75 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx, const char *old_op; errcode_t retval; blk_t blk; + blk64_t first_dir_blk; unsigned int i, rec_len, not_device = 0; + int extent_fs; + /* + * If the mode looks OK, we believe it. If the first block in + * the i_block array is 0, this cannot be a directory. If the + * inode is extent-mapped, it is still the case that the latter + * cannot be 0 - the magic number in the extent header would make + * it nonzero. + */ if (LINUX_S_ISDIR(inode->i_mode) || LINUX_S_ISREG(inode->i_mode) || LINUX_S_ISLNK(inode->i_mode) || inode->i_block[0] == 0) return; - for (i=0; i < EXT2_N_BLOCKS; i++) { - blk = inode->i_block[i]; - if (!blk) - continue; - if (i >= 4) - not_device++; + /* + * Check the block numbers in the i_block array for validity: + * zero blocks are skipped (but the first one cannot be zero - + * see above), other blocks are checked against the first and + * max data blocks (from the the superblock) and against the + * block bitmap. Any invalid block found means this cannot be + * a directory. + * + * If there are non-zero blocks past the fourth entry, then + * this cannot be a device file: we remember that for the next + * check. + * + * For extent mapped files, we don't do any sanity checking: + * just try to get the phys block of logical block 0 and run + * with it. + */ + + extent_fs = (ctx->fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS); + if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) { + /* extent mapped */ + if (ext2fs_bmap(ctx->fs, pctx->ino, inode, 0, 0, 0, + &blk)) + return; + /* device files are never extent mapped */ + not_device++; + } else { + for (i=0; i < EXT2_N_BLOCKS; i++) { + blk = inode->i_block[i]; + if (!blk) + continue; + if (i >= 4) + not_device++; - if (blk < ctx->fs->super->s_first_data_block || - blk >= ctx->fs->super->s_blocks_count || - ext2fs_fast_test_block_bitmap(ctx->block_found_map, blk)) - return; /* Invalid block, can't be dir */ + if (blk < ctx->fs->super->s_first_data_block || + blk >= ctx->fs->super->s_blocks_count || + ext2fs_fast_test_block_bitmap(ctx->block_found_map, + blk)) + return; /* Invalid block, can't be dir */ + } + blk = inode->i_block[0]; } + /* + * If the mode says this is a device file and the i_links_count field + * is sane and we have not ruled it out as a device file previously, + * we declare it a device file, not a directory. + */ if ((LINUX_S_ISCHR(inode->i_mode) || LINUX_S_ISBLK(inode->i_mode)) && (inode->i_links_count == 1) && !not_device) return; + /* read the first block */ old_op = ehandler_operation(_("reading directory block")); - retval = ext2fs_read_dir_block(ctx->fs, inode->i_block[0], buf); + retval = ext2fs_read_dir_block(ctx->fs, blk, buf); ehandler_operation(0); if (retval) return; |