dir.c 16.9 KB
Newer Older
1
/*
2
 *  linux/fs/ext4/dir.c
3
4
5
6
7
8
9
10
11
12
13
14
 *
 * Copyright (C) 1992, 1993, 1994, 1995
 * Remy Card (card@masi.ibp.fr)
 * Laboratoire MASI - Institut Blaise Pascal
 * Universite Pierre et Marie Curie (Paris VI)
 *
 *  from
 *
 *  linux/fs/minix/dir.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 *
15
 *  ext4 directory handling functions
16
17
18
19
20
21
22
23
24
25
26
 *
 *  Big-endian to little-endian byte-swapping/bitmaps by
 *        David S. Miller (davem@caip.rutgers.edu), 1995
 *
 * Hash Tree Directory indexing (c) 2001  Daniel Phillips
 *
 */

#include <linux/fs.h>
#include <linux/buffer_head.h>
#include <linux/slab.h>
27
#include "ext4.h"
28
#include "xattr.h"
29

Al Viro's avatar
Al Viro committed
30
static int ext4_dx_readdir(struct file *, struct dir_context *);
31

32
33
/**
 * Check if the given dir-inode refers to an htree-indexed directory
34
 * (or a directory which could potentially get converted to use htree
35
36
37
38
39
40
41
42
 * indexing).
 *
 * Return 1 if it is a dx dir, 0 if not
 */
static int is_dx_dir(struct inode *inode)
{
	struct super_block *sb = inode->i_sb;

43
	if (ext4_has_feature_dir_index(inode->i_sb) &&
44
	    ((ext4_test_inode_flag(inode, EXT4_INODE_INDEX)) ||
45
46
	     ((inode->i_size >> sb->s_blocksize_bits) == 1) ||
	     ext4_has_inline_data(inode)))
47
48
49
50
51
		return 1;

	return 0;
}

52
53
54
55
/*
 * Return 0 if the directory entry is OK, and 1 if there is a problem
 *
 * Note: this is the opposite of what ext2 and ext3 historically returned...
56
57
58
 *
 * bh passed here can be an inode block or a dir data block, depending
 * on the inode inline data flag.
59
 */
60
int __ext4_check_dir_entry(const char *function, unsigned int line,
61
			   struct inode *dir, struct file *filp,
62
			   struct ext4_dir_entry_2 *de,
63
			   struct buffer_head *bh, char *buf, int size,
64
			   unsigned int offset)
65
{
66
	const char *error_msg = NULL;
67
68
	const int rlen = ext4_rec_len_from_disk(de->rec_len,
						dir->i_sb->s_blocksize);
69

70
	if (unlikely(rlen < EXT4_DIR_REC_LEN(1)))
71
		error_msg = "rec_len is smaller than minimal";
72
	else if (unlikely(rlen % 4 != 0))
73
		error_msg = "rec_len % 4 != 0";
74
	else if (unlikely(rlen < EXT4_DIR_REC_LEN(de->name_len)))
75
		error_msg = "rec_len is too small for name_len";
76
77
	else if (unlikely(((char *) de - buf) + rlen > size))
		error_msg = "directory entry across range";
78
79
	else if (unlikely(le32_to_cpu(de->inode) >
			le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count)))
80
		error_msg = "inode out of bounds";
81
82
83
	else
		return 0;

84
	if (filp)
85
		ext4_error_file(filp, function, line, bh->b_blocknr,
86
87
				"bad entry in directory: %s - offset=%u(%u), "
				"inode=%u, rec_len=%d, name_len=%d",
88
				error_msg, (unsigned) (offset % size),
89
90
91
				offset, le32_to_cpu(de->inode),
				rlen, de->name_len);
	else
92
		ext4_error_inode(dir, function, line, bh->b_blocknr,
93
94
				"bad entry in directory: %s - offset=%u(%u), "
				"inode=%u, rec_len=%d, name_len=%d",
95
				error_msg, (unsigned) (offset % size),
96
97
98
				offset, le32_to_cpu(de->inode),
				rlen, de->name_len);

99
	return 1;
100
101
}

