Skip to content

Commit 3658b8b

Browse files
committed
ext4: replace strcmp with direct comparison for '.' and '..'
In a discussion over a proposed patch, "ext4: replace strcpy() with '.' assignment"[1], I had asserted that directory entries in ext4 were not NUL terminated, and hence it was safe to replace strcpy() with a direct assignment. As it turns out, this was incorrect. It's true for all all directory entries *except* for '.' and '..' where the kernel was using strcmp() and where e2fsck actually checks and offers to fix things if '.' and '..' are not NUL terminated. [1] https://lore.kernel.org/r/202505191316.JJMnPobO-lkp@intel.com We can't change this without breaking old kernel versions, but in the spirit of "be liberal in what you receive", use direct comparison of de->name_len and de->name[0,1] instead of strcmp(). This has the side benefit of reducing the compiled text size by 96 bytes on x86_64. Signed-off-by: Theodore Ts'o <tytso@mit.edu> Link: https://patch.msgid.link/20250712181249.434530-1-tytso@mit.edu Signed-off-by: Theodore Ts'o <tytso@mit.edu>
1 parent 91b8ca8 commit 3658b8b

1 file changed

Lines changed: 7 additions & 4 deletions

File tree

fs/ext4/namei.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3082,7 +3082,8 @@ bool ext4_empty_dir(struct inode *inode)
30823082
de = (struct ext4_dir_entry_2 *) bh->b_data;
30833083
if (ext4_check_dir_entry(inode, NULL, de, bh, bh->b_data, bh->b_size,
30843084
0) ||
3085-
le32_to_cpu(de->inode) != inode->i_ino || strcmp(".", de->name)) {
3085+
le32_to_cpu(de->inode) != inode->i_ino || de->name_len != 1 ||
3086+
de->name[0] != '.') {
30863087
ext4_warning_inode(inode, "directory missing '.'");
30873088
brelse(bh);
30883089
return false;
@@ -3091,7 +3092,8 @@ bool ext4_empty_dir(struct inode *inode)
30913092
de = ext4_next_entry(de, sb->s_blocksize);
30923093
if (ext4_check_dir_entry(inode, NULL, de, bh, bh->b_data, bh->b_size,
30933094
offset) ||
3094-
le32_to_cpu(de->inode) == 0 || strcmp("..", de->name)) {
3095+
le32_to_cpu(de->inode) == 0 || de->name_len != 2 ||
3096+
de->name[0] != '.' || de->name[1] != '.') {
30953097
ext4_warning_inode(inode, "directory missing '..'");
30963098
brelse(bh);
30973099
return false;
@@ -3532,7 +3534,7 @@ static struct buffer_head *ext4_get_first_dir_block(handle_t *handle,
35323534
if (ext4_check_dir_entry(inode, NULL, de, bh, bh->b_data,
35333535
bh->b_size, 0) ||
35343536
le32_to_cpu(de->inode) != inode->i_ino ||
3535-
strcmp(".", de->name)) {
3537+
de->name_len != 1 || de->name[0] != '.') {
35363538
EXT4_ERROR_INODE(inode, "directory missing '.'");
35373539
brelse(bh);
35383540
*retval = -EFSCORRUPTED;
@@ -3543,7 +3545,8 @@ static struct buffer_head *ext4_get_first_dir_block(handle_t *handle,
35433545
de = ext4_next_entry(de, inode->i_sb->s_blocksize);
35443546
if (ext4_check_dir_entry(inode, NULL, de, bh, bh->b_data,
35453547
bh->b_size, offset) ||
3546-
le32_to_cpu(de->inode) == 0 || strcmp("..", de->name)) {
3548+
le32_to_cpu(de->inode) == 0 || de->name_len != 2 ||
3549+
de->name[0] != '.' || de->name[1] != '.') {
35473550
EXT4_ERROR_INODE(inode, "directory missing '..'");
35483551
brelse(bh);
35493552
*retval = -EFSCORRUPTED;

0 commit comments

Comments
 (0)