Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0
2 : /*
3 : * linux/fs/ext4/dir.c
4 : *
5 : * Copyright (C) 1992, 1993, 1994, 1995
6 : * Remy Card (card@masi.ibp.fr)
7 : * Laboratoire MASI - Institut Blaise Pascal
8 : * Universite Pierre et Marie Curie (Paris VI)
9 : *
10 : * from
11 : *
12 : * linux/fs/minix/dir.c
13 : *
14 : * Copyright (C) 1991, 1992 Linus Torvalds
15 : *
16 : * ext4 directory handling functions
17 : *
18 : * Big-endian to little-endian byte-swapping/bitmaps by
19 : * David S. Miller (davem@caip.rutgers.edu), 1995
20 : *
21 : * Hash Tree Directory indexing (c) 2001 Daniel Phillips
22 : *
23 : */
24 :
25 : #include <linux/fs.h>
26 : #include <linux/buffer_head.h>
27 : #include <linux/slab.h>
28 : #include <linux/iversion.h>
29 : #include <linux/unicode.h>
30 : #include "ext4.h"
31 : #include "xattr.h"
32 :
33 : static int ext4_dx_readdir(struct file *, struct dir_context *);
34 :
35 : /**
36 : * is_dx_dir() - check if a directory is using htree indexing
37 : * @inode: directory inode
38 : *
39 : * Check if the given dir-inode refers to an htree-indexed directory
40 : * (or a directory which could potentially get converted to use htree
41 : * indexing).
42 : *
43 : * Return 1 if it is a dx dir, 0 if not
44 : */
45 1099 : static int is_dx_dir(struct inode *inode)
46 : {
47 1099 : struct super_block *sb = inode->i_sb;
48 :
49 1099 : if (ext4_has_feature_dir_index(inode->i_sb) &&
50 1099 : ((ext4_test_inode_flag(inode, EXT4_INODE_INDEX)) ||
51 1082 : ((inode->i_size >> sb->s_blocksize_bits) == 1) ||
52 0 : ext4_has_inline_data(inode)))
53 1099 : return 1;
54 :
55 : return 0;
56 : }
57 :
58 : /*
59 : * Return 0 if the directory entry is OK, and 1 if there is a problem
60 : *
61 : * Note: this is the opposite of what ext2 and ext3 historically returned...
62 : *
63 : * bh passed here can be an inode block or a dir data block, depending
64 : * on the inode inline data flag.
65 : */
66 32436 : int __ext4_check_dir_entry(const char *function, unsigned int line,
67 : struct inode *dir, struct file *filp,
68 : struct ext4_dir_entry_2 *de,
69 : struct buffer_head *bh, char *buf, int size,
70 : unsigned int offset)
71 : {
72 32436 : const char *error_msg = NULL;
73 32436 : const int rlen = ext4_rec_len_from_disk(de->rec_len,
74 32436 : dir->i_sb->s_blocksize);
75 32436 : const int next_offset = ((char *) de - buf) + rlen;
76 :
77 32436 : if (unlikely(rlen < EXT4_DIR_REC_LEN(1)))
78 : error_msg = "rec_len is smaller than minimal";
79 32436 : else if (unlikely(rlen % 4 != 0))
80 : error_msg = "rec_len % 4 != 0";
81 32436 : else if (unlikely(rlen < EXT4_DIR_REC_LEN(de->name_len)))
82 : error_msg = "rec_len is too small for name_len";
83 32436 : else if (unlikely(next_offset > size))
84 : error_msg = "directory entry overrun";
85 32436 : else if (unlikely(next_offset > size - EXT4_DIR_REC_LEN(1) &&
86 : next_offset != size))
87 : error_msg = "directory entry too close to block end";
88 32436 : else if (unlikely(le32_to_cpu(de->inode) >
89 : le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count)))
90 : error_msg = "inode out of bounds";
91 : else
92 : return 0;
93 :
94 0 : if (filp)
95 0 : ext4_error_file(filp, function, line, bh->b_blocknr,
96 : "bad entry in directory: %s - offset=%u, "
97 : "inode=%u, rec_len=%d, name_len=%d, size=%d",
98 : error_msg, offset, le32_to_cpu(de->inode),
99 : rlen, de->name_len, size);
100 : else
101 0 : ext4_error_inode(dir, function, line, bh->b_blocknr,
102 : "bad entry in directory: %s - offset=%u, "
103 : "inode=%u, rec_len=%d, name_len=%d, size=%d",
104 : error_msg, offset, le32_to_cpu(de->inode),
105 : rlen, de->name_len, size);
106 :
107 : return 1;
108 : }
109 :
110 1099 : static int ext4_readdir(struct file *file, struct dir_context *ctx)
111 : {
112 1099 : unsigned int offset;
113 1099 : int i;
114 1099 : struct ext4_dir_entry_2 *de;
115 1099 : int err;
116 1099 : struct inode *inode = file_inode(file);
117 1099 : struct super_block *sb = inode->i_sb;
118 1099 : struct buffer_head *bh = NULL;
119 1099 : struct fscrypt_str fstr = FSTR_INIT(NULL, 0);
120 :
121 1099 : err = fscrypt_prepare_readdir(inode);
122 1099 : if (err)
123 : return err;
124 :
125 1099 : if (is_dx_dir(inode)) {
126 1099 : err = ext4_dx_readdir(file, ctx);
127 1099 : if (err != ERR_BAD_DX_DIR) {
128 : return err;
129 : }
130 : /* Can we just clear INDEX flag to ignore htree information? */
131 0 : if (!ext4_has_metadata_csum(sb)) {
132 : /*
133 : * We don't set the inode dirty flag since it's not
134 : * critical that it gets flushed back to the disk.
135 : */
136 0 : ext4_clear_inode_flag(inode, EXT4_INODE_INDEX);
137 : }
138 : }
139 :
140 0 : if (ext4_has_inline_data(inode)) {
141 0 : int has_inline_data = 1;
142 0 : err = ext4_read_inline_dir(file, ctx,
143 : &has_inline_data);
144 0 : if (has_inline_data)
145 0 : return err;
146 : }
147 :
148 0 : if (IS_ENCRYPTED(inode)) {
149 1099 : err = fscrypt_fname_alloc_buffer(EXT4_NAME_LEN, &fstr);
150 : if (err < 0)
151 : return err;
152 : }
153 :
154 0 : while (ctx->pos < inode->i_size) {
155 0 : struct ext4_map_blocks map;
156 :
157 0 : if (fatal_signal_pending(current)) {
158 0 : err = -ERESTARTSYS;
159 0 : goto errout;
160 : }
161 0 : cond_resched();
162 0 : offset = ctx->pos & (sb->s_blocksize - 1);
163 0 : map.m_lblk = ctx->pos >> EXT4_BLOCK_SIZE_BITS(sb);
164 0 : map.m_len = 1;
165 0 : err = ext4_map_blocks(NULL, inode, &map, 0);
166 0 : if (err == 0) {
167 : /* m_len should never be zero but let's avoid
168 : * an infinite loop if it somehow is */
169 0 : if (map.m_len == 0)
170 0 : map.m_len = 1;
171 0 : ctx->pos += map.m_len * sb->s_blocksize;
172 0 : continue;
173 : }
174 0 : if (err > 0) {
175 0 : pgoff_t index = map.m_pblk >>
176 0 : (PAGE_SHIFT - inode->i_blkbits);
177 0 : if (!ra_has_index(&file->f_ra, index))
178 0 : page_cache_sync_readahead(
179 0 : sb->s_bdev->bd_inode->i_mapping,
180 : &file->f_ra, file,
181 : index, 1);
182 0 : file->f_ra.prev_pos = (loff_t)index << PAGE_SHIFT;
183 0 : bh = ext4_bread(NULL, inode, map.m_lblk, 0);
184 0 : if (IS_ERR(bh)) {
185 0 : err = PTR_ERR(bh);
186 0 : bh = NULL;
187 0 : goto errout;
188 : }
189 : }
190 :
191 0 : if (!bh) {
192 : /* corrupt size? Maybe no more blocks to read */
193 0 : if (ctx->pos > inode->i_blocks << 9)
194 : break;
195 0 : ctx->pos += sb->s_blocksize - offset;
196 0 : continue;
197 : }
198 :
199 : /* Check the checksum */
200 0 : if (!buffer_verified(bh) &&
201 0 : !ext4_dirblock_csum_verify(inode, bh)) {
202 0 : EXT4_ERROR_FILE(file, 0, "directory fails checksum "
203 : "at offset %llu",
204 : (unsigned long long)ctx->pos);
205 0 : ctx->pos += sb->s_blocksize - offset;
206 0 : brelse(bh);
207 0 : bh = NULL;
208 0 : continue;
209 : }
210 0 : set_buffer_verified(bh);
211 :
212 : /* If the dir block has changed since the last call to
213 : * readdir(2), then we might be pointing to an invalid
214 : * dirent right now. Scan from the start of the block
215 : * to make sure. */
216 0 : if (!inode_eq_iversion(inode, file->f_version)) {
217 0 : for (i = 0; i < sb->s_blocksize && i < offset; ) {
218 0 : de = (struct ext4_dir_entry_2 *)
219 0 : (bh->b_data + i);
220 : /* It's too expensive to do a full
221 : * dirent test each time round this
222 : * loop, but we do have to test at
223 : * least that it is non-zero. A
224 : * failure will be detected in the
225 : * dirent test below. */
226 0 : if (ext4_rec_len_from_disk(de->rec_len,
227 : sb->s_blocksize) < EXT4_DIR_REC_LEN(1))
228 : break;
229 0 : i += ext4_rec_len_from_disk(de->rec_len,
230 : sb->s_blocksize);
231 : }
232 0 : offset = i;
233 0 : ctx->pos = (ctx->pos & ~(sb->s_blocksize - 1))
234 0 : | offset;
235 0 : file->f_version = inode_query_iversion(inode);
236 : }
237 :
238 0 : while (ctx->pos < inode->i_size
239 0 : && offset < sb->s_blocksize) {
240 0 : de = (struct ext4_dir_entry_2 *) (bh->b_data + offset);
241 0 : if (ext4_check_dir_entry(inode, file, de, bh,
242 : bh->b_data, bh->b_size,
243 : offset)) {
244 : /*
245 : * On error, skip to the next block
246 : */
247 0 : ctx->pos = (ctx->pos |
248 0 : (sb->s_blocksize - 1)) + 1;
249 0 : break;
250 : }
251 0 : offset += ext4_rec_len_from_disk(de->rec_len,
252 0 : sb->s_blocksize);
253 0 : if (le32_to_cpu(de->inode)) {
254 0 : if (!IS_ENCRYPTED(inode)) {
255 0 : if (!dir_emit(ctx, de->name,
256 0 : de->name_len,
257 : le32_to_cpu(de->inode),
258 0 : get_dtype(sb, de->file_type)))
259 0 : goto done;
260 : } else {
261 0 : int save_len = fstr.len;
262 0 : struct fscrypt_str de_name =
263 0 : FSTR_INIT(de->name,
264 : de->name_len);
265 :
266 : /* Directory is encrypted */
267 0 : err = fscrypt_fname_disk_to_usr(inode,
268 : 0, 0, &de_name, &fstr);
269 0 : de_name = fstr;
270 0 : fstr.len = save_len;
271 0 : if (err)
272 0 : goto errout;
273 : if (!dir_emit(ctx,
274 : de_name.name, de_name.len,
275 : le32_to_cpu(de->inode),
276 : get_dtype(sb, de->file_type)))
277 : goto done;
278 : }
279 : }
280 0 : ctx->pos += ext4_rec_len_from_disk(de->rec_len,
281 0 : sb->s_blocksize);
282 : }
283 0 : if ((ctx->pos < inode->i_size) && !dir_relax_shared(inode))
284 0 : goto done;
285 0 : brelse(bh);
286 0 : bh = NULL;
287 0 : offset = 0;
288 : }
289 0 : done:
290 : err = 0;
291 0 : errout:
292 0 : fscrypt_fname_free_buffer(&fstr);
293 0 : brelse(bh);
294 : return err;
295 : }
296 :
297 9544 : static inline int is_32bit_api(void)
298 : {
299 : #ifdef CONFIG_COMPAT
300 9544 : return in_compat_syscall();
301 : #else
302 : return (BITS_PER_LONG == 32);
303 : #endif
304 : }
305 :
306 : /*
307 : * These functions convert from the major/minor hash to an f_pos
308 : * value for dx directories
309 : *
310 : * Upper layer (for example NFS) should specify FMODE_32BITHASH or
311 : * FMODE_64BITHASH explicitly. On the other hand, we allow ext4 to be mounted
312 : * directly on both 32-bit and 64-bit nodes, under such case, neither
313 : * FMODE_32BITHASH nor FMODE_64BITHASH is specified.
314 : */
315 6774 : static inline loff_t hash2pos(struct file *filp, __u32 major, __u32 minor)
316 : {
317 6774 : if ((filp->f_mode & FMODE_32BITHASH) ||
318 6774 : (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
319 0 : return major >> 1;
320 : else
321 6774 : return ((__u64)(major >> 1) << 32) | (__u64)minor;
322 : }
323 :
324 557 : static inline __u32 pos2maj_hash(struct file *filp, loff_t pos)
325 : {
326 557 : if ((filp->f_mode & FMODE_32BITHASH) ||
327 557 : (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
328 0 : return (pos << 1) & 0xffffffff;
329 : else
330 557 : return ((pos >> 32) << 1) & 0xffffffff;
331 : }
332 :
333 557 : static inline __u32 pos2min_hash(struct file *filp, loff_t pos)
334 : {
335 557 : if ((filp->f_mode & FMODE_32BITHASH) ||
336 557 : (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
337 : return 0;
338 : else
339 557 : return pos & 0xffffffff;
340 : }
341 :
342 : /*
343 : * Return 32- or 64-bit end-of-file for dx directories
344 : */
345 1656 : static inline loff_t ext4_get_htree_eof(struct file *filp)
346 : {
347 1656 : if ((filp->f_mode & FMODE_32BITHASH) ||
348 1656 : (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
349 : return EXT4_HTREE_EOF_32BIT;
350 : else
351 1656 : return EXT4_HTREE_EOF_64BIT;
352 : }
353 :
354 :
355 : /*
356 : * ext4_dir_llseek() calls generic_file_llseek_size to handle htree
357 : * directories, where the "offset" is in terms of the filename hash
358 : * value instead of the byte offset.
359 : *
360 : * Because we may return a 64-bit hash that is well beyond offset limits,
361 : * we need to pass the max hash as the maximum allowable offset in
362 : * the htree directory case.
363 : *
364 : * For non-htree, ext4_llseek already chooses the proper max offset.
365 : */
366 0 : static loff_t ext4_dir_llseek(struct file *file, loff_t offset, int whence)
367 : {
368 0 : struct inode *inode = file->f_mapping->host;
369 0 : int dx_dir = is_dx_dir(inode);
370 0 : loff_t ret, htree_max = ext4_get_htree_eof(file);
371 :
372 0 : if (likely(dx_dir))
373 0 : ret = generic_file_llseek_size(file, offset, whence,
374 : htree_max, htree_max);
375 : else
376 0 : ret = ext4_llseek(file, offset, whence);
377 0 : file->f_version = inode_peek_iversion(inode) - 1;
378 0 : return ret;
379 : }
380 :
381 : /*
382 : * This structure holds the nodes of the red-black tree used to store
383 : * the directory entry in hash order.
384 : */
385 : struct fname {
386 : __u32 hash;
387 : __u32 minor_hash;
388 : struct rb_node rb_hash;
389 : struct fname *next;
390 : __u32 inode;
391 : __u8 name_len;
392 : __u8 file_type;
393 : char name[];
394 : };
395 :
396 : /*
397 : * This functoin implements a non-recursive way of freeing all of the
398 : * nodes in the red-black tree.
399 : */
400 1203 : static void free_rb_tree_fname(struct rb_root *root)
401 : {
402 1203 : struct fname *fname, *next;
403 :
404 9179 : rbtree_postorder_for_each_entry_safe(fname, next, root, rb_hash)
405 13546 : while (fname) {
406 6773 : struct fname *old = fname;
407 6773 : fname = fname->next;
408 6773 : kfree(old);
409 : }
410 :
411 1203 : *root = RB_ROOT;
412 1203 : }
413 :
414 :
415 557 : static struct dir_private_info *ext4_htree_create_dir_info(struct file *filp,
416 : loff_t pos)
417 : {
418 557 : struct dir_private_info *p;
419 :
420 557 : p = kzalloc(sizeof(*p), GFP_KERNEL);
421 557 : if (!p)
422 : return NULL;
423 557 : p->curr_hash = pos2maj_hash(filp, pos);
424 557 : p->curr_minor_hash = pos2min_hash(filp, pos);
425 557 : return p;
426 : }
427 :
428 557 : void ext4_htree_free_dir_info(struct dir_private_info *p)
429 : {
430 0 : free_rb_tree_fname(&p->root);
431 557 : kfree(p);
432 557 : }
433 :
434 : /*
435 : * Given a directory entry, enter it into the fname rb tree.
436 : *
437 : * When filename encryption is enabled, the dirent will hold the
438 : * encrypted filename, while the htree will hold decrypted filename.
439 : * The decrypted filename is passed in via ent_name. parameter.
440 : */
441 6773 : int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
442 : __u32 minor_hash,
443 : struct ext4_dir_entry_2 *dirent,
444 : struct fscrypt_str *ent_name)
445 : {
446 6773 : struct rb_node **p, *parent = NULL;
447 6773 : struct fname *fname, *new_fn;
448 6773 : struct dir_private_info *info;
449 6773 : int len;
450 :
451 6773 : info = dir_file->private_data;
452 6773 : p = &info->root.rb_node;
453 :
454 : /* Create and allocate the fname structure */
455 6773 : len = sizeof(struct fname) + ent_name->len + 1;
456 6773 : new_fn = kzalloc(len, GFP_KERNEL);
457 6773 : if (!new_fn)
458 : return -ENOMEM;
459 6773 : new_fn->hash = hash;
460 6773 : new_fn->minor_hash = minor_hash;
461 6773 : new_fn->inode = le32_to_cpu(dirent->inode);
462 6773 : new_fn->name_len = ent_name->len;
463 6773 : new_fn->file_type = dirent->file_type;
464 6773 : memcpy(new_fn->name, ent_name->name, ent_name->len);
465 :
466 32274 : while (*p) {
467 25501 : parent = *p;
468 25501 : fname = rb_entry(parent, struct fname, rb_hash);
469 :
470 : /*
471 : * If the hash and minor hash match up, then we put
472 : * them on a linked list. This rarely happens...
473 : */
474 25501 : if ((new_fn->hash == fname->hash) &&
475 : (new_fn->minor_hash == fname->minor_hash)) {
476 0 : new_fn->next = fname->next;
477 0 : fname->next = new_fn;
478 0 : return 0;
479 : }
480 :
481 25501 : if (new_fn->hash < fname->hash)
482 9810 : p = &(*p)->rb_left;
483 15691 : else if (new_fn->hash > fname->hash)
484 15691 : p = &(*p)->rb_right;
485 0 : else if (new_fn->minor_hash < fname->minor_hash)
486 0 : p = &(*p)->rb_left;
487 : else /* if (new_fn->minor_hash > fname->minor_hash) */
488 0 : p = &(*p)->rb_right;
489 : }
490 :
491 6773 : rb_link_node(&new_fn->rb_hash, parent, p);
492 6773 : rb_insert_color(&new_fn->rb_hash, &info->root);
493 6773 : return 0;
494 : }
495 :
496 :
497 :
498 : /*
499 : * This is a helper function for ext4_dx_readdir. It calls filldir
500 : * for all entres on the fname linked list. (Normally there is only
501 : * one entry on the linked list, unless there are 62 bit hash collisions.)
502 : */
503 6774 : static int call_filldir(struct file *file, struct dir_context *ctx,
504 : struct fname *fname)
505 : {
506 6774 : struct dir_private_info *info = file->private_data;
507 6774 : struct inode *inode = file_inode(file);
508 6774 : struct super_block *sb = inode->i_sb;
509 :
510 6774 : if (!fname) {
511 0 : ext4_msg(sb, KERN_ERR, "%s:%d: inode #%lu: comm %s: "
512 : "called with null fname?!?", __func__, __LINE__,
513 : inode->i_ino, current->comm);
514 0 : return 0;
515 : }
516 6774 : ctx->pos = hash2pos(file, fname->hash, fname->minor_hash);
517 13547 : while (fname) {
518 6774 : if (!dir_emit(ctx, fname->name,
519 6774 : fname->name_len,
520 6774 : fname->inode,
521 13548 : get_dtype(sb, fname->file_type))) {
522 1 : info->extra_fname = fname;
523 1 : return 1;
524 : }
525 6773 : fname = fname->next;
526 : }
527 : return 0;
528 : }
529 :
530 1099 : static int ext4_dx_readdir(struct file *file, struct dir_context *ctx)
531 : {
532 1099 : struct dir_private_info *info = file->private_data;
533 1099 : struct inode *inode = file_inode(file);
534 1099 : struct fname *fname;
535 1099 : int ret;
536 :
537 1099 : if (!info) {
538 557 : info = ext4_htree_create_dir_info(file, ctx->pos);
539 557 : if (!info)
540 : return -ENOMEM;
541 557 : file->private_data = info;
542 : }
543 :
544 1099 : if (ctx->pos == ext4_get_htree_eof(file))
545 : return 0; /* EOF */
546 :
547 : /* Some one has messed with f_pos; reset the world */
548 558 : if (info->last_pos != ctx->pos) {
549 0 : free_rb_tree_fname(&info->root);
550 0 : info->curr_node = NULL;
551 0 : info->extra_fname = NULL;
552 0 : info->curr_hash = pos2maj_hash(file, ctx->pos);
553 0 : info->curr_minor_hash = pos2min_hash(file, ctx->pos);
554 : }
555 :
556 : /*
557 : * If there are any leftover names on the hash collision
558 : * chain, return them first.
559 : */
560 558 : if (info->extra_fname) {
561 1 : if (call_filldir(file, ctx, info->extra_fname))
562 0 : goto finished;
563 1 : info->extra_fname = NULL;
564 1 : goto next_node;
565 557 : } else if (!info->curr_node)
566 557 : info->curr_node = rb_first(&info->root);
567 :
568 6775 : while (1) {
569 : /*
570 : * Fill the rbtree if we have no more entries,
571 : * or the inode has changed since we last read in the
572 : * cached entries.
573 : */
574 6775 : if ((!info->curr_node) ||
575 6129 : !inode_eq_iversion(inode, file->f_version)) {
576 646 : info->curr_node = NULL;
577 646 : free_rb_tree_fname(&info->root);
578 646 : file->f_version = inode_query_iversion(inode);
579 646 : ret = ext4_htree_fill_tree(file, info->curr_hash,
580 : info->curr_minor_hash,
581 : &info->next_hash);
582 646 : if (ret < 0)
583 : return ret;
584 646 : if (ret == 0) {
585 2 : ctx->pos = ext4_get_htree_eof(file);
586 2 : break;
587 : }
588 644 : info->curr_node = rb_first(&info->root);
589 : }
590 :
591 6773 : fname = rb_entry(info->curr_node, struct fname, rb_hash);
592 6773 : info->curr_hash = fname->hash;
593 6773 : info->curr_minor_hash = fname->minor_hash;
594 6773 : if (call_filldir(file, ctx, fname))
595 : break;
596 6772 : next_node:
597 6773 : info->curr_node = rb_next(info->curr_node);
598 6773 : if (info->curr_node) {
599 6129 : fname = rb_entry(info->curr_node, struct fname,
600 : rb_hash);
601 6129 : info->curr_hash = fname->hash;
602 6129 : info->curr_minor_hash = fname->minor_hash;
603 : } else {
604 644 : if (info->next_hash == ~0) {
605 555 : ctx->pos = ext4_get_htree_eof(file);
606 555 : break;
607 : }
608 89 : info->curr_hash = info->next_hash;
609 89 : info->curr_minor_hash = 0;
610 : }
611 : }
612 1 : finished:
613 558 : info->last_pos = ctx->pos;
614 558 : return 0;
615 : }
616 :
617 598 : static int ext4_release_dir(struct inode *inode, struct file *filp)
618 : {
619 598 : if (filp->private_data)
620 557 : ext4_htree_free_dir_info(filp->private_data);
621 :
622 598 : return 0;
623 : }
624 :
625 0 : int ext4_check_all_de(struct inode *dir, struct buffer_head *bh, void *buf,
626 : int buf_size)
627 : {
628 0 : struct ext4_dir_entry_2 *de;
629 0 : int rlen;
630 0 : unsigned int offset = 0;
631 0 : char *top;
632 :
633 0 : de = (struct ext4_dir_entry_2 *)buf;
634 0 : top = buf + buf_size;
635 0 : while ((char *) de < top) {
636 0 : if (ext4_check_dir_entry(dir, NULL, de, bh,
637 : buf, buf_size, offset))
638 : return -EFSCORRUPTED;
639 0 : rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
640 0 : de = (struct ext4_dir_entry_2 *)((char *)de + rlen);
641 0 : offset += rlen;
642 : }
643 0 : if ((char *) de > top)
644 0 : return -EFSCORRUPTED;
645 :
646 : return 0;
647 : }
648 :
649 : const struct file_operations ext4_dir_operations = {
650 : .llseek = ext4_dir_llseek,
651 : .read = generic_read_dir,
652 : .iterate_shared = ext4_readdir,
653 : .unlocked_ioctl = ext4_ioctl,
654 : #ifdef CONFIG_COMPAT
655 : .compat_ioctl = ext4_compat_ioctl,
656 : #endif
657 : .fsync = ext4_sync_file,
658 : .release = ext4_release_dir,
659 : };
|