]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
e2fsck: improve the inline directory detector
authorDarrick J. Wong <darrick.wong@oracle.com>
Wed, 28 Jan 2015 16:37:44 +0000 (11:37 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Wed, 28 Jan 2015 16:37:44 +0000 (11:37 -0500)
Strengthen the checks that guess if the inode we're looking at is an
inline directory.  The current check sweeps up any inline inode if
its length is a multiple of four; now we'll at least try to see if
there's the beginning of a valid directory entry.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
e2fsck/pass1.c
tests/f_inlinedata_repair/expect.1
tests/f_inlinedata_repair/expect.2
tests/f_inlinedir_detector/expect.1 [new file with mode: 0644]
tests/f_inlinedir_detector/expect.2 [new file with mode: 0644]
tests/f_inlinedir_detector/image.gz [new file with mode: 0644]
tests/f_inlinedir_detector/name [new file with mode: 0644]

index 69a9ac16016787adddb6b4fdd706bbf157045bbf..9f22826be3ecc54edaf47463b667ac68b8929ab0 100644 (file)
@@ -537,6 +537,9 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
                         EXT4_FEATURE_INCOMPAT_INLINE_DATA);
        if (inlinedata_fs && (inode->i_flags & EXT4_INLINE_DATA_FL)) {
                size_t size;
+               __u32 dotdot;
+               unsigned int rec_len;
+               struct ext2_dir_entry de;
 
                if (ext2fs_inline_data_size(ctx->fs, pctx->ino, &size))
                        return;
@@ -546,6 +549,26 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
                 */
                if (size & 3)
                        return;
+               /*
+                * If the first 10 bytes don't look like a directory entry,
+                * it's probably not a directory.
+                */
+               memcpy(&dotdot, inode->i_block, sizeof(dotdot));
+               memcpy(&de, ((char *)inode->i_block) + EXT4_INLINE_DATA_DOTDOT_SIZE,
+                      EXT2_DIR_REC_LEN(0));
+               dotdot = ext2fs_le32_to_cpu(dotdot);
+               de.inode = ext2fs_le32_to_cpu(de.inode);
+               de.rec_len = ext2fs_le16_to_cpu(de.rec_len);
+               ext2fs_get_rec_len(ctx->fs, &de, &rec_len);
+               if (dotdot >= ctx->fs->super->s_inodes_count ||
+                   (dotdot < EXT2_FIRST_INO(ctx->fs->super) &&
+                    dotdot != EXT2_ROOT_INO) ||
+                   de.inode >= ctx->fs->super->s_inodes_count ||
+                   (de.inode < EXT2_FIRST_INO(ctx->fs->super) &&
+                    de.inode != 0) ||
+                   rec_len > EXT4_MIN_INLINE_DATA_SIZE -
+                             EXT4_INLINE_DATA_DOTDOT_SIZE)
+                       return;
                /* device files never have a "system.data" entry */
                goto isdir;
        } else if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) {
index faba192e0b92ddafd6c30cfcf7180c74472b6f97..cc220ba16828df17f2733249142cde25bce1c9a6 100644 (file)
@@ -8,11 +8,6 @@ Inode 24, i_size is 59, should be 60.  Fix? yes
 Inode 28 is a unknown file type with mode 00 but it looks like it is really a directory.
 Fix? yes
 
-Inode 36 is a unknown file type with mode 00 but it looks like it is really a directory.
-Fix? yes
-
-Inode 36, i_size is 5, should be 60.  Fix? yes
-
 Pass 2: Checking directory structure
 Directory inode 20, block #0, offset 4: directory corrupted
 Salvage? yes
@@ -26,26 +21,16 @@ Salvage? yes
 Directory inode 32, block #0, offset 4: directory corrupted
 Salvage? yes
 
-Entry '..' in ??? (36) has invalid inode #: 1633774699.
-Clear? yes
-
-Directory inode 36, block #0, offset 4: directory corrupted
-Salvage? yes
-
 Symlink /3 (inode #14) is invalid.
 Clear? yes
 
 Inode 38 (/B) has invalid mode (00).
 Clear? yes
 
-Entry 'A' in / (2) has an incorrect filetype (was 1, should be 2).
-Fix? yes
+Inode 36 (/A) has invalid mode (00).
+Clear? yes
 
 Pass 3: Checking directory connectivity
-'..' in /A (36) is ??? (1633774699), should be / (2).
-Fix? yes
-
-Error while adjusting inode count on inode 0
 Pass 4: Checking reference counts
 Unattached zero-length inode 22.  Clear? yes
 
@@ -63,13 +48,8 @@ Unattached zero-length inode 34.  Clear? yes
 
 Unattached zero-length inode 35.  Clear? yes
 
-Inode 36 ref count is 1, should be 2.  Fix? yes
-
 Pass 5: Checking group summary information
-Directories count wrong for group #0 (7, counted=8).
-Fix? yes
-
 
 test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
-test_filesys: 28/128 files (0.0% non-contiguous), 18/512 blocks
+test_filesys: 27/128 files (0.0% non-contiguous), 18/512 blocks
 Exit status is 1
index 519f21d70b0c925dedc2b9ccc78f979d5c85da51..2c400a5798395eeebe0f2f297f694dc5c6ded203 100644 (file)
@@ -3,5 +3,5 @@ Pass 2: Checking directory structure
 Pass 3: Checking directory connectivity
 Pass 4: Checking reference counts
 Pass 5: Checking group summary information
-test_filesys: 28/128 files (0.0% non-contiguous), 18/512 blocks
+test_filesys: 27/128 files (0.0% non-contiguous), 18/512 blocks
 Exit status is 0
diff --git a/tests/f_inlinedir_detector/expect.1 b/tests/f_inlinedir_detector/expect.1
new file mode 100644 (file)
index 0000000..72b7519
--- /dev/null
@@ -0,0 +1,20 @@
+Pass 1: Checking inodes, blocks, and sizes
+Special (device/socket/fifo) file (inode 12) has extents
+or inline-data flag set.  Clear? yes
+
+Special (device/socket/fifo) inode 12 has non-zero size.  Fix? yes
+
+Inode 13 is a named pipe but it looks like it is really a directory.
+Fix? yes
+
+Pass 2: Checking directory structure
+Entry 'moo' in / (2) has an incorrect filetype (was 1, should be 5).
+Fix? yes
+
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 13/128 files (0.0% non-contiguous), 17/512 blocks
+Exit status is 1
diff --git a/tests/f_inlinedir_detector/expect.2 b/tests/f_inlinedir_detector/expect.2
new file mode 100644 (file)
index 0000000..06886a4
--- /dev/null
@@ -0,0 +1,7 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 13/128 files (0.0% non-contiguous), 17/512 blocks
+Exit status is 0
diff --git a/tests/f_inlinedir_detector/image.gz b/tests/f_inlinedir_detector/image.gz
new file mode 100644 (file)
index 0000000..34b4518
Binary files /dev/null and b/tests/f_inlinedir_detector/image.gz differ
diff --git a/tests/f_inlinedir_detector/name b/tests/f_inlinedir_detector/name
new file mode 100644 (file)
index 0000000..3368af5
--- /dev/null
@@ -0,0 +1 @@
+detect inline dirs correctly