Skip to content

Commit ac78d9d

Browse files
committed
btrfs-progs: add duplicate filename check
If when doing btrfs check we encounter a DIR_ITEM slot with multiple entries due to a hash collision, loop through them to make sure that they are all distinct names. Signed-off-by: Mark Harmstone <mark@harmstone.com>
1 parent 5378bb9 commit ac78d9d

File tree

4 files changed

+57
-0
lines changed

4 files changed

+57
-0
lines changed

check/main.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,8 @@ static void print_inode_error(struct btrfs_root *root, struct inode_record *rec)
653653
rec->nlink);
654654
if (errors & I_ERR_INVALID_XATTR)
655655
fprintf(stderr, ", invalid xattr");
656+
if (errors & I_ERR_DUP_FILENAME)
657+
fprintf(stderr, ", dup filename");
656658
fprintf(stderr, "\n");
657659

658660
/* Print the holes if needed */
@@ -1434,6 +1436,43 @@ static int add_mismatch_dir_hash(struct inode_record *dir_rec,
14341436
return 0;
14351437
}
14361438

1439+
static void check_for_dupe_filenames(struct extent_buffer *eb, int slot,
1440+
int nritems, struct inode_record *rec)
1441+
{
1442+
struct btrfs_dir_item *di, *di2;
1443+
char namebuf[BTRFS_NAME_LEN], namebuf2[BTRFS_NAME_LEN];
1444+
u32 len, len2;
1445+
1446+
di = btrfs_item_ptr(eb, slot, struct btrfs_dir_item);
1447+
1448+
for (int i = 0; i < nritems - 1; i++) {
1449+
len = btrfs_dir_name_len(eb, di) + btrfs_dir_data_len(eb, di);
1450+
1451+
read_extent_buffer(eb, namebuf, (unsigned long)(di + 1), len);
1452+
1453+
di2 = di;
1454+
len2 = len;
1455+
1456+
for (int j = i + 1; j < nritems; j++) {
1457+
di2 = (struct btrfs_dir_item *)
1458+
((char *)di2 + sizeof(*di2) + len2);
1459+
len2 = btrfs_dir_name_len(eb, di2) +
1460+
btrfs_dir_data_len(eb, di2);
1461+
1462+
if (len != len2)
1463+
continue;
1464+
1465+
read_extent_buffer(eb, namebuf2,
1466+
(unsigned long)(di2 + 1), len2);
1467+
1468+
if (!memcmp(namebuf, namebuf2, len))
1469+
rec->errors |= I_ERR_DUP_FILENAME;
1470+
}
1471+
1472+
di = (struct btrfs_dir_item *) ((char *)di + sizeof(*di) + len);
1473+
}
1474+
}
1475+
14371476
static int process_dir_item(struct extent_buffer *eb,
14381477
int slot, struct btrfs_key *key,
14391478
struct shared_node *active_node)
@@ -1525,6 +1564,9 @@ static int process_dir_item(struct extent_buffer *eb,
15251564
if (key->type == BTRFS_DIR_INDEX_KEY && nritems > 1)
15261565
rec->errors |= I_ERR_DUP_DIR_INDEX;
15271566

1567+
if (key->type == BTRFS_DIR_ITEM_KEY && nritems > 1)
1568+
check_for_dupe_filenames(eb, slot, nritems, rec);
1569+
15281570
return 0;
15291571
}
15301572

check/mode-original.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ struct unaligned_extent_rec_t {
195195
#define I_ERR_INVALID_NLINK (1U << 21)
196196
#define I_ERR_INVALID_XATTR (1U << 22)
197197
#define I_ERR_DEPRECATED_FREE_INO (1U << 23)
198+
#define I_ERR_DUP_FILENAME (1U << 24)
198199

199200
struct inode_record {
200201
struct list_head backrefs;
Binary file not shown.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/bash
2+
#
3+
# Verify that check can report duplicate filename as an error
4+
5+
source "$TEST_TOP/common" || exit
6+
7+
check_prereq btrfs
8+
9+
check_image() {
10+
run_mustfail "duplicate filename not reported as error" \
11+
"$TOP/btrfs" check "$1"
12+
}
13+
14+
check_all_images

0 commit comments

Comments
 (0)