aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext4/dir.c')
-rw-r--r--fs/ext4/dir.c41
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"
31static 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
35static int ext4_dx_readdir(struct file *filp, 32static int ext4_dx_readdir(struct file *filp,
36 void *dirent, filldir_t filldir); 33 void *dirent, filldir_t filldir);
37 34
38static 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 */
72int __ext4_check_dir_entry(const char *function, unsigned int line, 63int __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 */