aboutsummaryrefslogtreecommitdiffstats
path: root/e2fsck/pass1.c
diff options
context:
space:
mode:
authorTahsin Erdogan <tahsin@google.com>2017-06-29 18:31:59 -0700
committerTheodore Ts'o <tytso@mit.edu>2017-07-05 00:06:30 -0400
commitcf0be23436880a7c9658e2e24259e93cdcb4cc86 (patch)
treee6bdfe7133ab2c69095b59cbe2c9281abe1751b7 /e2fsck/pass1.c
parent0446b9907fbdc8f130ec35726bc8b9cdd493a1cb (diff)
downloadandroid_external_e2fsprogs-cf0be23436880a7c9658e2e24259e93cdcb4cc86.tar.gz
android_external_e2fsprogs-cf0be23436880a7c9658e2e24259e93cdcb4cc86.tar.bz2
android_external_e2fsprogs-cf0be23436880a7c9658e2e24259e93cdcb4cc86.zip
Use i_size to determine whether a symlink is a fast symlink
Current way of determining whether a symlink is in fast symlink format is to call ext2fs_inode_data_blocks2(). If number of data blocks is zero and EXT4_INLINE_DATA_FL flag is not set, then symlink data must be in inode->i_block. This heuristic is becoming increasingly hard to maintain because inode->i_blocks count can also be incremented for blocks used by extended attributes. Before ea_inode feature, extra block could come from xattr block, now more blocks can be added because of xattr inodes. To address the issue, add a ext2fs_is_fast_symlink() function that gives a direct answer based on inode->i_size field. This is equivalent to kernel's ext4_inode_is_fast_symlink() function. This patch also fixes a few issues related to fast symlink handling: - Both rdump_symlink() and follow_link() interpreted symlinks with 0 data blocks to always mean fast symlinks. This is incorrect because symlinks that are stored as inline data also have 0 data blocks. Thus, they try to read everything from inode->i_block and miss the symlink suffix in inode extra area. - e2fsck_pass1_check_symlink() had code to handle inode with EXT4_INLINE_DATA_FL flag twice. The first if block always returns from the function so the second one is unreachable code. Signed-off-by: Tahsin Erdogan <tahsin@google.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'e2fsck/pass1.c')
-rw-r--r--e2fsck/pass1.c42
1 files changed, 8 insertions, 34 deletions
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index 4ea7962f..6deaab20 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -179,7 +179,6 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
{
unsigned int len;
int i;
- blk64_t blocks;
ext2_extent_handle_t handle;
struct ext2_extent_info info;
struct ext2fs_extent extent;
@@ -223,12 +222,15 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
return 1;
}
- blocks = ext2fs_inode_data_blocks2(fs, inode);
- if (blocks) {
- if (inode->i_flags & EXT4_INLINE_DATA_FL)
+ if (ext2fs_is_fast_symlink(inode)) {
+ if (inode->i_size >= sizeof(inode->i_block))
+ return 0;
+
+ len = strnlen((char *)inode->i_block, sizeof(inode->i_block));
+ if (len == sizeof(inode->i_block))
return 0;
+ } else {
if ((inode->i_size >= fs->blocksize) ||
- (blocks != fs->blocksize >> 9) ||
(inode->i_block[0] < fs->super->s_first_data_block) ||
(inode->i_block[0] >= ext2fs_blocks_count(fs->super)))
return 0;
@@ -247,34 +249,6 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
}
if (len == fs->blocksize)
return 0;
- } else if (inode->i_flags & EXT4_INLINE_DATA_FL) {
- char *inline_buf = NULL;
- size_t inline_sz = 0;
-
- if (ext2fs_inline_data_size(fs, ino, &inline_sz))
- return 0;
- if (inode->i_size != inline_sz)
- return 0;
- if (ext2fs_get_mem(inline_sz + 1, &inline_buf))
- return 0;
- i = 0;
- if (ext2fs_inline_data_get(fs, ino, inode, inline_buf, NULL))
- goto exit_inline;
- inline_buf[inline_sz] = 0;
- len = strnlen(inline_buf, inline_sz);
- if (len != inline_sz)
- goto exit_inline;
- i = 1;
-exit_inline:
- ext2fs_free_mem(&inline_buf);
- return i;
- } else {
- if (inode->i_size >= sizeof(inode->i_block))
- return 0;
-
- len = strnlen((char *)inode->i_block, sizeof(inode->i_block));
- if (len == sizeof(inode->i_block))
- return 0;
}
if (len != inode->i_size)
if ((inode->i_flags & EXT4_ENCRYPT_FL) == 0)
@@ -1911,7 +1885,7 @@ void e2fsck_pass1(e2fsck_t ctx)
if (inode->i_flags & EXT4_INLINE_DATA_FL) {
FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
continue;
- } else if (ext2fs_inode_data_blocks(fs, inode) == 0) {
+ } else if (ext2fs_is_fast_symlink(inode)) {
ctx->fs_fast_symlinks_count++;
check_blocks(ctx, &pctx, block_buf,
ea_ibody_quota_blocks);