pass2.c revision a5abfe0382729fba2c5fea6aaae486cb8bc98f00
13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
23839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * pass2.c --- check directory structure
3efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o *
421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o
521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o *
621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * %Begin-Header%
721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * This file may be redistributed under the terms of the GNU Public
821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * License.
921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * %End-Header%
10efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o *
113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Pass 2 of e2fsck iterates through all active directory inodes, and
123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * applies to following tests to each directory entry in the directory
133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * blocks in the inodes:
143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *	- The length of the directory entry (rec_len) should be at
163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 		least 8 bytes, and no more than the remaining space
173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 		left in the directory block.
183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 	- The length of the name in the directory entry (name_len)
19efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o * 		should be less than (rec_len - 8).
203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *	- The inode number in the directory entry should be within
213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 		legal bounds.
223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 	- The inode number should refer to a in-use inode.
233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *	- The first entry should be '.', and its inode should be
243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 		the inode of the directory.
253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 	- The second entry should be '..'.
263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * To minimize disk seek time, the directory blocks are processed in
283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * sorted order of block numbers.
293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Pass 2 also collects the following information:
313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 	- The inode numbers of the subdirectories for each directory.
323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Pass 2 relies on the following information from previous passes:
343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 	- The directory information collected in pass 1.
353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 	- The inode_used_map bitmap
363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 	- The inode_bad_map bitmap
373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 	- The inode_dir_map bitmap
383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Pass 2 frees the following data structures
403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 	- The inode_bad_map bitmap
41aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o * 	- The inode_reg_map bitmap
423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
44b969b1b8a5c13992cadb026114731958644540d8Matthias Andree#define _GNU_SOURCE 1 /* get strnlen() */
45d1154eb460efe588eaed3d439c1caaca149fa362Theodore Ts'o#include "config.h"
4648e6e81362f264aee4f3945c14928efaf71a06c9Theodore Ts'o#include <string.h>
4748e6e81362f264aee4f3945c14928efaf71a06c9Theodore Ts'o
483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "e2fsck.h"
4921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o#include "problem.h"
500926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o#include "dict.h"
513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
52aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o#ifdef NO_INLINE_FUNCS
53aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o#define _INLINE_
54aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o#else
55aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o#define _INLINE_ inline
56aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o#endif
57aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
58ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o/* #define DX_DEBUG */
598fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Keeps track of how many times an inode is referenced.
623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
634035f40bc4550ce7520724cc837992a700794e00Theodore Ts'ostatic void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf);
64a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wongstatic int check_dir_block2(ext2_filsys fs,
65a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong			   struct ext2_db_entry2 *dir_blocks_info,
66a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong			   void *priv_data);
673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int check_dir_block(ext2_filsys fs,
686dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson			   struct ext2_db_entry2 *dir_blocks_info,
6954dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o			   void *priv_data);
701b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic int allocate_dir_block(e2fsck_t ctx,
716dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson			      struct ext2_db_entry2 *dir_blocks_info,
7221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			      char *buf, struct problem_context *pctx);
738fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'ostatic void clear_htree(e2fsck_t ctx, ext2_ino_t ino);
74ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'ostatic int htree_depth(struct dx_dir_info *dx_dir,
75ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		       struct dx_dirblock_info *dx_db);
76ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'ostatic EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b);
773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
7821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'ostruct check_dir_struct {
7921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	char *buf;
8021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	struct problem_context	pctx;
81f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o	int	count, max;
821b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	e2fsck_t ctx;
83a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	unsigned long long list_offset;
84a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	unsigned long long ra_entries;
85a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	unsigned long long next_ra_off;
86efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o};
8721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
8808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'ovoid e2fsck_pass2(e2fsck_t ctx)
893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
90a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	struct ext2_super_block *sb = ctx->fs->super;
91a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	struct problem_context	pctx;
92a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	ext2_filsys 		fs = ctx->fs;
93a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	char			*buf;
948bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#ifdef RESOURCE_TRACK
953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct resource_track	rtrack;
968bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#endif
9721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	struct check_dir_struct cd;
988fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct dx_dir_info	*dx_dir;
998fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct dx_dirblock_info	*dx_db, *dx_parent;
100830b44f4385eb255d08fe0c8b200f8d8e3e97a8dTheodore Ts'o	unsigned int		save_type;
101544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	int			b;
102ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	int			i, depth;
1038fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	problem_t		code;
1048fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	int			bad_dir;
105a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	int (*check_dir_func)(ext2_filsys fs,
106a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong			      struct ext2_db_entry2 *dir_blocks_info,
107a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong			      void *priv_data);
1088fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
1096d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	init_resource_track(&rtrack, ctx->fs->io);
1101b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	clear_problem_context(&cd.pctx);
1111b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
1123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#ifdef MTRACE
1133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	mtrace_print("Pass 2");
1143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif
1153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1161b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (!(ctx->options & E2F_OPT_PREEN))
1171b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx);
1181b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
119efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	e2fsck_setup_tdb_icount(ctx, EXT2_ICOUNT_OPT_INCREMENT,
12034b9f7963933daeb1c3fb3f21a70a1673d098154Theodore Ts'o				&ctx->inode_count);
12134b9f7963933daeb1c3fb3f21a70a1673d098154Theodore Ts'o	if (ctx->inode_count)
12234b9f7963933daeb1c3fb3f21a70a1673d098154Theodore Ts'o		cd.pctx.errcode = 0;
123830b44f4385eb255d08fe0c8b200f8d8e3e97a8dTheodore Ts'o	else {
124830b44f4385eb255d08fe0c8b200f8d8e3e97a8dTheodore Ts'o		e2fsck_set_bitmap_type(fs, EXT2FS_BMAP64_RBTREE,
125830b44f4385eb255d08fe0c8b200f8d8e3e97a8dTheodore Ts'o				       "inode_count", &save_type);
126efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		cd.pctx.errcode = ext2fs_create_icount2(fs,
12734b9f7963933daeb1c3fb3f21a70a1673d098154Theodore Ts'o						EXT2_ICOUNT_OPT_INCREMENT,
1281b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o						0, ctx->inode_link_info,
1291b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o						&ctx->inode_count);
130830b44f4385eb255d08fe0c8b200f8d8e3e97a8dTheodore Ts'o		fs->default_bitmap_type = save_type;
131830b44f4385eb255d08fe0c8b200f8d8e3e97a8dTheodore Ts'o	}
1321b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (cd.pctx.errcode) {
1331b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx);
13408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
13508b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		return;
13621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
137bcf9c5d4016975c3c2afdb4a4b358569bd3c8681Theodore Ts'o	buf = (char *) e2fsck_allocate_memory(ctx, 2*fs->blocksize,
13854dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o					      "directory scan buffer");
1393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
14021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	/*
14121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	 * Set up the parent pointer for the root directory, if
14221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	 * present.  (If the root directory is not present, we will
14321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	 * create it in pass 3.)
14421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	 */
14528db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	(void) e2fsck_dir_info_set_parent(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
14621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
14721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	cd.buf = buf;
1481b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	cd.ctx = ctx;
149f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	cd.count = 1;
1506dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson	cd.max = ext2fs_dblist_count2(fs->dblist);
151a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	cd.list_offset = 0;
152a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	cd.ra_entries = ctx->readahead_kb * 1024 / ctx->fs->blocksize;
153a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	cd.next_ra_off = 0;
154f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
155f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (ctx->progress)
156f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		(void) (ctx->progress)(ctx, 2, 0, cd.max);
157ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o
158ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX)
1596dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson		ext2fs_dblist_sort2(fs->dblist, special_dir_block_cmp);
160efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
161a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	check_dir_func = cd.ra_entries ? check_dir_block2 : check_dir_block;
162a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	cd.pctx.errcode = ext2fs_dblist_iterate2(fs->dblist, check_dir_func,
1636dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson						 &cd);
16449a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos	if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART)
16508b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		return;
1666267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger
1676267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger	if (ctx->flags & E2F_FLAG_RESTART_LATER) {
1686267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger		ctx->flags |= E2F_FLAG_RESTART;
1696267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger		return;
1706267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger	}
1716267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger
1721b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (cd.pctx.errcode) {
1731b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
17408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
17508b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		return;
1767ac02a5ebddcc6187c893eedc80d92777b399575Theodore Ts'o	}
1778fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
1788fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef ENABLE_HTREE
1798fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) {
1804cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o		if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
1814cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o			return;
182d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong		if (e2fsck_dir_will_be_rehashed(ctx, dx_dir->ino) ||
183d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong		    dx_dir->numblocks == 0)
1848fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			continue;
1858fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		clear_problem_context(&pctx);
1868fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		bad_dir = 0;
1878fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		pctx.dir = dx_dir->ino;
1888fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db = dx_dir->dx_block;
1898fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (dx_db->flags & DX_FLAG_REFERENCED)
1908fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->flags |= DX_FLAG_DUP_REF;
1918fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		else
1928fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->flags |= DX_FLAG_REFERENCED;
1938fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		/*
1948fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		 * Find all of the first and last leaf blocks, and
1958fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		 * update their parent's min and max hash values
1968fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		 */
1978fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		for (b=0, dx_db = dx_dir->dx_block;
1988fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		     b < dx_dir->numblocks;
1998fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		     b++, dx_db++) {
2008fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if ((dx_db->type != DX_DIRBLOCK_LEAF) ||
2018fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			    !(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST)))
2028fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				continue;
2038fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_parent = &dx_dir->dx_block[dx_db->parent];
2048fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			/*
2058fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			 * XXX Make sure dx_parent->min_hash > dx_db->min_hash
2068fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			 */
2078fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (dx_db->flags & DX_FLAG_FIRST)
2088fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				dx_parent->min_hash = dx_db->min_hash;
2098fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			/*
2108fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			 * XXX Make sure dx_parent->max_hash < dx_db->max_hash
2118fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			 */
2128fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (dx_db->flags & DX_FLAG_LAST)
2138fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				dx_parent->max_hash = dx_db->max_hash;
2148fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
215efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
2168fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		for (b=0, dx_db = dx_dir->dx_block;
2178fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		     b < dx_dir->numblocks;
2188fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		     b++, dx_db++) {
2198fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			pctx.blkcount = b;
2208fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			pctx.group = dx_db->parent;
2218fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			code = 0;
2228fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (!(dx_db->flags & DX_FLAG_FIRST) &&
2238fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			    (dx_db->min_hash < dx_db->node_min_hash)) {
2248fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				pctx.blk = dx_db->min_hash;
2258fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				pctx.blk2 = dx_db->node_min_hash;
2268fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				code = PR_2_HTREE_MIN_HASH;
2278fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				fix_problem(ctx, code, &pctx);
2288fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				bad_dir++;
2298fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			}
230ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o			if (dx_db->type == DX_DIRBLOCK_LEAF) {
231ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o				depth = htree_depth(dx_dir, dx_db);
232ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o				if (depth != dx_dir->depth) {
233e5e12db959d3c18f6cf4ac938a14f68be0a89accAndreas Dilger					pctx.num = dx_dir->depth;
234ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o					code = PR_2_HTREE_BAD_DEPTH;
235ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o					fix_problem(ctx, code, &pctx);
236ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o					bad_dir++;
237ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o				}
238ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o			}
2398fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			/*
240efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o			 * This test doesn't apply for the root block
2418fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			 * at block #0
2428fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			 */
2438fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (b &&
2448fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			    (dx_db->max_hash > dx_db->node_max_hash)) {
2458fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				pctx.blk = dx_db->max_hash;
2468fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				pctx.blk2 = dx_db->node_max_hash;
2478fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				code = PR_2_HTREE_MAX_HASH;
2488fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				fix_problem(ctx, code, &pctx);
249503f9e7f6eb331c5b75d7f1ad126f71bcdcfb4e3Theodore Ts'o				bad_dir++;
2508fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			}
2518fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (!(dx_db->flags & DX_FLAG_REFERENCED)) {
2528fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				code = PR_2_HTREE_NOTREF;
2538fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				fix_problem(ctx, code, &pctx);
2548fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				bad_dir++;
2558fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			} else if (dx_db->flags & DX_FLAG_DUP_REF) {
2568fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				code = PR_2_HTREE_DUPREF;
2578fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				fix_problem(ctx, code, &pctx);
2588fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				bad_dir++;
2598fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			}
2608fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
2618fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (bad_dir && fix_problem(ctx, PR_2_HTREE_CLEAR, &pctx)) {
2628fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			clear_htree(ctx, dx_dir->ino);
26362acaa1de132a808949d71264731bba7fe095705Theodore Ts'o			dx_dir->numblocks = 0;
2648fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
2658fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	}
26623f75f6efaac6b756e0f3e4e1d33b6798347f66aTheodore Ts'o	e2fsck_free_dx_dir_info(ctx);
2678fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif
268c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&buf);
26921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	ext2fs_free_dblist(fs->dblist);
27021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
2711b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (ctx->inode_bad_map) {
2721b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		ext2fs_free_inode_bitmap(ctx->inode_bad_map);
2731b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		ctx->inode_bad_map = 0;
2743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
275aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	if (ctx->inode_reg_map) {
276aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		ext2fs_free_inode_bitmap(ctx->inode_reg_map);
277aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		ctx->inode_reg_map = 0;
278aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	}
279dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o	if (ctx->encrypted_dirs) {
280dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o		ext2fs_u32_list_free(ctx->encrypted_dirs);
281dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o		ctx->encrypted_dirs = 0;
282dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o	}
283a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o
284a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	clear_problem_context(&pctx);
285a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	if (ctx->large_files) {
286a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		if (!(sb->s_feature_ro_compat &
287a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		      EXT2_FEATURE_RO_COMPAT_LARGE_FILE) &&
288a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		    fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) {
289a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o			sb->s_feature_ro_compat |=
290a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o				EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
2910cfce7f749ea519522929d91e705cf90518594c4Theodore Ts'o			fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
292a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o			ext2fs_mark_super_dirty(fs);
293a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		}
294a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
295a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		    fix_problem(ctx, PR_1_FS_REV_LEVEL, &pctx)) {
296a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o			ext2fs_update_dynamic_rev(fs);
297a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o			ext2fs_mark_super_dirty(fs);
298a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		}
299a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o	}
300efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
3019facd076ae8af6e908e228392cea866ce0faf1bcKen Chen	print_resource_track(ctx, _("Pass 2"), &rtrack, fs->io);
3023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
3033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
304ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o#define MAX_DEPTH 32000
305ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'ostatic int htree_depth(struct dx_dir_info *dx_dir,
306ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		       struct dx_dirblock_info *dx_db)
307ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o{
308ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	int	depth = 0;
309ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o
310ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	while (dx_db->type != DX_DIRBLOCK_ROOT && depth < MAX_DEPTH) {
311ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		dx_db = &dx_dir->dx_block[dx_db->parent];
312ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		depth++;
313ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	}
314ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	return depth;
315ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o}
316ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o
3170926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'ostatic int dict_de_cmp(const void *a, const void *b)
3180926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o{
319520ead378ec5ddef828a8d206434cc3a444b2e9eTheodore Ts'o	const struct ext2_dir_entry *de_a, *de_b;
3200926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	int	a_len, b_len;
3210926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o
322520ead378ec5ddef828a8d206434cc3a444b2e9eTheodore Ts'o	de_a = (const struct ext2_dir_entry *) a;
32370f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara	a_len = ext2fs_dirent_name_len(de_a);
324520ead378ec5ddef828a8d206434cc3a444b2e9eTheodore Ts'o	de_b = (const struct ext2_dir_entry *) b;
32570f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara	b_len = ext2fs_dirent_name_len(de_b);
3260926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o
3270926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	if (a_len != b_len)
3280926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o		return (a_len - b_len);
3290926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o
330baa14bd17fb7f83b8f95e32318a7319a762ce000Theodore Ts'o	return memcmp(de_a->name, de_b->name, a_len);
3310926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o}
332ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o
3333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
334ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o * This is special sort function that makes sure that directory blocks
335ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o * with a dirblock of zero are sorted to the beginning of the list.
336ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o * This guarantees that the root node of the htree directories are
337ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o * processed first, so we know what hash version to use.
338ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o */
339ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'ostatic EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b)
340ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o{
3416dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson	const struct ext2_db_entry2 *db_a =
3426dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson		(const struct ext2_db_entry2 *) a;
3436dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson	const struct ext2_db_entry2 *db_b =
3446dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson		(const struct ext2_db_entry2 *) b;
345ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o
346ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	if (db_a->blockcnt && !db_b->blockcnt)
347ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o		return 1;
348ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o
349ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	if (!db_a->blockcnt && db_b->blockcnt)
350ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o		return -1;
351efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
352ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	if (db_a->blk != db_b->blk)
353ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o		return (int) (db_a->blk - db_b->blk);
354efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
355ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	if (db_a->ino != db_b->ino)
356ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o		return (int) (db_a->ino - db_b->ino);
357ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o
358ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	return (int) (db_a->blockcnt - db_b->blockcnt);
359ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o}
360ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o
361ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o
362ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o/*
3633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Make sure the first entry in the directory is '.', and that the
3643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * directory entry is sane.
3653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
3661b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic int check_dot(e2fsck_t ctx,
3673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		     struct ext2_dir_entry *dirent,
36886c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'o		     ext2_ino_t ino, struct problem_context *pctx)
3693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
3703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_dir_entry *nextdir;
3718a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o	unsigned int	rec_len, new_len;
3723c7c6d73f1a0bd45835966f1179fc3e8236a7d9cTheodore Ts'o	int		status = 0;
3733c7c6d73f1a0bd45835966f1179fc3e8236a7d9cTheodore Ts'o	int		created = 0;
3743c7c6d73f1a0bd45835966f1179fc3e8236a7d9cTheodore Ts'o	problem_t	problem = 0;
375efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
37621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (!dirent->inode)
37721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		problem = PR_2_MISSING_DOT;
37870f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara	else if ((ext2fs_dirent_name_len(dirent) != 1) ||
37921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		 (dirent->name[0] != '.'))
38021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		problem = PR_2_1ST_NOT_DOT;
38121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	else if (dirent->name[1] != '\0')
38221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		problem = PR_2_DOT_NULL_TERM;
3835dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o
3848a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o	(void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
38521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (problem) {
3861b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (fix_problem(ctx, problem, pctx)) {
3875dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o			if (rec_len < 12)
3885dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o				rec_len = dirent->rec_len = 12;
3893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			dirent->inode = ino;
39070f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara			ext2fs_dirent_set_name_len(dirent, 1);
39170f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara			ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
3923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			dirent->name[0] = '.';
39321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			dirent->name[1] = '\0';
3943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			status = 1;
3953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			created = 1;
3963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
3973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (dirent->inode != ino) {
3991b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (fix_problem(ctx, PR_2_BAD_INODE_DOT, pctx)) {
4003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			dirent->inode = ino;
4013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			status = 1;
40221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		}
4033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4045dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o	if (rec_len > 12) {
4055dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o		new_len = rec_len - 12;
4063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (new_len > 12) {
4073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			if (created ||
408f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o			    fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) {
4093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				nextdir = (struct ext2_dir_entry *)
4103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					((char *) dirent + 12);
4113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dirent->rec_len = 12;
4128a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o				(void) ext2fs_set_rec_len(ctx->fs, new_len,
4138a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o							  nextdir);
4143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				nextdir->inode = 0;
41570f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara				ext2fs_dirent_set_name_len(nextdir, 0);
41670f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara				ext2fs_dirent_set_file_type(nextdir,
41770f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara							    EXT2_FT_UNKNOWN);
4183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				status = 1;
4193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			}
4203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
4213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return status;
4233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
4263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Make sure the second entry in the directory is '..', and that the
4273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * directory entry is sane.  We do not check the inode number of '..'
4283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * here; this gets done in pass 3.
4293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
4301b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic int check_dotdot(e2fsck_t ctx,
4313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			struct ext2_dir_entry *dirent,
43228db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			ext2_ino_t ino, struct problem_context *pctx)
4333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4343c7c6d73f1a0bd45835966f1179fc3e8236a7d9cTheodore Ts'o	problem_t	problem = 0;
435cf5301d7f2c3bbed3d26600335102414cbf0c4baAndreas Dilger	unsigned int	rec_len;
436efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
43721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (!dirent->inode)
43821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		problem = PR_2_MISSING_DOT_DOT;
43970f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara	else if ((ext2fs_dirent_name_len(dirent) != 2) ||
44021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		 (dirent->name[0] != '.') ||
44121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		 (dirent->name[1] != '.'))
44221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		problem = PR_2_2ND_NOT_DOT_DOT;
44321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	else if (dirent->name[2] != '\0')
44421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		problem = PR_2_DOT_DOT_NULL_TERM;
44521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
4468a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o	(void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
44721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (problem) {
4481b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (fix_problem(ctx, problem, pctx)) {
4495dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o			if (rec_len < 12)
45021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				dirent->rec_len = 12;
4513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			/*
4523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			 * Note: we don't have the parent inode just
4533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			 * yet, so we will fill it in with the root
4543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			 * inode.  This will get fixed in pass 3.
4553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			 */
4563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			dirent->inode = EXT2_ROOT_INO;
45770f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara			ext2fs_dirent_set_name_len(dirent, 2);
45870f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara			ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
4593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			dirent->name[0] = '.';
4603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			dirent->name[1] = '.';
46121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			dirent->name[2] = '\0';
4623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return 1;
463efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		}
4643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
4653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
46628db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	if (e2fsck_dir_info_set_dotdot(ctx, ino, dirent->inode)) {
46728db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o		fix_problem(ctx, PR_2_NO_DIRINFO, pctx);
46828db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o		return -1;
46928db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	}
4703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
4713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
4743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Check to make sure a directory entry doesn't contain any illegal
4753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * characters.
4763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
4771b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic int check_name(e2fsck_t ctx,
4783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		      struct ext2_dir_entry *dirent,
479dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o		      ext2_ino_t dir_ino,
480544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		      struct problem_context *pctx)
4813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	i;
4833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	fixup = -1;
4843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	ret = 0;
485efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
48670f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara	for ( i = 0; i < ext2fs_dirent_name_len(dirent); i++) {
487dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o		if (dirent->name[i] != '/' && dirent->name[i] != '\0')
488dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o			continue;
489dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o		if (fixup < 0)
490dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o			fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx);
491dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o		if (fixup == 0)
492dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o			return 0;
493dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o		dirent->name[i] = '.';
494dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o		ret = 1;
4953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return ret;
4973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
499aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o/*
500aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o * Check the directory filetype (if present)
501aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o */
502aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'ostatic _INLINE_ int check_filetype(e2fsck_t ctx,
503544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				   struct ext2_dir_entry *dirent,
504544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				   ext2_ino_t dir_ino EXT2FS_ATTR((unused)),
505544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				   struct problem_context *pctx)
506aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o{
50770f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara	int	filetype = ext2fs_dirent_file_type(dirent);
508aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	int	should_be = EXT2_FT_UNKNOWN;
509aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	struct ext2_inode	inode;
510aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
511aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	if (!(ctx->fs->super->s_feature_incompat &
5127847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o	      EXT2_FEATURE_INCOMPAT_FILETYPE)) {
5137847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o		if (filetype == 0 ||
5147847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o		    !fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx))
5157847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o			return 0;
51670f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara		ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
5177847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o		return 1;
5187847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o	}
519aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
520c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson	if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, dirent->inode)) {
521aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		should_be = EXT2_FT_DIR;
522c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson	} else if (ext2fs_test_inode_bitmap2(ctx->inode_reg_map,
523aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o					    dirent->inode)) {
524aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		should_be = EXT2_FT_REG_FILE;
525aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	} else if (ctx->inode_bad_map &&
526c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson		   ext2fs_test_inode_bitmap2(ctx->inode_bad_map,
527aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o					    dirent->inode))
528aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		should_be = 0;
529aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	else {
530aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		e2fsck_read_inode(ctx, dirent->inode, &inode,
531aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o				  "check_filetype");
5326fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o		should_be = ext2_file_type(inode.i_mode);
533aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	}
534aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	if (filetype == should_be)
535aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		return 0;
536aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	pctx->num = should_be;
537aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
538aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	if (fix_problem(ctx, filetype ? PR_2_BAD_FILETYPE : PR_2_SET_FILETYPE,
539aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o			pctx) == 0)
540aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		return 0;
541efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
54270f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara	ext2fs_dirent_set_file_type(dirent, should_be);
543aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o	return 1;
544aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o}
545aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
5468fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef ENABLE_HTREE
5478fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'ostatic void parse_int_node(ext2_filsys fs,
5486dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson			   struct ext2_db_entry2 *db,
5498fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			   struct check_dir_struct *cd,
5508fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			   struct dx_dir_info	*dx_dir,
55107307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong			   char *block_buf, int failed_csum)
5528fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o{
5538fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct 		ext2_dx_root_info  *root;
5548fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct 		ext2_dx_entry *ent;
5558fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct		ext2_dx_countlimit *limit;
5568fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct dx_dirblock_info	*dx_db;
557ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	int		i, expect_limit, count;
5588fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	blk_t		blk;
5598fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	ext2_dirhash_t	min_hash = 0xffffffff;
5608fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	ext2_dirhash_t	max_hash = 0;
561ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	ext2_dirhash_t	hash = 0, prev_hash;
56207307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong	int		csum_size = 0;
5638fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
5648fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	if (db->blockcnt == 0) {
5658fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		root = (struct ext2_dx_root_info *) (block_buf + 24);
566efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
5678fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef DX_DEBUG
5688fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		printf("Root node dump:\n");
5698deb80a5d1078cbe43eaffcdeebf0a1a549d6a54Takashi Sato		printf("\t Reserved zero: %u\n", root->reserved_zero);
5708fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		printf("\t Hash Version: %d\n", root->hash_version);
5718fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		printf("\t Info length: %d\n", root->info_length);
5728fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		printf("\t Indirect levels: %d\n", root->indirect_levels);
5738fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		printf("\t Flags: %d\n", root->unused_flags);
5748fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif
5758fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
5768fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
57707307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong
57807307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong		if (failed_csum &&
57907307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong		    (e2fsck_dir_will_be_rehashed(cd->ctx, cd->pctx.ino) ||
58007307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong		     fix_problem(cd->ctx, PR_2_HTREE_ROOT_CSUM_INVALID,
58107307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong				&cd->pctx)))
58207307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong			goto clear_and_exit;
5838fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	} else {
5848fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		ent = (struct ext2_dx_entry *) (block_buf+8);
58507307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong
58607307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong		if (failed_csum &&
58707307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong		    (e2fsck_dir_will_be_rehashed(cd->ctx, cd->pctx.ino) ||
58807307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong		     fix_problem(cd->ctx, PR_2_HTREE_NODE_CSUM_INVALID,
58907307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong				&cd->pctx)))
59007307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong			goto clear_and_exit;
5918fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	}
59207307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong
5938fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	limit = (struct ext2_dx_countlimit *) ent;
5948fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
5958fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef DX_DEBUG
596efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	printf("Number of entries (count): %d\n",
5978132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o	       ext2fs_le16_to_cpu(limit->count));
598efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	printf("Number of entries (limit): %d\n",
5998132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o	       ext2fs_le16_to_cpu(limit->limit));
6008fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif
6018fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
6028132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o	count = ext2fs_le16_to_cpu(limit->count);
60307307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
60407307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong				       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
60507307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong		csum_size = sizeof(struct ext2_dx_tail);
60607307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong	expect_limit = (fs->blocksize -
60707307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong			(csum_size + ((char *) ent - block_buf))) /
60807307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong		       sizeof(struct ext2_dx_entry);
6098132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o	if (ext2fs_le16_to_cpu(limit->limit) != expect_limit) {
6108132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o		cd->pctx.num = ext2fs_le16_to_cpu(limit->limit);
611ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		if (fix_problem(cd->ctx, PR_2_HTREE_BAD_LIMIT, &cd->pctx))
612ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o			goto clear_and_exit;
613ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	}
6148132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o	if (count > expect_limit) {
6158132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o		cd->pctx.num = count;
616ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		if (fix_problem(cd->ctx, PR_2_HTREE_BAD_COUNT, &cd->pctx))
617ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o			goto clear_and_exit;
618ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		count = expect_limit;
619ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	}
620efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
621ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	for (i=0; i < count; i++) {
622ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		prev_hash = hash;
6238132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o		hash = i ? (ext2fs_le32_to_cpu(ent[i].hash) & ~1) : 0;
6248fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef DX_DEBUG
6258deb80a5d1078cbe43eaffcdeebf0a1a549d6a54Takashi Sato		printf("Entry #%d: Hash 0x%08x, block %u\n", i,
6268132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o		       hash, ext2fs_le32_to_cpu(ent[i].block));
6278fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif
6288132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o		blk = ext2fs_le32_to_cpu(ent[i].block) & 0x0ffffff;
6298fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		/* Check to make sure the block is valid */
630977ac8731bf3bd934421dd8107e77325ec7e6de7Theodore Ts'o		if (blk >= (blk_t) dx_dir->numblocks) {
631b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o			cd->pctx.blk = blk;
6328fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (fix_problem(cd->ctx, PR_2_HTREE_BADBLK,
633ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o					&cd->pctx))
634ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o				goto clear_and_exit;
635977ac8731bf3bd934421dd8107e77325ec7e6de7Theodore Ts'o			continue;
6368fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
637ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		if (hash < prev_hash &&
638ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		    fix_problem(cd->ctx, PR_2_HTREE_HASH_ORDER, &cd->pctx))
639ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o			goto clear_and_exit;
6408fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db = &dx_dir->dx_block[blk];
6418fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (dx_db->flags & DX_FLAG_REFERENCED) {
6428fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->flags |= DX_FLAG_DUP_REF;
6438fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		} else {
6448fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->flags |= DX_FLAG_REFERENCED;
6458fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->parent = db->blockcnt;
6468fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
6478fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (hash < min_hash)
6488fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			min_hash = hash;
6498fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (hash > max_hash)
6508fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			max_hash = hash;
6518fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db->node_min_hash = hash;
6528132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o		if ((i+1) < count)
653efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o			dx_db->node_max_hash =
6548132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o			  ext2fs_le32_to_cpu(ent[i+1].hash) & ~1;
6558fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		else {
6568fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->node_max_hash = 0xfffffffe;
6578fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->flags |= DX_FLAG_LAST;
6588fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
6598fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (i == 0)
6608fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->flags |= DX_FLAG_FIRST;
6618fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	}
6628fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef DX_DEBUG
6638fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	printf("Blockcnt = %d, min hash 0x%08x, max hash 0x%08x\n",
6648fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	       db->blockcnt, min_hash, max_hash);
6658fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif
6668fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	dx_db = &dx_dir->dx_block[db->blockcnt];
6678fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	dx_db->min_hash = min_hash;
6688fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	dx_db->max_hash = max_hash;
669ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	return;
670ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o
671ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'oclear_and_exit:
672ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	clear_htree(cd->ctx, cd->pctx.ino);
673ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	dx_dir->numblocks = 0;
67407307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong	e2fsck_rehash_dir_later(cd->ctx, cd->pctx.ino);
6758fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o}
6768fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif /* ENABLE_HTREE */
677aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
678e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o/*
679e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o * Given a busted directory, try to salvage it somehow.
680efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o *
681e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o */
682ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'ostatic void salvage_directory(ext2_filsys fs,
683e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o			      struct ext2_dir_entry *dirent,
684e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o			      struct ext2_dir_entry *prev,
68582ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong			      unsigned int *offset,
68682ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong			      unsigned int block_len)
687e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o{
688e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	char	*cp = (char *) dirent;
6898a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o	int left;
6908a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o	unsigned int rec_len, prev_rec_len;
6914a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	unsigned int name_len;
692e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o
6934a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	/*
6944a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	 * If the space left for the entry is too small to be an entry,
6954a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	 * we can't access dirent's fields, so plumb in the values needed
6964a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	 * so that the previous entry absorbs this one.
6974a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	 */
6984a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	if (block_len - *offset < EXT2_DIR_ENTRY_HEADER_LEN) {
6994a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong		name_len = 0;
7004a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong		rec_len = block_len - *offset;
7014a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	} else {
7024a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong		name_len = ext2fs_dirent_name_len(dirent);
7034a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong		(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
7044a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	}
70582ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong	left = block_len - *offset - rec_len;
7065dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o
707e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	/*
708e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 * Special case of directory entry of size 8: copy what's left
709e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 * of the directory block up to cover up the invalid hole.
710e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 */
7114a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	if ((left >= 12) && (rec_len == EXT2_DIR_ENTRY_HEADER_LEN)) {
7124a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong		memmove(cp, cp+EXT2_DIR_ENTRY_HEADER_LEN, left);
7134a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong		memset(cp + left, 0, EXT2_DIR_ENTRY_HEADER_LEN);
714ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		return;
715ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	}
716ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	/*
717ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	 * If the directory entry overruns the end of the directory
718ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	 * block, and the name is small enough to fit, then adjust the
719ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	 * record length.
720ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	 */
721ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	if ((left < 0) &&
7224a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	    ((int) rec_len + left > EXT2_DIR_ENTRY_HEADER_LEN) &&
7234a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong	    ((int) name_len + EXT2_DIR_ENTRY_HEADER_LEN <= (int) rec_len + left) &&
724ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	    dirent->inode <= fs->super->s_inodes_count &&
725ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o	    strnlen(dirent->name, name_len) == name_len) {
7268a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		(void) ext2fs_set_rec_len(fs, (int) rec_len + left, dirent);
727ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		return;
728e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	}
729e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	/*
730575307cc63d24766ff789262a5cea7b4faf2fa13Kalpak Shah	 * If the record length of the directory entry is a multiple
731575307cc63d24766ff789262a5cea7b4faf2fa13Kalpak Shah	 * of four, and not too big, such that it is valid, let the
732575307cc63d24766ff789262a5cea7b4faf2fa13Kalpak Shah	 * previous directory entry absorb the invalid one.
733e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 */
7345dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o	if (prev && rec_len && (rec_len % 4) == 0 &&
73582ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong	    (*offset + rec_len <= block_len)) {
7368a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		(void) ext2fs_get_rec_len(fs, prev, &prev_rec_len);
7378a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		prev_rec_len += rec_len;
7388a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		(void) ext2fs_set_rec_len(fs, prev_rec_len, prev);
7395dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o		*offset += rec_len;
740ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		return;
741e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	}
742e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	/*
743e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 * Default salvage method --- kill all of the directory
744e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 * entries for the rest of the block.  We will either try to
745e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 * absorb it into the previous directory entry, or create a
746e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 * new empty directory entry the rest of the directory block.
747e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	 */
748e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	if (prev) {
7498a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		(void) ext2fs_get_rec_len(fs, prev, &prev_rec_len);
75082ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong		prev_rec_len += block_len - *offset;
7518a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		(void) ext2fs_set_rec_len(fs, prev_rec_len, prev);
752ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o		*offset = fs->blocksize;
753e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	} else {
75482ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong		rec_len = block_len - *offset;
7558a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		(void) ext2fs_set_rec_len(fs, rec_len, dirent);
75670f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara		ext2fs_dirent_set_name_len(dirent, 0);
75770f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara		ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
758e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		dirent->inode = 0;
759e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	}
760e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o}
761e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o
762d3eb1502fd07a4c751d20ad5fa4b75bfda039d52Darrick J. Wong#define NEXT_DIRENT(d)	((void *)((char *)(d) + (d)->rec_len))
76317641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wongstatic errcode_t insert_dirent_tail(ext2_filsys fs, void *dirbuf)
76417641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong{
76517641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	struct ext2_dir_entry *d;
76617641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	void *top;
76717641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	struct ext2_dir_entry_tail *t;
76817641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong
76917641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	d = dirbuf;
77017641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	top = EXT2_DIRENT_TAIL(dirbuf, fs->blocksize);
77117641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong
772d3eb1502fd07a4c751d20ad5fa4b75bfda039d52Darrick J. Wong	while (d->rec_len && !(d->rec_len & 0x3) && NEXT_DIRENT(d) <= top)
773d3eb1502fd07a4c751d20ad5fa4b75bfda039d52Darrick J. Wong		d = NEXT_DIRENT(d);
77417641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong
77517641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	if (d != top) {
77617641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong		size_t min_size = EXT2_DIR_REC_LEN(
77717641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong				ext2fs_dirent_name_len(dirbuf));
778d3eb1502fd07a4c751d20ad5fa4b75bfda039d52Darrick J. Wong		if (min_size > top - (void *)d)
77917641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong			return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
780d3eb1502fd07a4c751d20ad5fa4b75bfda039d52Darrick J. Wong		d->rec_len = top - (void *)d;
78117641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	}
78217641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong
78317641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	t = (struct ext2_dir_entry_tail *)top;
78417641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	if (t->det_reserved_zero1 ||
78517641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	    t->det_rec_len != sizeof(struct ext2_dir_entry_tail) ||
78617641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	    t->det_reserved_name_len != EXT2_DIR_NAME_LEN_CSUM)
78717641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong		ext2fs_initialize_dirent_tail(fs, t);
78817641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong
78917641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong	return 0;
79017641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong}
791d3eb1502fd07a4c751d20ad5fa4b75bfda039d52Darrick J. Wong#undef NEXT_DIRENT
79217641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong
79352b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wongstatic errcode_t fix_inline_dir_size(e2fsck_t ctx, ext2_ino_t ino,
79452b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong				     size_t *inline_data_size,
79552b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong				     struct problem_context *pctx,
79652b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong				     char *buf)
79752b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong{
79852b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	ext2_filsys fs = ctx->fs;
79952b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	struct ext2_inode inode;
80052b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	size_t new_size, old_size;
80152b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	errcode_t retval;
80252b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong
80352b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	old_size = *inline_data_size;
8040ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	/*
8050ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	 * If there's not enough bytes to start the "second" dir block
8060ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	 * (in the EA space) then truncate everything to the first block.
8070ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	 */
8080ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	if (old_size > EXT4_MIN_INLINE_DATA_SIZE &&
8090ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	    old_size < EXT4_MIN_INLINE_DATA_SIZE +
8100ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		       EXT2_DIR_REC_LEN(1)) {
8110ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		old_size = EXT4_MIN_INLINE_DATA_SIZE;
8120ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		new_size = old_size;
8130ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	} else
8140ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		/* Increase to the next four-byte boundary for salvaging */
8150ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		new_size = old_size + (4 - (old_size & 3));
81652b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	memset(buf + old_size, 0, new_size - old_size);
81752b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	retval = ext2fs_inline_data_set(fs, ino, 0, buf, new_size);
81852b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	if (retval == EXT2_ET_INLINE_DATA_NO_SPACE) {
8190ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		/* Or we can't, so truncate. */
82052b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		new_size -= 4;
82152b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		retval = ext2fs_inline_data_set(fs, ino, 0, buf, new_size);
82252b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		if (retval) {
82352b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong			if (fix_problem(ctx, PR_2_FIX_INLINE_DIR_FAILED,
82452b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong					pctx)) {
82552b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong				new_size = 0;
82652b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong				goto write_inode;
82752b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong			}
82852b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong			goto err;
82952b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		}
83052b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	} else if (retval) {
83152b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		if (fix_problem(ctx, PR_2_FIX_INLINE_DIR_FAILED,
83252b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong				pctx)) {
83352b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong			new_size = 0;
83452b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong			goto write_inode;
83552b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		}
83652b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		goto err;
83752b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	}
83852b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong
83952b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wongwrite_inode:
84052b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	retval = ext2fs_read_inode(fs, ino, &inode);
84152b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	if (retval)
84252b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		goto err;
84352b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong
84452b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	retval = ext2fs_inode_size_set(fs, &inode, new_size);
84552b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	if (retval)
84652b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		goto err;
84752b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	if (new_size == 0)
84852b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		inode.i_flags &= ~EXT4_INLINE_DATA_FL;
84952b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	retval = ext2fs_write_inode(fs, ino, &inode);
85052b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	if (retval)
85152b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		goto err;
85252b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	*inline_data_size = new_size;
85352b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong
85452b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wongerr:
85552b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	return retval;
85652b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong}
85752b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong
85862ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'oint get_filename_hash(ext2_filsys fs, int encrypted, int version,
85962ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o		      const char *name, int len, ext2_dirhash_t *ret_hash,
86062ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o		      ext2_dirhash_t *ret_minor_hash)
86162ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o{
86262ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o	char	buf[2*EXT2FS_DIGEST_SIZE];
86362ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o	int	buf_len;
86462ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o
86562ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o	if (!encrypted)
86662ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o		return ext2fs_dirhash(version, name, len,
86762ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o				      fs->super->s_hash_seed,
86862ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o				      ret_hash, ret_minor_hash);
86962ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o
87062ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o	if (len <= EXT2FS_DIGEST_SIZE)
87162ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o		buf_len = ext2fs_digest_encode(name, len, buf);
87262ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o	else {
87362ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o		ext2fs_sha256(name, len, buf + EXT2FS_DIGEST_SIZE);
87462ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o		buf[0] = 'I';
87562ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o		buf_len = ext2fs_digest_encode(buf + EXT2FS_DIGEST_SIZE,
87662ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o					       EXT2FS_DIGEST_SIZE, buf + 1);
87762ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o		buf_len++;
87862ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o	}
87962ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o	return ext2fs_dirhash(version, buf, buf_len,
88062ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o			      fs->super->s_hash_seed,
88162ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o			      ret_hash, ret_minor_hash);
88262ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o}
88362ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o
884a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wongstatic int check_dir_block2(ext2_filsys fs,
885a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong			   struct ext2_db_entry2 *db,
886a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong			   void *priv_data)
887a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong{
888a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	int err;
889a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	struct check_dir_struct *cd = priv_data;
890a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong
891a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	if (cd->ra_entries && cd->list_offset >= cd->next_ra_off) {
892a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong		err = e2fsck_readahead_dblist(fs,
893a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong					E2FSCK_RA_DBLIST_IGNORE_BLOCKCNT,
894a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong					fs->dblist,
895a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong					cd->list_offset + cd->ra_entries / 8,
896a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong					cd->ra_entries);
897a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong		if (err)
898a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong			cd->ra_entries = 0;
899a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong		cd->next_ra_off = cd->list_offset + (cd->ra_entries * 7 / 8);
900a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	}
901a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong
902a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	err = check_dir_block(fs, db, priv_data);
903a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	cd->list_offset++;
904a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong	return err;
905a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong}
906a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong
9073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int check_dir_block(ext2_filsys fs,
9086dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson			   struct ext2_db_entry2 *db,
90954dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o			   void *priv_data)
9103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
9118fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o 	struct dx_dir_info	*dx_dir;
9128fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef ENABLE_HTREE
9138fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct dx_dirblock_info	*dx_db = 0;
9148fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif /* ENABLE_HTREE */
9156582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu	struct ext2_dir_entry 	*dirent, *prev, dot, dotdot;
9168fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	ext2_dirhash_t		hash;
917544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned int		offset = 0;
9183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int			dir_modified = 0;
91921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	int			dot_state;
92003fa6f8ae28a87018325c892f731097cc97d9eacTheodore Ts'o	unsigned int		rec_len;
9216dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson	blk64_t			block_nr = db->blk;
92286c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'o	ext2_ino_t 		ino = db->ino;
92328db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	ext2_ino_t 		subdir_parent;
92421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	__u16			links;
92554dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o	struct check_dir_struct	*cd;
9260ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	char			*buf, *ibuf;
9271b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	e2fsck_t		ctx;
9283c7c6d73f1a0bd45835966f1179fc3e8236a7d9cTheodore Ts'o	problem_t		problem;
929ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o	struct ext2_dx_root_info *root;
930e8254bfd3b49cb325a1ff6b21ca86570a1008744Theodore Ts'o	struct ext2_dx_countlimit *limit;
9310926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	static dict_t de_dict;
9320926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	struct problem_context	pctx;
9330926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	int	dups_found = 0;
93428db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o	int	ret;
935e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong	int	dx_csum_size = 0, de_csum_size = 0;
93681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	int	failed_csum = 0;
937e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong	int	is_leaf = 1;
93824997f1cd2b3c3ea7a5a2c7fe37013de36a6d8a3Darrick J. Wong	size_t	inline_data_size = 0;
9396582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu	int	filetype = 0;
94062ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o	int	encrypted = 0;
9410ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	size_t	max_block_size;
9421b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
94354dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o	cd = (struct check_dir_struct *) priv_data;
9440ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	ibuf = buf = cd->buf;
9451b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ctx = cd->ctx;
946f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o
94749a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos	if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART)
9484cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o		return DIRENT_ABORT;
949efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
9504cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o	if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
9514cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o		return DIRENT_ABORT;
952efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
95307307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
954e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong				       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
95507307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong		dx_csum_size = sizeof(struct ext2_dx_tail);
956e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		de_csum_size = sizeof(struct ext2_dir_entry_tail);
957e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong	}
95807307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong
9596582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu	if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
9606582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				      EXT2_FEATURE_INCOMPAT_FILETYPE))
9616582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		filetype = EXT2_FT_DIR << 8;
9626582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu
9633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
964efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	 * Make sure the inode is still in use (could have been
9653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * deleted in the duplicate/bad blocks pass.
9663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
967c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson	if (!(ext2fs_test_inode_bitmap2(ctx->inode_used_map, ino)))
9683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
96950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
97021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	cd->pctx.ino = ino;
97121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	cd->pctx.blk = block_nr;
97221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	cd->pctx.blkcount = db->blockcnt;
97321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	cd->pctx.ino2 = 0;
97421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	cd->pctx.dirent = 0;
97521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	cd->pctx.num = 0;
97621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
9776582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu	if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
9786582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				      EXT4_FEATURE_INCOMPAT_INLINE_DATA)) {
9796582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		errcode_t ec;
9806582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu
9816582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		ec = ext2fs_inline_data_size(fs, ino, &inline_data_size);
9826582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		if (ec && ec != EXT2_ET_NO_INLINE_DATA)
9836582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			return DIRENT_ABORT;
9846582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu	}
9856582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu
9866582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu	if (db->blk == 0 && !inline_data_size) {
9871b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (allocate_dir_block(ctx, db, buf, &cd->pctx))
98850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o			return 0;
98950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		block_nr = db->blk;
99050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	}
991efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
9923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (db->blockcnt)
9933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		dot_state = 2;
9943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	else
9953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		dot_state = 0;
9963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
9970926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	if (ctx->dirs_to_hash &&
9980926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	    ext2fs_u32_list_test(ctx->dirs_to_hash, ino))
9990926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o		dups_found++;
10000926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o
10013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0
1002f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	printf("In process_dir_block block %lu, #%d, inode %lu\n", block_nr,
10033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	       db->blockcnt, ino);
10043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif
1005efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
1006f85a9ae6397ff074193322a12ed721dbf5751e41Eric Sandeen	ehandler_operation(_("reading directory block"));
1007cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong	if (inline_data_size) {
10084a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong		memset(buf, 0, fs->blocksize - inline_data_size);
10096582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		cd->pctx.errcode = ext2fs_inline_data_get(fs, ino, 0, buf, 0);
1010cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong		if (cd->pctx.errcode)
1011cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong			goto inline_read_fail;
1012cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong#ifdef WORDS_BIGENDIAN
10130ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		if (db->blockcnt)
10140ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			goto skip_first_read_swab;
1015cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong		*((__u32 *)buf) = ext2fs_le32_to_cpu(*((__u32 *)buf));
1016cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong		cd->pctx.errcode = ext2fs_dirent_swab_in2(fs,
1017cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong				buf + EXT4_INLINE_DATA_DOTDOT_SIZE,
10180ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong				EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE,
10190ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong				0);
10200ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		if (cd->pctx.errcode)
10210ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			goto inline_read_fail;
10220ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wongskip_first_read_swab:
10230ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		if (inline_data_size <= EXT4_MIN_INLINE_DATA_SIZE ||
10240ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		    !db->blockcnt)
10250ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			goto inline_read_fail;
10260ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		cd->pctx.errcode = ext2fs_dirent_swab_in2(fs,
10270ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong				buf + EXT4_MIN_INLINE_DATA_SIZE,
10280ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong				inline_data_size - EXT4_MIN_INLINE_DATA_SIZE,
1029cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong				0);
1030cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong#endif
1031cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong	} else
10326582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		cd->pctx.errcode = ext2fs_read_dir_block4(fs, block_nr,
10336582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu							  buf, 0, ino);
1034cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wonginline_read_fail:
103552b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	pctx.ino = ino;
103652b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	pctx.num = inline_data_size;
10370ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	if (((inline_data_size & 3) ||
10380ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	     (inline_data_size > EXT4_MIN_INLINE_DATA_SIZE &&
10390ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	      inline_data_size < EXT4_MIN_INLINE_DATA_SIZE +
10400ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong				 EXT2_DIR_REC_LEN(1))) &&
104152b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	    fix_problem(ctx, PR_2_BAD_INLINE_DIR_SIZE, &pctx)) {
104252b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		errcode_t err = fix_inline_dir_size(ctx, ino,
104352b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong						    &inline_data_size, &pctx,
104452b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong						    buf);
104552b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong		if (err)
104652b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong			return DIRENT_ABORT;
104752b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong
104852b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong	}
1049e94bc631648299dca43a6015520b18f6232d50dfTheodore Ts'o	ehandler_operation(0);
1050b9852cd87b42f79d569db68c3fdefe4a8f48ede1Theodore Ts'o	if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
1051b9852cd87b42f79d569db68c3fdefe4a8f48ede1Theodore Ts'o		cd->pctx.errcode = 0; /* We'll handle this ourselves */
105281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	else if (cd->pctx.errcode == EXT2_ET_DIR_CSUM_INVALID) {
105381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		cd->pctx.errcode = 0; /* We'll handle this ourselves */
105481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		failed_csum = 1;
105581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	}
10561b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (cd->pctx.errcode) {
1057e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		char *buf2;
105808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
105908b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o			ctx->flags |= E2F_FLAG_ABORT;
106008b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o			return DIRENT_ABORT;
106108b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		}
1062e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		ext2fs_new_dir_block(fs, db->blockcnt == 0 ? ino : 0,
1063e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong				     EXT2_ROOT_INO, &buf2);
1064e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		memcpy(buf, buf2, fs->blocksize);
1065e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		ext2fs_free_mem(&buf2);
10663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
10678fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef ENABLE_HTREE
10688fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
106962acaa1de132a808949d71264731bba7fe095705Theodore Ts'o	if (dx_dir && dx_dir->numblocks) {
10708fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (db->blockcnt >= dx_dir->numblocks) {
1071ea9085c711e92c3727538a0637bc805141333d83Darrick J. Wong			pctx.dir = ino;
1072efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o			if (fix_problem(ctx, PR_2_UNEXPECTED_HTREE_BLOCK,
1073d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'o					&pctx)) {
1074d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'o				clear_htree(ctx, ino);
1075d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'o				dx_dir->numblocks = 0;
1076d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'o				dx_db = 0;
1077d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'o				goto out_htree;
1078d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'o			}
1079d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'o			fatal_error(ctx, _("Can not continue."));
10808fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
10818fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db = &dx_dir->dx_block[db->blockcnt];
10828fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db->type = DX_DIRBLOCK_LEAF;
10838fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db->phys = block_nr;
10848fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db->min_hash = ~0;
10858fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dx_db->max_hash = 0;
1086efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
10878fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		dirent = (struct ext2_dir_entry *) buf;
10888a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o		(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
1089e8254bfd3b49cb325a1ff6b21ca86570a1008744Theodore Ts'o		limit = (struct ext2_dx_countlimit *) (buf+8);
10908fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (db->blockcnt == 0) {
1091ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o			root = (struct ext2_dx_root_info *) (buf + 24);
10928fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->type = DX_DIRBLOCK_ROOT;
10938fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
1094ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o			if ((root->reserved_zero ||
1095ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o			     root->info_length < 8 ||
1096ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o			     root->indirect_levels > 1) &&
1097ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o			    fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) {
1098ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o				clear_htree(ctx, ino);
1099ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o				dx_dir->numblocks = 0;
1100ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o				dx_db = 0;
1101f77704e416fca7dbe4cc91abba674d2ae3c14f6fTheodore Ts'o			}
1102ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o			dx_dir->hashversion = root->hash_version;
1103f77704e416fca7dbe4cc91abba674d2ae3c14f6fTheodore Ts'o			if ((dx_dir->hashversion <= EXT2_HASH_TEA) &&
1104f77704e416fca7dbe4cc91abba674d2ae3c14f6fTheodore Ts'o			    (fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH))
1105f77704e416fca7dbe4cc91abba674d2ae3c14f6fTheodore Ts'o				dx_dir->hashversion += 3;
1106ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o			dx_dir->depth = root->indirect_levels + 1;
11078fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		} else if ((dirent->inode == 0) &&
11085dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o			   (rec_len == fs->blocksize) &&
110970f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara			   (ext2fs_dirent_name_len(dirent) == 0) &&
1110efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o			   (ext2fs_le16_to_cpu(limit->limit) ==
111107307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong			    ((fs->blocksize - (8 + dx_csum_size)) /
11128132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o			     sizeof(struct ext2_dx_entry))))
11138fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			dx_db->type = DX_DIRBLOCK_NODE;
1114e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		is_leaf = 0;
11158fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	}
1116d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'oout_htree:
11178fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif /* ENABLE_HTREE */
11183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
11197f43a46fad362435f8420f656c6157dc8be8dd4dDarrick J. Wong	/* Leaf node with no space for csum?  Rebuild dirs in pass 3A. */
11207f43a46fad362435f8420f656c6157dc8be8dd4dDarrick J. Wong	if (is_leaf && !inline_data_size && failed_csum &&
11217f43a46fad362435f8420f656c6157dc8be8dd4dDarrick J. Wong	    !ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf)) {
11227f43a46fad362435f8420f656c6157dc8be8dd4dDarrick J. Wong		de_csum_size = 0;
1123d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong		if (e2fsck_dir_will_be_rehashed(ctx, ino)) {
1124d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong			failed_csum = 0;
1125d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong			goto skip_checksum;
1126d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong		}
1127d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong		if (!fix_problem(cd->ctx, PR_2_LEAF_NODE_MISSING_CSUM,
11287f43a46fad362435f8420f656c6157dc8be8dd4dDarrick J. Wong				 &cd->pctx))
1129e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong			goto skip_checksum;
11307f43a46fad362435f8420f656c6157dc8be8dd4dDarrick J. Wong		e2fsck_rehash_dir_later(ctx, ino);
1131d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong		failed_csum = 0;
11327f43a46fad362435f8420f656c6157dc8be8dd4dDarrick J. Wong		goto skip_checksum;
1133e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong	}
1134e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong	/* htree nodes don't use fake dirents to store checksums */
1135e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong	if (!is_leaf)
1136e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		de_csum_size = 0;
1137e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong
1138e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wongskip_checksum:
11390ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	if (inline_data_size) {
11400ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		if (db->blockcnt) {
11410ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			buf += EXT4_MIN_INLINE_DATA_SIZE;
11420ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			max_block_size = inline_data_size - EXT4_MIN_INLINE_DATA_SIZE;
11430ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			/* Zero-length second block, just exit */
11440ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			if (max_block_size == 0)
11450ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong				return 0;
11460ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		} else {
11470ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			max_block_size = EXT4_MIN_INLINE_DATA_SIZE;
11480ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		}
11490ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	} else
11500ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		max_block_size = fs->blocksize - de_csum_size;
11510ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong
115262ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o	if (ctx->encrypted_dirs)
115362ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o		encrypted = ext2fs_u32_list_test(ctx->encrypted_dirs, ino);
115462ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o
11550926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
1156e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o	prev = 0;
11573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	do {
11583971bfe878d6c30f9b5be3a2c0310943982a4775Theodore Ts'o		dgrp_t group;
115949a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos		ext2_ino_t first_unused_inode;
116070f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara		unsigned int name_len;
116149a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos
11621b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		problem = 0;
11636582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		if (!inline_data_size || dot_state > 1) {
11646582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			dirent = (struct ext2_dir_entry *) (buf + offset);
11654a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong			/*
11664a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong			 * If there's not even space for the entry header,
11674a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong			 * force salvaging this dir.
11684a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong			 */
11694a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong			if (max_block_size - offset < EXT2_DIR_ENTRY_HEADER_LEN)
11704a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong				rec_len = EXT2_DIR_REC_LEN(1);
11714a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong			else
11724a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong				(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
11736582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			cd->pctx.dirent = dirent;
11746582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			cd->pctx.num = offset;
11754a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong			if ((offset + rec_len > max_block_size) ||
11766582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			    (rec_len < 12) ||
11776582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			    ((rec_len % 4) != 0) ||
11784a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong			    ((ext2fs_dirent_name_len(dirent) + EXT2_DIR_ENTRY_HEADER_LEN) > rec_len)) {
117982ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong				if (fix_problem(ctx, PR_2_DIR_CORRUPTED,
118082ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong						&cd->pctx)) {
11814348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong#ifdef WORDS_BIGENDIAN
11824348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					/*
11834348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * On big-endian systems, if the dirent
11844348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * swap routine finds a rec_len that it
11854348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * doesn't like, it continues
11864348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * processing the block as if rec_len
11874a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong					 * == EXT2_DIR_ENTRY_HEADER_LEN.  This means that the name
11884348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * field gets byte swapped, which means
11894348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * that salvage will not detect the
11904348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * correct name length (unless the name
11914348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * has a length that's an exact
11924348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * multiple of four bytes), and it'll
11934348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * discard the entry (unnecessarily)
11944348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * and the rest of the dirent block.
11954348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * Therefore, swap the rest of the
11964348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * block back to disk order, run
11974348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * salvage, and re-swap anything after
11984348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 * the salvaged dirent.
11994348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					 */
12004348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					int need_reswab = 0;
12014a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong					if (rec_len < EXT2_DIR_ENTRY_HEADER_LEN || rec_len % 4) {
12024348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong						need_reswab = 1;
12034348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong						ext2fs_dirent_swab_in2(fs,
12044a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong							((char *)dirent) + EXT2_DIR_ENTRY_HEADER_LEN,
12054a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong							max_block_size - offset - EXT2_DIR_ENTRY_HEADER_LEN,
12064348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong							0);
12074348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					}
12084348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong#endif
120982ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong					salvage_directory(fs, dirent, prev,
121082ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong							  &offset,
12113a748dfc1cc28878b5c0ffc1042c3efb3d26360eDarrick J. Wong							  max_block_size);
12124348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong#ifdef WORDS_BIGENDIAN
12134348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					if (need_reswab) {
12144348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong						(void) ext2fs_get_rec_len(fs,
12154348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong							dirent, &rec_len);
12164348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong						ext2fs_dirent_swab_in2(fs,
12174348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong							((char *)dirent) + offset + rec_len,
12184348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong							max_block_size - offset - rec_len,
12194348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong							0);
12204348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong					}
12214348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong#endif
12226582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu					dir_modified++;
12236582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu					continue;
12246582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				} else
12256582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu					goto abort_free_dict;
12266582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			}
12276582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		} else {
12286582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			if (dot_state == 0) {
12296582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				memset(&dot, 0, sizeof(dot));
12306582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent = &dot;
12316582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent->inode = ino;
12326582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent->rec_len = EXT2_DIR_REC_LEN(1);
12336582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent->name_len = 1 | filetype;
12346582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent->name[0] = '.';
12356582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			} else if (dot_state == 1) {
12366582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				memset(&dotdot, 0, sizeof(dotdot));
12376582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent = &dotdot;
12386582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent->inode =
12396582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu					((struct ext2_dir_entry *)buf)->inode;
12406582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent->rec_len = EXT2_DIR_REC_LEN(2);
12416582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent->name_len = 2 | filetype;
12426582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent->name[0] = '.';
12436582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				dirent->name[1] = '.';
12446582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			} else {
12456582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				fatal_error(ctx, _("Can not continue."));
12466582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			}
12476582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			cd->pctx.dirent = dirent;
12486582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			cd->pctx.num = offset;
12493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
125050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
1251e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		if (dot_state == 0) {
12521b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			if (check_dot(ctx, dirent, ino, &cd->pctx))
12533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dir_modified++;
1254e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		} else if (dot_state == 1) {
125528db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			ret = check_dotdot(ctx, dirent, ino, &cd->pctx);
125628db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			if (ret < 0)
12570926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o				goto abort_free_dict;
125828db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			if (ret)
12593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dir_modified++;
12603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		} else if (dirent->inode == ino) {
12611b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			problem = PR_2_LINK_DOT;
12621b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) {
12633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dirent->inode = 0;
12643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dir_modified++;
126521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				goto next;
12663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			}
12673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
1268efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		if (!dirent->inode)
12693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			goto next;
1270efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
12713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		/*
12723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * Make sure the inode listed is a legal one.
1273efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		 */
127470f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara		name_len = ext2fs_dirent_name_len(dirent);
12753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (((dirent->inode != EXT2_ROOT_INO) &&
12767f88b04341d88c5df0360d930832c38040303b61Theodore Ts'o		     (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
12773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		    (dirent->inode > fs->super->s_inodes_count)) {
12781b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			problem = PR_2_BAD_INO;
12791b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		} else if (ctx->inode_bb_map &&
1280c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson			   (ext2fs_test_inode_bitmap2(ctx->inode_bb_map,
12811b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o						     dirent->inode))) {
12821b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			/*
12831b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * If the inode is in a bad block, offer to
12841b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * clear it.
12851b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 */
12861b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			problem = PR_2_BB_INODE;
128770f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara		} else if ((dot_state > 1) && (name_len == 1) &&
12881b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			   (dirent->name[0] == '.')) {
12891b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			/*
12901b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * If there's a '.' entry in anything other
12911b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * than the first directory entry, it's a
12921b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * duplicate entry that should be removed.
12931b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 */
12941b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			problem = PR_2_DUP_DOT;
129570f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara		} else if ((dot_state > 1) && (name_len == 2) &&
1296efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o			   (dirent->name[0] == '.') &&
12971b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			   (dirent->name[1] == '.')) {
12981b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			/*
12991b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * If there's a '..' entry in anything other
13001b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * than the second directory entry, it's a
13011b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * duplicate entry that should be removed.
13021b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 */
13031b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			problem = PR_2_DUP_DOT_DOT;
1304e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		} else if ((dot_state > 1) &&
13051b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			   (dirent->inode == EXT2_ROOT_INO)) {
13061b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			/*
13071b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * Don't allow links to the root directory.
13081b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * We check this specially to make sure we
13091b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * catch this error case even if the root
13101b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 * directory hasn't been created yet.
13111b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			 */
13121b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			problem = PR_2_LINK_ROOT;
131370f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara		} else if ((dot_state > 1) && (name_len == 0)) {
1314c40db6d5717023bdd6bb4935161e7ce9678d6234Theodore Ts'o			/*
1315c40db6d5717023bdd6bb4935161e7ce9678d6234Theodore Ts'o			 * Don't allow zero-length directory names.
1316c40db6d5717023bdd6bb4935161e7ce9678d6234Theodore Ts'o			 */
1317c40db6d5717023bdd6bb4935161e7ce9678d6234Theodore Ts'o			problem = PR_2_NULL_NAME;
131821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		}
131921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
13201b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (problem) {
13211b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			if (fix_problem(ctx, problem, &cd->pctx)) {
132221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				dirent->inode = 0;
132321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				dir_modified++;
132421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				goto next;
13251b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			} else {
13261b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o				ext2fs_unmark_valid(fs);
13271b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o				if (problem == PR_2_BAD_INO)
13281b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o					goto next;
132921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			}
13303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
13313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
13323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		/*
13333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * If the inode was marked as having bad fields in
13343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * pass1, process it and offer to fix/clear it.
13353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * (We wait until now so that we can display the
13363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * pathname to the user.)
13373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 */
13381b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (ctx->inode_bad_map &&
1339c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson		    ext2fs_test_inode_bitmap2(ctx->inode_bad_map,
13403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					     dirent->inode)) {
1341e72a9ba39471364ad2f9397f645ca547090e3485Theodore Ts'o			if (e2fsck_process_bad_inode(ctx, ino,
1342bcf9c5d4016975c3c2afdb4a4b358569bd3c8681Theodore Ts'o						     dirent->inode,
1343bcf9c5d4016975c3c2afdb4a4b358569bd3c8681Theodore Ts'o						     buf + fs->blocksize)) {
13443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dirent->inode = 0;
13453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				dir_modified++;
13463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				goto next;
13473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			}
1348a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o			if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
134908b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o				return DIRENT_ABORT;
13503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
13513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
135249a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos		group = ext2fs_group_of_ino(fs, dirent->inode);
135349a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos		first_unused_inode = group * fs->super->s_inodes_per_group +
135449a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos					1 + fs->super->s_inodes_per_group -
1355d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson					ext2fs_bg_itable_unused(fs, group);
135649a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos		cd->pctx.group = group;
135749a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos
135849a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos		/*
135942e89ce7f8823ad14099b03469c2f4e4f6530d05Theodore Ts'o		 * Check if the inode was missed out because
136042e89ce7f8823ad14099b03469c2f4e4f6530d05Theodore Ts'o		 * _INODE_UNINIT flag was set or bg_itable_unused was
136142e89ce7f8823ad14099b03469c2f4e4f6530d05Theodore Ts'o		 * incorrect.  If so, clear the _INODE_UNINIT flag and
136242e89ce7f8823ad14099b03469c2f4e4f6530d05Theodore Ts'o		 * restart e2fsck.  In the future it would be nice if
136342e89ce7f8823ad14099b03469c2f4e4f6530d05Theodore Ts'o		 * we could call a function in pass1.c that checks the
136442e89ce7f8823ad14099b03469c2f4e4f6530d05Theodore Ts'o		 * newly visible inodes.
136549a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos		 */
1366cd65a24e756b8f6770a5961fd94c67eb00dd7baaTheodore Ts'o		if (ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT)) {
13676267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger			pctx.num = dirent->inode;
136849a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos			if (fix_problem(ctx, PR_2_INOREF_BG_INO_UNINIT,
136949a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos					&cd->pctx)){
1370e633b58ac75f2f544b7d6572e37d4b63da31e59cEric Sandeen				ext2fs_bg_flags_clear(fs, group,
1371732c8cd58ff30ffae0d3276c411a08920717a46cTheodore Ts'o						      EXT2_BG_INODE_UNINIT);
137242e89ce7f8823ad14099b03469c2f4e4f6530d05Theodore Ts'o				ext2fs_mark_super_dirty(fs);
13736267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger				ctx->flags |= E2F_FLAG_RESTART_LATER;
137449a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos			} else {
137549a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos				ext2fs_unmark_valid(fs);
137649a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos				if (problem == PR_2_BAD_INO)
137749a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos					goto next;
137849a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos			}
137949a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos		} else if (dirent->inode >= first_unused_inode) {
13806267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger			pctx.num = dirent->inode;
138149a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos			if (fix_problem(ctx, PR_2_INOREF_IN_UNUSED, &cd->pctx)){
1382d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson				ext2fs_bg_itable_unused_set(fs, group, 0);
138349a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos				ext2fs_mark_super_dirty(fs);
13846267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger				ctx->flags |= E2F_FLAG_RESTART_LATER;
138549a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos			} else {
138649a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos				ext2fs_unmark_valid(fs);
138749a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos				if (problem == PR_2_BAD_INO)
138849a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos					goto next;
138949a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos			}
139049a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos		}
139149a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos
13920433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o		/*
13930433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o		 * Offer to clear unused inodes; if we are going to be
13940433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o		 * restarting the scan due to bg_itable_unused being
13950433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o		 * wrong, then don't clear any inodes to avoid zapping
13960433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o		 * inodes that were skipped during pass1 due to an
13970433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o		 * incorrect bg_itable_unused; we'll get any real
13980433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o		 * problems after we restart.
13990433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o		 */
14000433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o		if (!(ctx->flags & E2F_FLAG_RESTART_LATER) &&
140197d26ce9e3589e9f5fa17014467a9730a884d158Theodore Ts'o		    !(ext2fs_test_inode_bitmap2(ctx->inode_used_map,
140297d26ce9e3589e9f5fa17014467a9730a884d158Theodore Ts'o						dirent->inode)))
140349a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos			problem = PR_2_UNUSED_INODE;
140449a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos
140549a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos		if (problem) {
140649a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos			if (fix_problem(ctx, problem, &cd->pctx)) {
140749a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos				dirent->inode = 0;
140849a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos				dir_modified++;
140949a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos				goto next;
141049a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos			} else {
141149a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos				ext2fs_unmark_valid(fs);
141249a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos				if (problem == PR_2_BAD_INO)
141349a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos					goto next;
141449a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos			}
141549a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos		}
141649a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos
141762ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o		if (!encrypted && check_name(ctx, dirent, ino, &cd->pctx))
14181b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			dir_modified++;
14191b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o
1420aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o		if (check_filetype(ctx, dirent, ino, &cd->pctx))
1421aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o			dir_modified++;
1422aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o
14238fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef ENABLE_HTREE
14248fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if (dx_db) {
142562ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o			get_filename_hash(fs, encrypted, dx_dir->hashversion,
142662ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o					  dirent->name,
142762ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o					  ext2fs_dirent_name_len(dirent),
142862ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o					  &hash, 0);
14298fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (hash < dx_db->min_hash)
14308fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				dx_db->min_hash = hash;
14318fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o			if (hash > dx_db->max_hash)
14328fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o				dx_db->max_hash = hash;
14338fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		}
14348fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif
14358fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
143621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		/*
14373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * If this is a directory, then mark its parent in its
14383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * dir_info structure.  If the parent field is already
14393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * filled in, then this directory has more than one
14403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * hard link.  We assume the first link is correct,
14413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 * and ask the user if he/she wants to clear this one.
14423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 */
1443e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		if ((dot_state > 1) &&
1444c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson		    (ext2fs_test_inode_bitmap2(ctx->inode_dir_map,
14453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					      dirent->inode))) {
144628db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			if (e2fsck_dir_info_get_parent(ctx, dirent->inode,
144728db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o						       &subdir_parent)) {
14481b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o				cd->pctx.ino = dirent->inode;
14491b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o				fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
14500926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o				goto abort_free_dict;
14513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			}
145228db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			if (subdir_parent) {
145328db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o				cd->pctx.ino2 = subdir_parent;
14541b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o				if (fix_problem(ctx, PR_2_LINK_DIR,
145521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o						&cd->pctx)) {
14563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					dirent->inode = 0;
14573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					dir_modified++;
14583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					goto next;
145921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				}
146021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o				cd->pctx.ino2 = 0;
146128db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			} else {
1462efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o				(void) e2fsck_dir_info_set_parent(ctx,
146328db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o						  dirent->inode, ino);
146428db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o			}
14653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
14660926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o
14670926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o		if (dups_found) {
14680926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			;
14690926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o		} else if (dict_lookup(&de_dict, dirent)) {
14700926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			clear_problem_context(&pctx);
14710926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			pctx.ino = ino;
14720926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			pctx.dirent = dirent;
14730926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			fix_problem(ctx, PR_2_REPORT_DUP_DIRENT, &pctx);
1474e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong			e2fsck_rehash_dir_later(ctx, ino);
14750926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			dups_found++;
14760926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o		} else
14770926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o			dict_alloc_insert(&de_dict, dirent, dirent);
1478efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
14791b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		ext2fs_icount_increment(ctx->inode_count, dirent->inode,
14801b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o					&links);
148121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		if (links > 1)
14821b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			ctx->fs_links_count++;
14831b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		ctx->fs_total_count++;
14843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	next:
1485e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		prev = dirent;
14865dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o		if (dir_modified)
14878a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o			(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
14886582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		if (!inline_data_size || dot_state > 1) {
14896582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			offset += rec_len;
14906582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		} else {
14916698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong			if (dot_state == 1) {
14926582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				offset = 4;
14936698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong				/*
14946698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong				 * If we get here, we're checking an inline
14956698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong				 * directory and we've just checked a (fake)
14966698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong				 * dotdot entry that we created on the stack.
14976698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong				 * Therefore set 'prev' to NULL so that if we
14986698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong				 * call salvage_directory on the next entry,
14996698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong				 * it won't try to absorb the next entry into
15006698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong				 * the on-stack dotdot entry.
15016698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong				 */
15026698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong				prev = NULL;
15036698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong			}
15046582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		}
1505e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o		dot_state++;
15060ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	} while (offset < max_block_size);
15073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0
15083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	printf("\n");
15093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif
15108fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef ENABLE_HTREE
15118fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	if (dx_db) {
15128fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef DX_DEBUG
15138fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		printf("db_block %d, type %d, min_hash 0x%0x, max_hash 0x%0x\n",
15148fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		       db->blockcnt, dx_db->type,
15158fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		       dx_db->min_hash, dx_db->max_hash);
15168fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif
1517b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o		cd->pctx.dir = cd->pctx.ino;
15188fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
15198fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o		    (dx_db->type == DX_DIRBLOCK_NODE))
152081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong			parse_int_node(fs, db, cd, dx_dir, buf, failed_csum);
15218fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	}
15228fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif /* ENABLE_HTREE */
1523e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong
15240ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong	if (offset != max_block_size) {
15250ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		cd->pctx.num = rec_len + offset - max_block_size;
15260ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong		if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
15270ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			dirent->rec_len = cd->pctx.num;
15280ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			dir_modified++;
15291b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		}
15303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
15313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (dir_modified) {
15322e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong		int	flags, will_rehash;
1533e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		/* leaf block with no tail?  Rehash dirs later. */
1534e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
1535e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong				EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
1536e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		    is_leaf &&
153717641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong		    !inline_data_size &&
153817641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong		    !ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf)) {
153917641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong			if (insert_dirent_tail(fs, buf) == 0)
154017641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong				goto write_and_fix;
1541e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong			e2fsck_rehash_dir_later(ctx, ino);
154217641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong		}
1543e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong
1544e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wongwrite_and_fix:
15452e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong		will_rehash = e2fsck_dir_will_be_rehashed(ctx, ino);
15462e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong		if (will_rehash) {
15472e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong			flags = ctx->fs->flags;
1548e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong			ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
15492e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong		}
15506582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		if (inline_data_size) {
15510ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			buf = ibuf;
1552cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong#ifdef WORDS_BIGENDIAN
15530ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			if (db->blockcnt)
15540ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong				goto skip_first_write_swab;
1555cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong			*((__u32 *)buf) = ext2fs_le32_to_cpu(*((__u32 *)buf));
1556cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong			cd->pctx.errcode = ext2fs_dirent_swab_out2(fs,
1557cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong					buf + EXT4_INLINE_DATA_DOTDOT_SIZE,
15580ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong					EXT4_MIN_INLINE_DATA_SIZE -
1559cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong					EXT4_INLINE_DATA_DOTDOT_SIZE,
1560cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong					0);
15610ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			if (cd->pctx.errcode)
15620ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong				goto skip_second_write_swab;
15630ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wongskip_first_write_swab:
15640ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			if (inline_data_size <= EXT4_MIN_INLINE_DATA_SIZE ||
15650ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			    !db->blockcnt)
15660ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong				goto skip_second_write_swab;
15670ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong			cd->pctx.errcode = ext2fs_dirent_swab_out2(fs,
15680ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong					buf + EXT4_MIN_INLINE_DATA_SIZE,
15690ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong					inline_data_size -
15700ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong					EXT4_MIN_INLINE_DATA_SIZE,
15710ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong					0);
15720ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wongskip_second_write_swab:
1573cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong			if (cd->pctx.errcode &&
1574cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong			    !fix_problem(ctx, PR_2_WRITE_DIRBLOCK, &cd->pctx))
1575cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong				goto abort_free_dict;
1576cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong#endif
15776582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			cd->pctx.errcode =
15786582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu				ext2fs_inline_data_set(fs, ino, 0, buf,
15796582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu						       inline_data_size);
15806582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu		} else
15816582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu			cd->pctx.errcode = ext2fs_write_dir_block4(fs, block_nr,
15826582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu								   buf, 0, ino);
15832e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong		if (will_rehash)
15842e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong			ctx->fs->flags = (flags &
15852e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong					  EXT2_FLAG_IGNORE_CSUM_ERRORS) |
15862e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong					 (ctx->fs->flags &
15872e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong					  ~EXT2_FLAG_IGNORE_CSUM_ERRORS);
15881b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (cd->pctx.errcode) {
158908b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o			if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
15900926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o					 &cd->pctx))
15910926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o				goto abort_free_dict;
15923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
15933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		ext2fs_mark_changed(fs);
1594e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong	} else if (is_leaf && failed_csum && !dir_modified) {
1595e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		/*
1596e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		 * If a leaf node that fails csum makes it this far without
1597e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		 * alteration, ask the user if the checksum should be fixed.
1598e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		 */
1599e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong		if (fix_problem(ctx, PR_2_LEAF_NODE_ONLY_CSUM_INVALID,
1600e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong				&cd->pctx))
1601e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong			goto write_and_fix;
16023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
16030926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	dict_free_nodes(&de_dict);
16043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
16050926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'oabort_free_dict:
16060926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	ctx->flags |= E2F_FLAG_ABORT;
160749a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos	dict_free_nodes(&de_dict);
16080926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o	return DIRENT_ABORT;
16093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
16103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1611624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kalistruct del_block {
1612624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali	e2fsck_t	ctx;
1613624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali	e2_blkcnt_t	num;
1614624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali};
1615624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali
16163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
16173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This function is called to deallocate a block, and is an interator
16183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * functioned called by deallocate inode via ext2fs_iterate_block().
16193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
16203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int deallocate_inode_block(ext2_filsys fs,
16216dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson				  blk64_t	*block_nr,
1622544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				  e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
16236dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson				  blk64_t ref_block EXT2FS_ATTR((unused)),
1624544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				  int ref_offset EXT2FS_ATTR((unused)),
1625133a56dc9da52054bc27b4c1a23f03e3405003dbTheodore Ts'o				  void *priv_data)
16263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
1627624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali	struct del_block *p = priv_data;
1628efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
16294a05268cf86f7138c78d80a53f7e162f32128a3dTheodore Ts'o	if (*block_nr == 0)
16303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
16311ba7a2f2b6a9b152828a06443955a7fb1d139930Theodore Ts'o	if ((*block_nr < fs->super->s_first_data_block) ||
16324efbac6fed75c29d3d5f1b676b932754653a2ac5Valerie Aurora Henson	    (*block_nr >= ext2fs_blocks_count(fs->super)))
16331ba7a2f2b6a9b152828a06443955a7fb1d139930Theodore Ts'o		return 0;
16348dd650ab9ac394c6d6d19b02e8bb22d5a1e5da0dDarrick J. Wong	if ((*block_nr % EXT2FS_CLUSTER_RATIO(fs)) == 0)
16358dd650ab9ac394c6d6d19b02e8bb22d5a1e5da0dDarrick J. Wong		ext2fs_block_alloc_stats2(fs, *block_nr, -1);
1636624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali	p->num++;
16373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
16383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
1639efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
16403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
16413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This fuction deallocates an inode
16423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
16434035f40bc4550ce7520724cc837992a700794e00Theodore Ts'ostatic void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
16443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
16451b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
16463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode	inode;
16471b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	struct problem_context	pctx;
16480684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o	__u32			count;
1649624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali	struct del_block	del_block;
1650efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
165108b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
16521b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	clear_problem_context(&pctx);
16531b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	pctx.ino = ino;
1654f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
16553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
16563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Fix up the bitmaps...
16573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
1658f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o	e2fsck_read_bitmaps(ctx);
16590684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o	ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
16600684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o
16610c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o	if (ext2fs_file_acl_block(fs, &inode) &&
16620684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o	    (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
166339f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong		pctx.errcode = ext2fs_adjust_ea_refcount3(fs,
166439f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong				ext2fs_file_acl_block(fs, &inode),
166539f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong				block_buf, -1, &count, ino);
16660684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
16670684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o			pctx.errcode = 0;
16680684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o			count = 1;
16690684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		}
16700684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		if (pctx.errcode) {
16710c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o			pctx.blk = ext2fs_file_acl_block(fs, &inode);
16720684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o			fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx);
16730684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o			ctx->flags |= E2F_FLAG_ABORT;
16740684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o			return;
16750684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		}
16760684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		if (count == 0) {
167748f23054bb8ad0506c0baa9f06ba182acc2aa88bValerie Aurora Henson			ext2fs_block_alloc_stats2(fs,
16780c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o				  ext2fs_file_acl_block(fs, &inode), -1);
16790684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		}
16800c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o		ext2fs_file_acl_block_set(fs, &inode, 0);
16810684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o	}
16823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
16830c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o	if (!ext2fs_inode_has_valid_blocks2(fs, &inode))
1684c8ec2bad18fdaa842f786f3b37c9320a3411aea3Theodore Ts'o		goto clear_inode;
1685a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o
16862ece839011f3074c2249dcfbf99945c93cc1927dDarrick J. Wong	/* Inline data inodes don't have blocks to iterate */
16872ece839011f3074c2249dcfbf99945c93cc1927dDarrick J. Wong	if (inode.i_flags & EXT4_INLINE_DATA_FL)
16882ece839011f3074c2249dcfbf99945c93cc1927dDarrick J. Wong		goto clear_inode;
16892ece839011f3074c2249dcfbf99945c93cc1927dDarrick J. Wong
16903b6c0938ec5aa401c7ae6c95e94e5ad30a7b8562Darrick J. Wong	if (LINUX_S_ISREG(inode.i_mode) &&
16913b6c0938ec5aa401c7ae6c95e94e5ad30a7b8562Darrick J. Wong	    ext2fs_needs_large_file_feature(EXT2_I_SIZE(&inode)))
1692a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o		ctx->large_files--;
1693a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o
1694624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali	del_block.ctx = ctx;
1695624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali	del_block.num = 0;
16966dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson	pctx.errcode = ext2fs_block_iterate3(fs, ino, 0, block_buf,
1697624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali					     deallocate_inode_block,
1698624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali					     &del_block);
16991b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx.errcode) {
17001b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx);
170108b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		ctx->flags |= E2F_FLAG_ABORT;
170208b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		return;
17031b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	}
1704c8ec2bad18fdaa842f786f3b37c9320a3411aea3Theodore Ts'oclear_inode:
1705c8ec2bad18fdaa842f786f3b37c9320a3411aea3Theodore Ts'o	/* Inode may have changed by block_iterate, so reread it */
1706c8ec2bad18fdaa842f786f3b37c9320a3411aea3Theodore Ts'o	e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
1707c8ec2bad18fdaa842f786f3b37c9320a3411aea3Theodore Ts'o	e2fsck_clear_inode(ctx, ino, &inode, 0, "deallocate_inode");
17083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
17093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
17108fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o/*
17118fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o * This fuction clears the htree flag on an inode
17128fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o */
17138fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'ostatic void clear_htree(e2fsck_t ctx, ext2_ino_t ino)
17148fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o{
17158fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	struct ext2_inode	inode;
1716efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
17178fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	e2fsck_read_inode(ctx, ino, &inode, "clear_htree");
17188fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL;
17198fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o	e2fsck_write_inode(ctx, ino, &inode, "clear_htree");
1720b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o	if (ctx->dirs_to_hash)
1721b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o		ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
17228fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o}
17238fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
17248fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o
1725f404167dda29a59d2be2882328aeb074b9899669Theodore Ts'oint e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
1726f404167dda29a59d2be2882328aeb074b9899669Theodore Ts'o			     ext2_ino_t ino, char *buf)
17273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
17281b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
17293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode	inode;
17303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int			inode_modified = 0;
17316c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o	int			not_fixed = 0;
17321e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	unsigned char		*frag, *fsize;
173321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	struct problem_context	pctx;
17343c7c6d73f1a0bd45835966f1179fc3e8236a7d9cTheodore Ts'o	problem_t		problem = 0;
17353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
173608b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode");
173721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
173821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	clear_problem_context(&pctx);
173921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	pctx.ino = ino;
174021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	pctx.dir = dir;
174121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	pctx.inode = &inode;
174221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
17430c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o	if (ext2fs_file_acl_block(fs, &inode) &&
1744f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o	    !(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
1745f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o		if (fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) {
17460c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o			ext2fs_file_acl_block_set(fs, &inode, 0);
1747f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o			inode_modified++;
1748f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o		} else
1749f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o			not_fixed++;
1750f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o	}
17516c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o
175250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) &&
175350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	    !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) &&
175450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	    !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) &&
175508b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	    !(LINUX_S_ISSOCK(inode.i_mode)))
175608b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		problem = PR_2_BAD_MODE;
1757fdbdea09b87dbd8e39c23286f22653e7641599aeTheodore Ts'o	else if (LINUX_S_ISCHR(inode.i_mode)
17580684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		 && !e2fsck_pass1_check_device_inode(fs, &inode))
175908b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		problem = PR_2_BAD_CHAR_DEV;
1760fdbdea09b87dbd8e39c23286f22653e7641599aeTheodore Ts'o	else if (LINUX_S_ISBLK(inode.i_mode)
17610684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		 && !e2fsck_pass1_check_device_inode(fs, &inode))
176208b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		problem = PR_2_BAD_BLOCK_DEV;
1763fdbdea09b87dbd8e39c23286f22653e7641599aeTheodore Ts'o	else if (LINUX_S_ISFIFO(inode.i_mode)
17640684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		 && !e2fsck_pass1_check_device_inode(fs, &inode))
17651dde43f0c1176f61dd0bf91aff265ce8cd1c5fd6Theodore Ts'o		problem = PR_2_BAD_FIFO;
1766fdbdea09b87dbd8e39c23286f22653e7641599aeTheodore Ts'o	else if (LINUX_S_ISSOCK(inode.i_mode)
17670684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o		 && !e2fsck_pass1_check_device_inode(fs, &inode))
17681dde43f0c1176f61dd0bf91aff265ce8cd1c5fd6Theodore Ts'o		problem = PR_2_BAD_SOCKET;
1769fdbdea09b87dbd8e39c23286f22653e7641599aeTheodore Ts'o	else if (LINUX_S_ISLNK(inode.i_mode)
17707cadc57780f3e3e8e644e8976e11a336902d4a25Theodore Ts'o		 && !e2fsck_pass1_check_symlink(fs, ino, &inode, buf)) {
1771bcf9c5d4016975c3c2afdb4a4b358569bd3c8681Theodore Ts'o		problem = PR_2_INVALID_SYMLINK;
177267052a8aeeca8cd80d1dd33c2792f917573accc8Andreas Dilger	}
17731dde43f0c1176f61dd0bf91aff265ce8cd1c5fd6Theodore Ts'o
177408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	if (problem) {
177508b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		if (fix_problem(ctx, problem, &pctx)) {
17761b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o			deallocate_inode(ctx, ino, 0);
1777a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o			if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
177808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o				return 0;
17797cf73dcd3d173d88ceab26d381f4abac362d8518Theodore Ts'o			return 1;
17806c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		} else
17816c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			not_fixed++;
178208b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		problem = 0;
17837cf73dcd3d173d88ceab26d381f4abac362d8518Theodore Ts'o	}
1784efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
17856c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o	if (inode.i_faddr) {
17866c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		if (fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) {
17876c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			inode.i_faddr = 0;
17886c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			inode_modified++;
17896c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		} else
17906c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			not_fixed++;
17913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
17921e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o
17931e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	switch (fs->super->s_creator_os) {
17941e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	    case EXT2_OS_HURD:
17951e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o		frag = &inode.osd2.hurd2.h_i_frag;
17961e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o		fsize = &inode.osd2.hurd2.h_i_fsize;
17971e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o		break;
17981e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	    default:
17991e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o		frag = fsize = 0;
18001e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o	}
180121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (frag && *frag) {
180221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		pctx.num = *frag;
18031b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) {
180421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			*frag = 0;
180521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			inode_modified++;
18067e0282c5f21add344b306876ca999aecd4d5fd0cTheodore Ts'o		} else
18077e0282c5f21add344b306876ca999aecd4d5fd0cTheodore Ts'o			not_fixed++;
180821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		pctx.num = 0;
180921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
181021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (fsize && *fsize) {
181121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		pctx.num = *fsize;
18121b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) {
181321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			*fsize = 0;
181421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			inode_modified++;
18156c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		} else
18166c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			not_fixed++;
181721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		pctx.num = 0;
181821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
181921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o
18205d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o	if ((fs->super->s_creator_os == EXT2_OS_LINUX) &&
1821efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	    !(fs->super->s_feature_ro_compat &
18225d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o	      EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
18235d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o	    (inode.osd2.linux2.l_i_blocks_hi != 0)) {
18245d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o		pctx.num = inode.osd2.linux2.l_i_blocks_hi;
18255d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o		if (fix_problem(ctx, PR_2_BLOCKS_HI_ZERO, &pctx)) {
18265d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o			inode.osd2.linux2.l_i_blocks_hi = 0;
18275d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o			inode_modified++;
18285d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o		}
18295d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o	}
18305d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o
183136769c606c270094df0431cbcab9932905adcedcJustus Winter	if ((fs->super->s_creator_os == EXT2_OS_LINUX) &&
183236769c606c270094df0431cbcab9932905adcedcJustus Winter	    !(fs->super->s_feature_incompat &
1833911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o	     EXT4_FEATURE_INCOMPAT_64BIT) &&
1834911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o	    inode.osd2.linux2.l_i_file_acl_high != 0) {
1835911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o		pctx.num = inode.osd2.linux2.l_i_file_acl_high;
1836911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o		if (fix_problem(ctx, PR_2_I_FILE_ACL_HI_ZERO, &pctx)) {
1837911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o			inode.osd2.linux2.l_i_file_acl_high = 0;
1838911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o			inode_modified++;
1839911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o		} else
1840911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o			not_fixed++;
1841911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o	}
1842911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o
18430c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o	if (ext2fs_file_acl_block(fs, &inode) &&
18440c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o	    ((ext2fs_file_acl_block(fs, &inode) < fs->super->s_first_data_block) ||
18450c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o	     (ext2fs_file_acl_block(fs, &inode) >= ext2fs_blocks_count(fs->super)))) {
18466c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		if (fix_problem(ctx, PR_2_FILE_ACL_BAD, &pctx)) {
18470c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o			ext2fs_file_acl_block_set(fs, &inode, 0);
18486c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			inode_modified++;
18496c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		} else
18506c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			not_fixed++;
1851342d847db355d81299218e07a1e58ece82080a04Theodore Ts'o	}
185221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (inode.i_dir_acl &&
18536c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o	    LINUX_S_ISDIR(inode.i_mode)) {
18546c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) {
18556c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			inode.i_dir_acl = 0;
18566c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			inode_modified++;
18576c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o		} else
18586c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o			not_fixed++;
185921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
18606c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o
1861f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	if (inode_modified)
186208b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o		e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode");
1863f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o	if (!not_fixed && ctx->inode_bad_map)
1864c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson		ext2fs_unmark_inode_bitmap2(ctx->inode_bad_map, ino);
18653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
18663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
18673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
186850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o/*
186950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * allocate_dir_block --- this function allocates a new directory
187050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * 	block for a particular inode; this is done if a directory has
187150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * 	a "hole" in it, or if a directory has a illegal block number
187250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * 	that was zeroed out and now needs to be replaced.
187350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o */
18741b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic int allocate_dir_block(e2fsck_t ctx,
18756dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson			      struct ext2_db_entry2 *db,
1876efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o			      char *buf EXT2FS_ATTR((unused)),
1877544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			      struct problem_context *pctx)
187850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o{
18791b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	ext2_filsys fs = ctx->fs;
1880ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong	blk64_t			blk = 0;
188150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	char			*block;
188250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	struct ext2_inode	inode;
188350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
18841b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0)
188550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return 1;
188650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
188750e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	/*
188850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 * Read the inode and block bitmaps in; we'll be messing with
188950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 * them.
189050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 */
1891f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o	e2fsck_read_bitmaps(ctx);
1892efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
189350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	/*
189450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 * First, find a free block
189550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 */
1896ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong	e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block");
1897ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong	pctx->errcode = ext2fs_map_cluster_block(fs, db->ino, &inode,
1898ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong						 db->blockcnt, &blk);
1899ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong	if (pctx->errcode || blk == 0) {
19007b486ec08cda3bc67b7f6bdcbcc9cb5783322e6cDarrick J. Wong		blk = ext2fs_find_inode_goal(fs, db->ino, &inode, db->blockcnt);
19017b486ec08cda3bc67b7f6bdcbcc9cb5783322e6cDarrick J. Wong		pctx->errcode = ext2fs_new_block2(fs, blk,
1902ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong						  ctx->block_found_map, &blk);
1903ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong		if (pctx->errcode) {
1904ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong			pctx->str = "ext2fs_new_block";
1905ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong			fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
1906ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong			return 1;
1907ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong		}
190850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	}
1909c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson	ext2fs_mark_block_bitmap2(ctx->block_found_map, blk);
1910c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson	ext2fs_mark_block_bitmap2(fs->block_map, blk);
191150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	ext2fs_mark_bb_dirty(fs);
191250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
191350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	/*
191450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 * Now let's create the actual data block for the inode
191550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 */
191650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	if (db->blockcnt)
19171b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block);
191850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	else
19191b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx->errcode = ext2fs_new_dir_block(fs, db->ino,
19201b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o						     EXT2_ROOT_INO, &block);
192150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
19221b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx->errcode) {
19231b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx->str = "ext2fs_new_dir_block";
19241b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
192550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return 1;
192650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	}
192750e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
192881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	pctx->errcode = ext2fs_write_dir_block4(fs, blk, block, 0, db->ino);
1929c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&block);
19301b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx->errcode) {
19311b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx->str = "ext2fs_write_dir_block";
19321b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
193350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return 1;
193450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	}
193550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
193650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	/*
193750e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 * Update the inode block count
193850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 */
19391ca1059fd0126fd2c065f272a566c18f14bab16dTheodore Ts'o	ext2fs_iblk_add_blocks(fs, &inode, 1);
194097c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong	if (EXT2_I_SIZE(&inode) < (db->blockcnt+1) * fs->blocksize) {
194197c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong		pctx->errcode = ext2fs_inode_size_set(fs, &inode,
194297c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong					(db->blockcnt+1) * fs->blocksize);
194397c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong		if (pctx->errcode) {
194497c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong			pctx->str = "ext2fs_inode_size_set";
194597c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong			fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
194697c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong			return 1;
194797c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong		}
194897c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong	}
194908b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o	e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block");
195050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
195150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	/*
195250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 * Finally, update the block pointers for the inode
195350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	 */
195450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	db->blk = blk;
19552d07b3ad98bfe1db5fb1071f53a5338ab6c35522Theodore Ts'o	pctx->errcode = ext2fs_bmap2(fs, db->ino, &inode, 0, BMAP_SET,
19562d07b3ad98bfe1db5fb1071f53a5338ab6c35522Theodore Ts'o				     db->blockcnt, 0, &blk);
19571b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o	if (pctx->errcode) {
19581b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		pctx->str = "ext2fs_block_iterate";
19591b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o		fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
196050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return 1;
196150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	}
196250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o
196350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	return 0;
196450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o}
1965