diff options
Diffstat (limited to 'fs/ext4/dir.c')
-rw-r--r-- | fs/ext4/dir.c | 41 |
1 files changed, 20 insertions, 21 deletions
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index 8e07d2a5a139..b8d877f6c1fa 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c | |||
@@ -27,23 +27,11 @@ | |||
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/rbtree.h> | 28 | #include <linux/rbtree.h> |
29 | #include "ext4.h" | 29 | #include "ext4.h" |
30 | 30 | #include "xattr.h" | |
31 | static unsigned char ext4_filetype_table[] = { | ||
32 | DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK | ||
33 | }; | ||
34 | 31 | ||
35 | static int ext4_dx_readdir(struct file *filp, | 32 | static int ext4_dx_readdir(struct file *filp, |
36 | void *dirent, filldir_t filldir); | 33 | void *dirent, filldir_t filldir); |
37 | 34 | ||
38 | static unsigned char get_dtype(struct super_block *sb, int filetype) | ||
39 | { | ||
40 | if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FILETYPE) || | ||
41 | (filetype >= EXT4_FT_MAX)) | ||
42 | return DT_UNKNOWN; | ||
43 | |||
44 | return (ext4_filetype_table[filetype]); | ||
45 | } | ||
46 | |||
47 | /** | 35 | /** |
48 | * Check if the given dir-inode refers to an htree-indexed directory | 36 | * Check if the given dir-inode refers to an htree-indexed directory |
49 | * (or a directory which chould potentially get coverted to use htree | 37 | * (or a directory which chould potentially get coverted to use htree |
@@ -68,11 +56,14 @@ static int is_dx_dir(struct inode *inode) | |||
68 | * Return 0 if the directory entry is OK, and 1 if there is a problem | 56 | * Return 0 if the directory entry is OK, and 1 if there is a problem |
69 | * | 57 | * |
70 | * Note: this is the opposite of what ext2 and ext3 historically returned... | 58 | * Note: this is the opposite of what ext2 and ext3 historically returned... |
59 | * | ||
60 | * bh passed here can be an inode block or a dir data block, depending | ||
61 | * on the inode inline data flag. | ||
71 | */ | 62 | */ |
72 | int __ext4_check_dir_entry(const char *function, unsigned int line, | 63 | int __ext4_check_dir_entry(const char *function, unsigned int line, |
73 | struct inode *dir, struct file *filp, | 64 | struct inode *dir, struct file *filp, |
74 | struct ext4_dir_entry_2 *de, | 65 | struct ext4_dir_entry_2 *de, |
75 | struct buffer_head *bh, | 66 | struct buffer_head *bh, char *buf, int size, |
76 | unsigned int offset) | 67 | unsigned int offset) |
77 | { | 68 | { |
78 | const char *error_msg = NULL; | 69 | const char *error_msg = NULL; |
@@ -85,9 +76,8 @@ int __ext4_check_dir_entry(const char *function, unsigned int line, | |||
85 | error_msg = "rec_len % 4 != 0"; | 76 | error_msg = "rec_len % 4 != 0"; |
86 | else if (unlikely(rlen < EXT4_DIR_REC_LEN(de->name_len))) | 77 | else if (unlikely(rlen < EXT4_DIR_REC_LEN(de->name_len))) |
87 | error_msg = "rec_len is too small for name_len"; | 78 | error_msg = "rec_len is too small for name_len"; |
88 | else if (unlikely(((char *) de - bh->b_data) + rlen > | 79 | else if (unlikely(((char *) de - buf) + rlen > size)) |
89 | dir->i_sb->s_blocksize)) | 80 | error_msg = "directory entry across range"; |
90 | error_msg = "directory entry across blocks"; | ||
91 | else if (unlikely(le32_to_cpu(de->inode) > | 81 | else if (unlikely(le32_to_cpu(de->inode) > |
92 | le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count))) | 82 | le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count))) |
93 | error_msg = "inode out of bounds"; | 83 | error_msg = "inode out of bounds"; |
@@ -98,14 +88,14 @@ int __ext4_check_dir_entry(const char *function, unsigned int line, | |||
98 | ext4_error_file(filp, function, line, bh->b_blocknr, | 88 | ext4_error_file(filp, function, line, bh->b_blocknr, |
99 | "bad entry in directory: %s - offset=%u(%u), " | 89 | "bad entry in directory: %s - offset=%u(%u), " |
100 | "inode=%u, rec_len=%d, name_len=%d", | 90 | "inode=%u, rec_len=%d, name_len=%d", |
101 | error_msg, (unsigned) (offset % bh->b_size), | 91 | error_msg, (unsigned) (offset % size), |
102 | offset, le32_to_cpu(de->inode), | 92 | offset, le32_to_cpu(de->inode), |
103 | rlen, de->name_len); | 93 | rlen, de->name_len); |
104 | else | 94 | else |
105 | ext4_error_inode(dir, function, line, bh->b_blocknr, | 95 | ext4_error_inode(dir, function, line, bh->b_blocknr, |
106 | "bad entry in directory: %s - offset=%u(%u), " | 96 | "bad entry in directory: %s - offset=%u(%u), " |
107 | "inode=%u, rec_len=%d, name_len=%d", | 97 | "inode=%u, rec_len=%d, name_len=%d", |
108 | error_msg, (unsigned) (offset % bh->b_size), | 98 | error_msg, (unsigned) (offset % size), |
109 | offset, le32_to_cpu(de->inode), | 99 | offset, le32_to_cpu(de->inode), |
110 | rlen, de->name_len); | 100 | rlen, de->name_len); |
111 | 101 | ||
@@ -125,6 +115,14 @@ static int ext4_readdir(struct file *filp, | |||
125 | int ret = 0; | 115 | int ret = 0; |
126 | int dir_has_error = 0; | 116 | int dir_has_error = 0; |
127 | 117 | ||
118 | if (ext4_has_inline_data(inode)) { | ||
119 | int has_inline_data = 1; | ||
120 | ret = ext4_read_inline_dir(filp, dirent, filldir, | ||
121 | &has_inline_data); | ||
122 | if (has_inline_data) | ||
123 | return ret; | ||
124 | } | ||
125 | |||
128 | if (is_dx_dir(inode)) { | 126 | if (is_dx_dir(inode)) { |
129 | err = ext4_dx_readdir(filp, dirent, filldir); | 127 | err = ext4_dx_readdir(filp, dirent, filldir); |
130 | if (err != ERR_BAD_DX_DIR) { | 128 | if (err != ERR_BAD_DX_DIR) { |
@@ -221,8 +219,9 @@ revalidate: | |||
221 | while (!error && filp->f_pos < inode->i_size | 219 | while (!error && filp->f_pos < inode->i_size |
222 | && offset < sb->s_blocksize) { | 220 | && offset < sb->s_blocksize) { |
223 | de = (struct ext4_dir_entry_2 *) (bh->b_data + offset); | 221 | de = (struct ext4_dir_entry_2 *) (bh->b_data + offset); |
224 | if (ext4_check_dir_entry(inode, filp, de, | 222 | if (ext4_check_dir_entry(inode, filp, de, bh, |
225 | bh, offset)) { | 223 | bh->b_data, bh->b_size, |
224 | offset)) { | ||
226 | /* | 225 | /* |
227 | * On error, skip the f_pos to the next block | 226 | * On error, skip the f_pos to the next block |
228 | */ | 227 | */ |