From b7dd40d05235871a5e6cae02f38c14dc6487d352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Tue, 6 Sep 2016 04:36:46 +0200 Subject: ext4: Scan all directory blocks when looking up an entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scanning only the direct blocks of the directory file may falsely report an existing file as nonexisting, and worse can also lead to creation of a duplicate entry on file creation. Signed-off-by: Stefan BrĂ¼ns Reviewed-by: Lukasz Majewski --- fs/ext4/ext4_common.c | 84 ++++++++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 44 deletions(-) (limited to 'fs') diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 3937e978e1..deca954e08 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -525,64 +525,57 @@ static int search_dir(struct ext2_inode *parent_inode, char *dirname) { int status; int inodeno = 0; - int totalbytes; - int templength; - int direct_blk_idx; + int offset; + int blk_idx; long int blknr; - char *ptr = NULL; - unsigned char *block_buffer = NULL; + char *block_buffer = NULL; struct ext2_dirent *dir = NULL; struct ext_filesystem *fs = get_fs(); + uint32_t directory_blocks; + char *direntname; - /* read the block no allocated to a file */ - for (direct_blk_idx = 0; direct_blk_idx < INDIRECT_BLOCKS; - direct_blk_idx++) { - blknr = read_allocated_block(parent_inode, direct_blk_idx); - if (blknr == 0) - goto fail; + directory_blocks = le32_to_cpu(parent_inode->size) >> + LOG2_BLOCK_SIZE(ext4fs_root); - /* read the blocks of parent inode */ - block_buffer = zalloc(fs->blksz); - if (!block_buffer) + block_buffer = zalloc(fs->blksz); + if (!block_buffer) + goto fail; + + /* get the block no allocated to a file */ + for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) { + blknr = read_allocated_block(parent_inode, blk_idx); + if (blknr == 0) goto fail; + /* read the directory block */ status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, (char *)block_buffer); if (status == 0) goto fail; - dir = (struct ext2_dirent *)block_buffer; - ptr = (char *)dir; - totalbytes = 0; - while (le16_to_cpu(dir->direntlen) >= 0) { - /* - * blocksize-totalbytes because last directory - * length i.e.,*dir->direntlen is free availble - * space in the block that means - * it is a last entry of directory entry - */ - if (dir->inode && (strlen(dirname) == dir->namelen)) { - if (strncmp(dirname, ptr + sizeof(struct ext2_dirent), dir->namelen) == 0) { - inodeno = le32_to_cpu(dir->inode); - break; - } - } + offset = 0; + do { + dir = (struct ext2_dirent *)(block_buffer + offset); + direntname = (char*)(dir) + sizeof(struct ext2_dirent); - if (fs->blksz - totalbytes == le16_to_cpu(dir->direntlen)) + int direntlen = le16_to_cpu(dir->direntlen); + if (direntlen < sizeof(struct ext2_dirent)) break; - /* traversing the each directory entry */ - templength = le16_to_cpu(dir->direntlen); - totalbytes = totalbytes + templength; - dir = (struct ext2_dirent *)((char *)dir + templength); - ptr = (char *)dir; - } + if (dir->inode && (strlen(dirname) == dir->namelen) && + (strncmp(dirname, direntname, dir->namelen) == 0)) { + inodeno = le32_to_cpu(dir->inode); + break; + } + + offset += direntlen; - free(block_buffer); - block_buffer = NULL; + } while (offset < fs->blksz); - if (inodeno > 0) + if (inodeno > 0) { + free(block_buffer); return inodeno; + } } fail: @@ -834,14 +827,17 @@ fail: int ext4fs_filename_unlink(char *filename) { - short direct_blk_idx = 0; + int blk_idx; long int blknr = -1; int inodeno = -1; + uint32_t directory_blocks; + + directory_blocks = le32_to_cpu(g_parent_inode->size) >> + LOG2_BLOCK_SIZE(ext4fs_root); /* read the block no allocated to a file */ - for (direct_blk_idx = 0; direct_blk_idx < INDIRECT_BLOCKS; - direct_blk_idx++) { - blknr = read_allocated_block(g_parent_inode, direct_blk_idx); + for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) { + blknr = read_allocated_block(g_parent_inode, blk_idx); if (blknr == 0) break; inodeno = unlink_filename(filename, blknr); -- cgit v1.2.3