Al Viro's avatar
Al Viro committed
102
static int ext4_readdir(struct file *file, struct dir_context *ctx)
103
{
104
	unsigned int offset;
105
	int i;
106
	struct ext4_dir_entry_2 *de;
107
	int err;
Al Viro's avatar
Al Viro committed
108
	struct inode *inode = file_inode(file);
109
	struct super_block *sb = inode->i_sb;
110
	struct buffer_head *bh = NULL;
111
	int dir_has_error = 0;
112
	struct ext4_str fname_crypto_str = {.name = NULL, .len = 0};
113

114
115
116
117
118
119
	if (ext4_encrypted_inode(inode)) {
		err = ext4_get_encryption_info(inode);
		if (err && err != -ENOKEY)
			return err;
	}

120
	if (is_dx_dir(inode)) {
Al Viro's avatar
Al Viro committed
121
		err = ext4_dx_readdir(file, ctx);
122
		if (err != ERR_BAD_DX_DIR) {
Al Viro's avatar
Al Viro committed
123
			return err;
124
125
126
127
128
		}
		/*
		 * We don't set the inode dirty flag since it's not
		 * critical that it get flushed back to the disk.
		 */
Al Viro's avatar
Al Viro committed
129
		ext4_clear_inode_flag(file_inode(file),
130
				      EXT4_INODE_INDEX);
131
	}
132
133
134

	if (ext4_has_inline_data(inode)) {
		int has_inline_data = 1;
135
		err = ext4_read_inline_dir(file, ctx,
136
137
					   &has_inline_data);
		if (has_inline_data)
138
139
140
			return err;
	}

141
142
	if (ext4_encrypted_inode(inode)) {
		err = ext4_fname_crypto_alloc_buffer(inode, EXT4_NAME_LEN,
143
						     &fname_crypto_str);
144
		if (err < 0)
145
			return err;
146
147
	}

Al Viro's avatar
Al Viro committed
148
	offset = ctx->pos & (sb->s_blocksize - 1);
149

Al Viro's avatar
Al Viro committed
150
	while (ctx->pos < inode->i_size) {
151
		struct ext4_map_blocks map;
152

153
154
155
156
157
		if (fatal_signal_pending(current)) {
			err = -ERESTARTSYS;
			goto errout;
		}
		cond_resched();
Al Viro's avatar
Al Viro committed
158
		map.m_lblk = ctx->pos >> EXT4_BLOCK_SIZE_BITS(sb);
159
160
		map.m_len = 1;
		err = ext4_map_blocks(NULL, inode, &map, 0);
161
		if (err > 0) {
162
			pgoff_t index = map.m_pblk >>
163
					(PAGE_SHIFT - inode->i_blkbits);
Al Viro's avatar
Al Viro committed
164
			if (!ra_has_index(&file->f_ra, index))
165
				page_cache_sync_readahead(
166
					sb->s_bdev->bd_inode->i_mapping,
Al Viro's avatar
Al Viro committed
167
					&file->f_ra, file,
168
					index, 1);
169
			file->f_ra.prev_pos = (loff_t)index << PAGE_SHIFT;
170
			bh = ext4_bread(NULL, inode, map.m_lblk, 0);
171
172
173
174
175
			if (IS_ERR(bh)) {
				err = PTR_ERR(bh);
				bh = NULL;
				goto errout;
			}
176
177
178
		}

		if (!bh) {
179
			if (!dir_has_error) {
Al Viro's avatar
Al Viro committed
180
				EXT4_ERROR_FILE(file, 0,
181
182
						"directory contains a "
						"hole at offset %llu",
Al Viro's avatar
Al Viro committed
183
					   (unsigned long long) ctx->pos);
184
185
				dir_has_error = 1;
			}
186
			/* corrupt size?  Maybe no more blocks to read */
Al Viro's avatar
Al Viro committed
187
			if (ctx->pos > inode->i_blocks << 9)
188
				break;
Al Viro's avatar
Al Viro committed
189
			ctx->pos += sb->s_blocksize - offset;
190
191
192
			continue;
		}

193
194
195
196
		/* Check the checksum */
		if (!buffer_verified(bh) &&
		    !ext4_dirent_csum_verify(inode,
				(struct ext4_dir_entry *)bh->b_data)) {
Al Viro's avatar
Al Viro committed
197
			EXT4_ERROR_FILE(file, 0, "directory fails checksum "
198
					"at offset %llu",
Al Viro's avatar
Al Viro committed
199
200
					(unsigned long long)ctx->pos);
			ctx->pos += sb->s_blocksize - offset;
201
			brelse(bh);
202
			bh = NULL;
203
204
205
206
			continue;
		}
		set_buffer_verified(bh);

207
208
209
210
		/* If the dir block has changed since the last call to
		 * readdir(2), then we might be pointing to an invalid
		 * dirent right now.  Scan from the start of the block
		 * to make sure. */
Al Viro's avatar
Al Viro committed
211
		if (file->f_version != inode->i_version) {
212
			for (i = 0; i < sb->s_blocksize && i < offset; ) {
213
				de = (struct ext4_dir_entry_2 *)
214
215
216
217
218
219
220
					(bh->b_data + i);
				/* It's too expensive to do a full
				 * dirent test each time round this
				 * loop, but we do have to test at
				 * least that it is non-zero.  A
				 * failure will be detected in the
				 * dirent test below. */
221
222
				if (ext4_rec_len_from_disk(de->rec_len,
					sb->s_blocksize) < EXT4_DIR_REC_LEN(1))
223
					break;
224
225
				i += ext4_rec_len_from_disk(de->rec_len,
							    sb->s_blocksize);
226
227
			}
			offset = i;
Al Viro's avatar
Al Viro committed
228
			ctx->pos = (ctx->pos & ~(sb->s_blocksize - 1))
229
				| offset;
Al Viro's avatar
Al Viro committed
230
			file->f_version = inode->i_version;
231
232
		}

Al Viro's avatar
Al Viro committed
233
		while (ctx->pos < inode->i_size
234
		       && offset < sb->s_blocksize) {
235
			de = (struct ext4_dir_entry_2 *) (bh->b_data + offset);
Al Viro's avatar
Al Viro committed
236
			if (ext4_check_dir_entry(inode, file, de, bh,
237
238
						 bh->b_data, bh->b_size,
						 offset)) {
239
				/*
Al Viro's avatar
Al Viro committed
240
				 * On error, skip to the next block
241
				 */
Al Viro's avatar
Al Viro committed
242
				ctx->pos = (ctx->pos |
243
						(sb->s_blocksize - 1)) + 1;
Al Viro's avatar
Al Viro committed
244
				break;
245
			}
246
247
			offset += ext4_rec_len_from_disk(de->rec_len,
					sb->s_blocksize);
248
			if (le32_to_cpu(de->inode)) {
249
				if (!ext4_encrypted_inode(inode)) {
250
251
252
253
254
255
					if (!dir_emit(ctx, de->name,
					    de->name_len,
					    le32_to_cpu(de->inode),
					    get_dtype(sb, de->file_type)))
						goto done;
				} else {
256
257
					int save_len = fname_crypto_str.len;

258
					/* Directory is encrypted */
259
					err = ext4_fname_disk_to_usr(inode,
260
						NULL, de, &fname_crypto_str);
261
					fname_crypto_str.len = save_len;
262
263
264
265
266
267
268
					if (err < 0)
						goto errout;
					if (!dir_emit(ctx,
					    fname_crypto_str.name, err,
					    le32_to_cpu(de->inode),
					    get_dtype(sb, de->file_type)))
						goto done;
Al Viro's avatar
Al Viro committed
269
				}
270
			}
Al Viro's avatar
Al Viro committed
271
			ctx->pos += ext4_rec_len_from_disk(de->rec_len,
272
						sb->s_blocksize);
273
		}
274
275
		if ((ctx->pos < inode->i_size) && !dir_relax(inode))
			goto done;
276
		brelse(bh);
277
278
		bh = NULL;
		offset = 0;
279
	}
280
281
282
283
284
285
286
287
done:
	err = 0;
errout:
#ifdef CONFIG_EXT4_FS_ENCRYPTION
	ext4_fname_crypto_free_buffer(&fname_crypto_str);
#endif
	brelse(bh);
	return err;
288
289
}

