121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o/*
221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * dir_iterate.c --- ext2fs directory iteration operations
3efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o *
421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * Copyright (C) 1993, 1994, 1994, 1995, 1996, 1997 Theodore Ts'o.
521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o *
621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * %Begin-Header%
7543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * This file may be redistributed under the terms of the GNU Library
8543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * General Public License, version 2.
921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * %End-Header%
1021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o */
1121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
1221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o#include <stdio.h>
1321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o#include <string.h>
144cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#if HAVE_UNISTD_H
1521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o#include <unistd.h>
164cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#endif
1721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o#if HAVE_ERRNO_H
1821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o#include <errno.h>
1921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o#endif
2021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
21b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h"
2221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o#include "ext2fsP.h"
2321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
248a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o#define EXT4_MAX_REC_LEN		((1<<16)-1)
258a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o
268a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'oerrcode_t ext2fs_get_rec_len(ext2_filsys fs,
278a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o			     struct ext2_dir_entry *dirent,
288a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o			     unsigned int *rec_len)
298a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o{
308a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o	unsigned int len = dirent->rec_len;
318a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o
32a4fdf09414e04e9ecb995aa0af2f525d335987aeTheodore Ts'o	if (fs->blocksize < 65536)
33a4fdf09414e04e9ecb995aa0af2f525d335987aeTheodore Ts'o		*rec_len = len;
34a4fdf09414e04e9ecb995aa0af2f525d335987aeTheodore Ts'o	else if (len == EXT4_MAX_REC_LEN || len == 0)
358a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		*rec_len = fs->blocksize;
368a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o	else
378a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		*rec_len = (len & 65532) | ((len & 3) << 16);
388a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o	return 0;
398a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o}
408a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o
418a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'oerrcode_t ext2fs_set_rec_len(ext2_filsys fs,
428a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o			     unsigned int len,
438a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o			     struct ext2_dir_entry *dirent)
448a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o{
458a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o	if ((len > fs->blocksize) || (fs->blocksize > (1 << 18)) || (len & 3))
468a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		return EINVAL;
478a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o	if (len < 65536) {
488a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		dirent->rec_len = len;
498a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		return 0;
508a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o	}
518a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o	if (len == fs->blocksize) {
528a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		if (fs->blocksize == 65536)
538a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o			dirent->rec_len = EXT4_MAX_REC_LEN;
548a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		else
558a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o			dirent->rec_len = 0;
568a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o	} else
578a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		dirent->rec_len = (len & 65532) | ((len >> 16) & 3);
588a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o	return 0;
598a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o}
608a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o
618bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o/*
628bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o * This function checks to see whether or not a potential deleted
638bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o * directory entry looks valid.  What we do is check the deleted entry
648bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o * and each successive entry to make sure that they all look valid and
658bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o * that the last deleted entry ends at the beginning of the next
668bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o * undeleted entry.  Returns 1 if the deleted entry looks valid, zero
678bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o * if not valid.
688bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o */
696a8da46d284721e95f893d4f229a2bec473797e1Nic Casestatic int ext2fs_validate_entry(ext2_filsys fs, char *buf,
706a8da46d284721e95f893d4f229a2bec473797e1Nic Case				 unsigned int offset,
716a8da46d284721e95f893d4f229a2bec473797e1Nic Case				 unsigned int final_offset)
728bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o{
738bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o	struct ext2_dir_entry *dirent;
748a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o	unsigned int rec_len;
756a8da46d284721e95f893d4f229a2bec473797e1Nic Case#define DIRENT_MIN_LENGTH 12
76efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
776a8da46d284721e95f893d4f229a2bec473797e1Nic Case	while ((offset < final_offset) &&
786a8da46d284721e95f893d4f229a2bec473797e1Nic Case	       (offset <= fs->blocksize - DIRENT_MIN_LENGTH)) {
798bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o		dirent = (struct ext2_dir_entry *)(buf + offset);
808a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		if (ext2fs_get_rec_len(fs, dirent, &rec_len))
818a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o			return 0;
825dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o		offset += rec_len;
835dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o		if ((rec_len < 8) ||
845dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o		    ((rec_len % 4) != 0) ||
8525c7e0c3042cb92a71d25cb3c2709a55b9f120a6Theodore Ts'o		    ((((unsigned) dirent->name_len & 0xFF)+8) > rec_len))
868bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o			return 0;
878bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o	}
888bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o	return (offset == final_offset);
898bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o}
908bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o
918bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'oerrcode_t ext2fs_dir_iterate2(ext2_filsys fs,
928bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o			      ext2_ino_t dir,
938bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o			      int flags,
948bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o			      char *block_buf,
958bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o			      int (*func)(ext2_ino_t	dir,
968bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o					  int		entry,
978bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o					  struct ext2_dir_entry *dirent,
988bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o					  int	offset,
998bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o					  int	blocksize,
1008bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o					  char	*buf,
1018bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o					  void	*priv_data),
1028bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o			      void *priv_data)
10321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o{
10421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	struct		dir_context	ctx;
10521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	errcode_t	retval;
106efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
10721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
10821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
10921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	retval = ext2fs_check_directory(fs, dir);
11021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (retval)
11121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		return retval;
112efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
11321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	ctx.dir = dir;
11421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	ctx.flags = flags;
11521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (block_buf)
11621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		ctx.buf = block_buf;
11721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	else {
118c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		retval = ext2fs_get_mem(fs->blocksize, &ctx.buf);
1197b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		if (retval)
1207b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o			return retval;
12121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
12221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	ctx.func = func;
123b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o	ctx.priv_data = priv_data;
12421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	ctx.errcode = 0;
125e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_READ_ONLY, 0,
12636a43d675ef61d0f5d5b2ad62d2e670c408d14acTheodore Ts'o				       ext2fs_process_dir_block, &ctx);
12721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (!block_buf)
128c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&ctx.buf);
12921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (retval)
13021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		return retval;
13121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	return ctx.errcode;
13221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o}
13321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
1348bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'ostruct xlate {
1358bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o	int (*func)(struct ext2_dir_entry *dirent,
1368bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o		    int		offset,
1378bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o		    int		blocksize,
1388bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o		    char	*buf,
1398bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o		    void	*priv_data);
1408bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o	void *real_private;
1418bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o};
1428bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o
143544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic int xlate_func(ext2_ino_t dir EXT2FS_ATTR((unused)),
144544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		      int entry EXT2FS_ATTR((unused)),
1458bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o		      struct ext2_dir_entry *dirent, int offset,
1468bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o		      int blocksize, char *buf, void *priv_data)
1478bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o{
1488bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o	struct xlate *xl = (struct xlate *) priv_data;
1498bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o
1508bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o	return (*xl->func)(dirent, offset, blocksize, buf, xl->real_private);
1518bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o}
1528bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o
153e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallerrcode_t ext2fs_dir_iterate(ext2_filsys fs,
154e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     ext2_ino_t dir,
155e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     int flags,
156e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     char *block_buf,
157e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     int (*func)(struct ext2_dir_entry *dirent,
158e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					 int	offset,
159e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					 int	blocksize,
160e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					 char	*buf,
161e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					 void	*priv_data),
162e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     void *priv_data)
1638bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o{
1648bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o	struct xlate xl;
165efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
1668bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o	xl.real_private = priv_data;
1678bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o	xl.func = func;
1688bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o
1698bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o	return ext2fs_dir_iterate2(fs, dir, flags, block_buf,
1708bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o				   xlate_func, &xl);
1718bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o}
1728bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o
1738bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o
17421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o/*
17521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * Helper function which is private to this module.  Used by
17621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * ext2fs_dir_iterate() and ext2fs_dblist_dir_iterate()
17721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o */
178544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'oint ext2fs_process_dir_block(ext2_filsys fs,
179e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     blk64_t	*blocknr,
180544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			     e2_blkcnt_t blockcnt,
181e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     blk64_t	ref_block EXT2FS_ATTR((unused)),
182544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			     int	ref_offset EXT2FS_ATTR((unused)),
183544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			     void	*priv_data)
18421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o{
185b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o	struct dir_context *ctx = (struct dir_context *) priv_data;
186544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned int	offset = 0;
187544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned int	next_real_entry = 0;
18821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	int		ret = 0;
18921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	int		changed = 0;
19021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	int		do_abort = 0;
19125c7e0c3042cb92a71d25cb3c2709a55b9f120a6Theodore Ts'o	unsigned int	rec_len, size;
19225c7e0c3042cb92a71d25cb3c2709a55b9f120a6Theodore Ts'o	int		entry;
19321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	struct ext2_dir_entry *dirent;
19421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
19521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (blockcnt < 0)
19621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		return 0;
19721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
19836a43d675ef61d0f5d5b2ad62d2e670c408d14acTheodore Ts'o	entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE;
199efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
200e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ctx->errcode = ext2fs_read_dir_block3(fs, *blocknr, ctx->buf, 0);
20121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (ctx->errcode)
20221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		return BLOCK_ABORT;
20321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
20421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	while (offset < fs->blocksize) {
20521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		dirent = (struct ext2_dir_entry *) (ctx->buf + offset);
2068a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		if (ext2fs_get_rec_len(fs, dirent, &rec_len))
2078a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o			return BLOCK_ABORT;
2085dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o		if (((offset + rec_len) > fs->blocksize) ||
2095dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o		    (rec_len < 8) ||
2105dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o		    ((rec_len % 4) != 0) ||
21125c7e0c3042cb92a71d25cb3c2709a55b9f120a6Theodore Ts'o		    ((((unsigned) dirent->name_len & 0xFF)+8) > rec_len)) {
212813bbb25a24ebba5177da18be413ea742efe5a8aTheodore Ts'o			ctx->errcode = EXT2_ET_DIR_CORRUPTED;
213813bbb25a24ebba5177da18be413ea742efe5a8aTheodore Ts'o			return BLOCK_ABORT;
214813bbb25a24ebba5177da18be413ea742efe5a8aTheodore Ts'o		}
21521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		if (!dirent->inode &&
21621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		    !(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY))
21721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			goto next;
21821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
2198bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o		ret = (ctx->func)(ctx->dir,
2208bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o				  (next_real_entry > offset) ?
2218bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o				  DIRENT_DELETED_FILE : entry,
2228bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o				  dirent, offset,
2238bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o				  fs->blocksize, ctx->buf,
2248bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o				  ctx->priv_data);
2258bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o		if (entry < DIRENT_OTHER_FILE)
2268bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o			entry++;
227efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
2285dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o		if (ret & DIRENT_CHANGED) {
2298a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o			if (ext2fs_get_rec_len(fs, dirent, &rec_len))
2308a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o				return BLOCK_ABORT;
23121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			changed++;
2325dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o		}
23321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		if (ret & DIRENT_ABORT) {
23421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			do_abort++;
23521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			break;
23621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		}
237efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'onext:
2388bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o 		if (next_real_entry == offset)
2395dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o			next_real_entry += rec_len;
240efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
2418bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o 		if (ctx->flags & DIRENT_FLAG_INCLUDE_REMOVED) {
2428bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o			size = ((dirent->name_len & 0xFF) + 11) & ~3;
2438bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o
2445dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o			if (rec_len != size)  {
245544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				unsigned int final_offset;
246544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o
2475dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o				final_offset = offset + rec_len;
2488bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o				offset += size;
2498bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o				while (offset < final_offset &&
2505dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o				       !ext2fs_validate_entry(fs, ctx->buf,
2518bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o							      offset,
2528bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o							      final_offset))
2538bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o					offset += 4;
2548bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o				continue;
2558bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o			}
2568bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o		}
2575dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o		offset += rec_len;
25821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
25921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
26021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (changed) {
261e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ctx->errcode = ext2fs_write_dir_block3(fs, *blocknr, ctx->buf,
262e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall						       0);
26321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		if (ctx->errcode)
26421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			return BLOCK_ABORT;
26521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
26621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (do_abort)
26721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		return BLOCK_ABORT;
26821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	return 0;
26921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o}
27021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
271