290
291
292
static inline int is_32bit_api(void)
{
#ifdef CONFIG_COMPAT
293
	return in_compat_syscall();
294
295
296
297
298
#else
	return (BITS_PER_LONG == 32);
#endif
}

299
300
/*
 * These functions convert from the major/minor hash to an f_pos
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
 * value for dx directories
 *
 * Upper layer (for example NFS) should specify FMODE_32BITHASH or
 * FMODE_64BITHASH explicitly. On the other hand, we allow ext4 to be mounted
 * directly on both 32-bit and 64-bit nodes, under such case, neither
 * FMODE_32BITHASH nor FMODE_64BITHASH is specified.
 */
static inline loff_t hash2pos(struct file *filp, __u32 major, __u32 minor)
{
	if ((filp->f_mode & FMODE_32BITHASH) ||
	    (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
		return major >> 1;
	else
		return ((__u64)(major >> 1) << 32) | (__u64)minor;
}

static inline __u32 pos2maj_hash(struct file *filp, loff_t pos)
{
	if ((filp->f_mode & FMODE_32BITHASH) ||
	    (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
		return (pos << 1) & 0xffffffff;
	else
		return ((pos >> 32) << 1) & 0xffffffff;
}

static inline __u32 pos2min_hash(struct file *filp, loff_t pos)
{
	if ((filp->f_mode & FMODE_32BITHASH) ||
	    (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
		return 0;
	else
		return pos & 0xffffffff;
}

/*
 * Return 32- or 64-bit end-of-file for dx directories
 */
static inline loff_t ext4_get_htree_eof(struct file *filp)
{
	if ((filp->f_mode & FMODE_32BITHASH) ||
	    (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
		return EXT4_HTREE_EOF_32BIT;
	else
		return EXT4_HTREE_EOF_64BIT;
}


/*
349
350
351
 * ext4_dir_llseek() calls generic_file_llseek_size to handle htree
 * directories, where the "offset" is in terms of the filename hash
 * value instead of the byte offset.
352
 *
353
354
355
356
357
 * Because we may return a 64-bit hash that is well beyond offset limits,
 * we need to pass the max hash as the maximum allowable offset in
 * the htree directory case.
 *
 * For non-htree, ext4_llseek already chooses the proper max offset.
358
 */
359
static loff_t ext4_dir_llseek(struct file *file, loff_t offset, int whence)
360
361
362
{
	struct inode *inode = file->f_mapping->host;
	int dx_dir = is_dx_dir(inode);
363
	loff_t htree_max = ext4_get_htree_eof(file);
364

365
	if (likely(dx_dir))
366
		return generic_file_llseek_size(file, offset, whence,
367
368
						    htree_max, htree_max);
	else
369
		return ext4_llseek(file, offset, whence);
370
}
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392

/*
 * This structure holds the nodes of the red-black tree used to store
 * the directory entry in hash order.
 */
struct fname {
	__u32		hash;
	__u32		minor_hash;
	struct rb_node	rb_hash;
	struct fname	*next;
	__u32		inode;
	__u8		name_len;
	__u8		file_type;
	char		name[0];
};

/*
 * This functoin implements a non-recursive way of freeing all of the
 * nodes in the red-black tree.
 */
static void free_rb_tree_fname(struct rb_root *root)
{
393
394
395
	struct fname *fname, *next;

	rbtree_postorder_for_each_entry_safe(fname, next, root, rb_hash)
396
		while (fname) {
397
			struct fname *old = fname;
398
			fname = fname->next;
399
			kfree(old);
400
		}
401
402

	*root = RB_ROOT;
403
404
405
}


406
407
static struct dir_private_info *ext4_htree_create_dir_info(struct file *filp,
							   loff_t pos)
408
409
410
{
	struct dir_private_info *p;

411
	p = kzalloc(sizeof(struct dir_private_info), GFP_KERNEL);
412
413
	if (!p)
		return NULL;
414
415
	p->curr_hash = pos2maj_hash(filp, pos);
	p->curr_minor_hash = pos2min_hash(filp, pos);
416
417
418
	return p;
}

419
void ext4_htree_free_dir_info(struct dir_private_info *p)
420
421
422
423
424
425
426
{
	free_rb_tree_fname(&p->root);
	kfree(p);
}

/*
 * Given a directory entry, enter it into the fname rb tree.
427
428
429
430
 *
 * When filename encryption is enabled, the dirent will hold the
 * encrypted filename, while the htree will hold decrypted filename.
 * The decrypted filename is passed in via ent_name.  parameter.
431
 */
432
int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
433
			     __u32 minor_hash,
434
435
			    struct ext4_dir_entry_2 *dirent,
			    struct ext4_str *ent_name)
436
437
{
	struct rb_node **p, *parent = NULL;
438
	struct fname *fname, *new_fn;
439
440
441
	struct dir_private_info *info;
	int len;

442
	info = dir_file->private_data;
443
444
445
	p = &info->root.rb_node;

	/* Create and allocate the fname structure */
446
	len = sizeof(struct fname) + ent_name->len + 1;
447
448
449
450
451
452
	new_fn = kzalloc(len, GFP_KERNEL);
	if (!new_fn)
		return -ENOMEM;
	new_fn->hash = hash;
	new_fn->minor_hash = minor_hash;
	new_fn->inode = le32_to_cpu(dirent->inode);
453
	new_fn->name_len = ent_name->len;
454
	new_fn->file_type = dirent->file_type;
455
456
	memcpy(new_fn->name, ent_name->name, ent_name->len);
	new_fn->name[ent_name->len] = 0;
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490

	while (*p) {
		parent = *p;
		fname = rb_entry(parent, struct fname, rb_hash);

		/*
		 * If the hash and minor hash match up, then we put
		 * them on a linked list.  This rarely happens...
		 */
		if ((new_fn->hash == fname->hash) &&
		    (new_fn->minor_hash == fname->minor_hash)) {
			new_fn->next = fname->next;
			fname->next = new_fn;
			return 0;
		}

		if (new_fn->hash < fname->hash)
			p = &(*p)->rb_left;
		else if (new_fn->hash > fname->hash)
			p = &(*p)->rb_right;
		else if (new_fn->minor_hash < fname->minor_hash)
			p = &(*p)->rb_left;
		else /* if (new_fn->minor_hash > fname->minor_hash) */
			p = &(*p)->rb_right;
	}

	rb_link_node(&new_fn->rb_hash, parent, p);
	rb_insert_color(&new_fn->rb_hash, &info->root);
	return 0;
}



/*
491
 * This is a helper function for ext4_dx_readdir.  It calls filldir
492
493
494
 * for all entres on the fname linked list.  (Normally there is only
 * one entry on the linked list, unless there are 62 bit hash collisions.)
 */
Al Viro's avatar
Al Viro committed
495
496
static int call_filldir(struct file *file, struct dir_context *ctx,
			struct fname *fname)
497
{
Al Viro's avatar
Al Viro committed
498
499
500
	struct dir_private_info *info = file->private_data;
	struct inode *inode = file_inode(file);
	struct super_block *sb = inode->i_sb;
501
502

	if (!fname) {
503
504
505
		ext4_msg(sb, KERN_ERR, "%s:%d: inode #%lu: comm %s: "
			 "called with null fname?!?", __func__, __LINE__,
			 inode->i_ino, current->comm);
506
507
		return 0;
	}
Al Viro's avatar
Al Viro committed
508
	ctx->pos = hash2pos(file, fname->hash, fname->minor_hash);
509
	while (fname) {
Al Viro's avatar
Al Viro committed
510
511
		if (!dir_emit(ctx, fname->name,
				fname->name_len,
512
				fname->inode,
Al Viro's avatar
Al Viro committed
513
				get_dtype(sb, fname->file_type))) {
514
			info->extra_fname = fname;
Al Viro's avatar
Al Viro committed
515
			return 1;
516
517
518
519
520
521
		}
		fname = fname->next;
	}
	return 0;
}

Al Viro's avatar
Al Viro committed
522
static int ext4_dx_readdir(struct file *file, struct dir_context *ctx)
523
{
Al Viro's avatar
Al Viro committed
524
525
	struct dir_private_info *info = file->private_data;
	struct inode *inode = file_inode(file);
526
527
528
529
	struct fname *fname;
	int	ret;

	if (!info) {
Al Viro's avatar
Al Viro committed
530
		info = ext4_htree_create_dir_info(file, ctx->pos);
531
532
		if (!info)
			return -ENOMEM;
Al Viro's avatar
Al Viro committed
533
		file->private_data = info;
534
535
	}

Al Viro's avatar
Al Viro committed
536
	if (ctx->pos == ext4_get_htree_eof(file))
537
538
539
		return 0;	/* EOF */

	/* Some one has messed with f_pos; reset the world */
Al Viro's avatar
Al Viro committed
540
	if (info->last_pos != ctx->pos) {
541
542
543
		free_rb_tree_fname(&info->root);
		info->curr_node = NULL;
		info->extra_fname = NULL;
Al Viro's avatar
Al Viro committed
544
545
		info->curr_hash = pos2maj_hash(file, ctx->pos);
		info->curr_minor_hash = pos2min_hash(file, ctx->pos);
546
547
548
549
550
551
	}

	/*
	 * If there are any leftover names on the hash collision
	 * chain, return them first.
	 */
552
	if (info->extra_fname) {
Al Viro's avatar
Al Viro committed
553
		if (call_filldir(file, ctx, info->extra_fname))
554
555
			goto finished;
		info->extra_fname = NULL;
556
		goto next_node;
557
	} else if (!info->curr_node)
558
559
560
561
562
563
564
565
566
		info->curr_node = rb_first(&info->root);

	while (1) {
		/*
		 * Fill the rbtree if we have no more entries,
		 * or the inode has changed since we last read in the
		 * cached entries.
		 */
		if ((!info->curr_node) ||
Al Viro's avatar
Al Viro committed
567
		    (file->f_version != inode->i_version)) {
568
569
			info->curr_node = NULL;
			free_rb_tree_fname(&info->root);
Al Viro's avatar
Al Viro committed
570
571
			file->f_version = inode->i_version;
			ret = ext4_htree_fill_tree(file, info->curr_hash,
572
573
574
575
576
						   info->curr_minor_hash,
						   &info->next_hash);
			if (ret < 0)
				return ret;
			if (ret == 0) {
Al Viro's avatar
Al Viro committed
577
				ctx->pos = ext4_get_htree_eof(file);
578
579
580
581
582
583
584
585
				break;
			}
			info->curr_node = rb_first(&info->root);
		}

		fname = rb_entry(info->curr_node, struct fname, rb_hash);
		info->curr_hash = fname->hash;
		info->curr_minor_hash = fname->minor_hash;
Al Viro's avatar
Al Viro committed
586
		if (call_filldir(file, ctx, fname))
587
			break;
588
	next_node:
589
		info->curr_node = rb_next(info->curr_node);
590
591
592
593
594
595
		if (info->curr_node) {
			fname = rb_entry(info->curr_node, struct fname,
					 rb_hash);
			info->curr_hash = fname->hash;
			info->curr_minor_hash = fname->minor_hash;
		} else {
596
			if (info->next_hash == ~0) {
Al Viro's avatar
Al Viro committed
597
				ctx->pos = ext4_get_htree_eof(file);
598
599
600
601
602
603
604
				break;
			}
			info->curr_hash = info->next_hash;
			info->curr_minor_hash = 0;
		}
	}
finished:
Al Viro's avatar
Al Viro committed
605
	info->last_pos = ctx->pos;
606
607
608
	return 0;
}

609
610
611
612
613
614
615
static int ext4_dir_open(struct inode * inode, struct file * filp)
{
	if (ext4_encrypted_inode(inode))
		return ext4_get_encryption_info(inode) ? -EACCES : 0;
	return 0;
}

616
static int ext4_release_dir(struct inode *inode, struct file *filp)
617
{
618
	if (filp->private_data)
619
		ext4_htree_free_dir_info(filp->private_data);
620
621
622

	return 0;
}
623

624
625
626
627
628
629
630
631
632
633
634
635
636
int ext4_check_all_de(struct inode *dir, struct buffer_head *bh, void *buf,
		      int buf_size)
{
	struct ext4_dir_entry_2 *de;
	int nlen, rlen;
	unsigned int offset = 0;
	char *top;

	de = (struct ext4_dir_entry_2 *)buf;
	top = buf + buf_size;
	while ((char *) de < top) {
		if (ext4_check_dir_entry(dir, NULL, de, bh,
					 buf, buf_size, offset))
637
			return -EFSCORRUPTED;
638
639
640
641
642
643
		nlen = EXT4_DIR_REC_LEN(de->name_len);
		rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
		de = (struct ext4_dir_entry_2 *)((char *)de + rlen);
		offset += rlen;
	}
	if ((char *) de > top)
644
		return -EFSCORRUPTED;
645
646
647
648

	return 0;
}

649
650
651
const struct file_operations ext4_dir_operations = {
	.llseek		= ext4_dir_llseek,
	.read		= generic_read_dir,
Al Viro's avatar
Al Viro committed
652
	.iterate	= ext4_readdir,
653
654
655
656
657
	.unlocked_ioctl = ext4_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl	= ext4_compat_ioctl,
#endif
	.fsync		= ext4_sync_file,
658
	.open		= ext4_dir_open,
659
660
	.release	= ext4_release_dir,
};